@vyuhlabs/dxkit 2.6.0 → 2.7.1

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 (221) hide show
  1. package/CHANGELOG.md +103 -13
  2. package/README.md +208 -459
  3. package/dist/analyzers/bom/discovery.d.ts +3 -4
  4. package/dist/analyzers/bom/discovery.d.ts.map +1 -1
  5. package/dist/analyzers/bom/discovery.js +3 -4
  6. package/dist/analyzers/bom/discovery.js.map +1 -1
  7. package/dist/analyzers/bom/types.d.ts +1 -1
  8. package/dist/analyzers/dashboard/index.d.ts.map +1 -1
  9. package/dist/analyzers/dashboard/index.js +42 -5
  10. package/dist/analyzers/dashboard/index.js.map +1 -1
  11. package/dist/analyzers/developer/gather.d.ts.map +1 -1
  12. package/dist/analyzers/developer/gather.js +9 -9
  13. package/dist/analyzers/developer/gather.js.map +1 -1
  14. package/dist/analyzers/quality/detailed.d.ts +8 -1
  15. package/dist/analyzers/quality/detailed.d.ts.map +1 -1
  16. package/dist/analyzers/quality/detailed.js +43 -10
  17. package/dist/analyzers/quality/detailed.js.map +1 -1
  18. package/dist/analyzers/quality/gather.js +3 -3
  19. package/dist/analyzers/quality/gather.js.map +1 -1
  20. package/dist/analyzers/security/detailed.d.ts +8 -1
  21. package/dist/analyzers/security/detailed.d.ts.map +1 -1
  22. package/dist/analyzers/security/detailed.js +14 -1
  23. package/dist/analyzers/security/detailed.js.map +1 -1
  24. package/dist/analyzers/security/gather.d.ts.map +1 -1
  25. package/dist/analyzers/security/gather.js +12 -3
  26. package/dist/analyzers/security/gather.js.map +1 -1
  27. package/dist/analyzers/tests/detailed.d.ts +8 -1
  28. package/dist/analyzers/tests/detailed.d.ts.map +1 -1
  29. package/dist/analyzers/tests/detailed.js +26 -7
  30. package/dist/analyzers/tests/detailed.js.map +1 -1
  31. package/dist/analyzers/tools/cloc.js +5 -5
  32. package/dist/analyzers/tools/cloc.js.map +1 -1
  33. package/dist/analyzers/tools/exclusions.d.ts +12 -12
  34. package/dist/analyzers/tools/exclusions.d.ts.map +1 -1
  35. package/dist/analyzers/tools/exclusions.js +27 -13
  36. package/dist/analyzers/tools/exclusions.js.map +1 -1
  37. package/dist/analyzers/tools/generic.d.ts.map +1 -1
  38. package/dist/analyzers/tools/generic.js +52 -14
  39. package/dist/analyzers/tools/generic.js.map +1 -1
  40. package/dist/analyzers/tools/gitleaks.d.ts.map +1 -1
  41. package/dist/analyzers/tools/gitleaks.js +28 -3
  42. package/dist/analyzers/tools/gitleaks.js.map +1 -1
  43. package/dist/analyzers/tools/graphify.d.ts +39 -5
  44. package/dist/analyzers/tools/graphify.d.ts.map +1 -1
  45. package/dist/analyzers/tools/graphify.js +609 -45
  46. package/dist/analyzers/tools/graphify.js.map +1 -1
  47. package/dist/analyzers/tools/grep-secrets.d.ts.map +1 -1
  48. package/dist/analyzers/tools/grep-secrets.js +1 -1
  49. package/dist/analyzers/tools/grep-secrets.js.map +1 -1
  50. package/dist/analyzers/tools/jscpd.d.ts.map +1 -1
  51. package/dist/analyzers/tools/jscpd.js +2 -1
  52. package/dist/analyzers/tools/jscpd.js.map +1 -1
  53. package/dist/analyzers/tools/nuget-package-reference.d.ts +4 -4
  54. package/dist/analyzers/tools/nuget-package-reference.js +4 -4
  55. package/dist/analyzers/tools/osv-scanner-deps.d.ts.map +1 -1
  56. package/dist/analyzers/tools/osv-scanner-deps.js +1 -1
  57. package/dist/analyzers/tools/osv-scanner-deps.js.map +1 -1
  58. package/dist/analyzers/tools/osv-scanner-fix.d.ts +4 -5
  59. package/dist/analyzers/tools/osv-scanner-fix.d.ts.map +1 -1
  60. package/dist/analyzers/tools/osv-scanner-fix.js +4 -5
  61. package/dist/analyzers/tools/osv-scanner-fix.js.map +1 -1
  62. package/dist/analyzers/tools/parallel.d.ts.map +1 -1
  63. package/dist/analyzers/tools/parallel.js +7 -0
  64. package/dist/analyzers/tools/parallel.js.map +1 -1
  65. package/dist/analyzers/tools/runner.d.ts +35 -2
  66. package/dist/analyzers/tools/runner.d.ts.map +1 -1
  67. package/dist/analyzers/tools/runner.js +112 -3
  68. package/dist/analyzers/tools/runner.js.map +1 -1
  69. package/dist/analyzers/tools/semgrep.d.ts.map +1 -1
  70. package/dist/analyzers/tools/semgrep.js +3 -1
  71. package/dist/analyzers/tools/semgrep.js.map +1 -1
  72. package/dist/analyzers/tools/tool-registry.d.ts +18 -0
  73. package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
  74. package/dist/analyzers/tools/tool-registry.js +140 -53
  75. package/dist/analyzers/tools/tool-registry.js.map +1 -1
  76. package/dist/analyzers/tools/tools-config.d.ts +46 -0
  77. package/dist/analyzers/tools/tools-config.d.ts.map +1 -0
  78. package/dist/analyzers/tools/tools-config.js +129 -0
  79. package/dist/analyzers/tools/tools-config.js.map +1 -0
  80. package/dist/analyzers/tools/vendored-advisor.d.ts.map +1 -1
  81. package/dist/analyzers/tools/vendored-advisor.js +3 -4
  82. package/dist/analyzers/tools/vendored-advisor.js.map +1 -1
  83. package/dist/analyzers/tools/walk-source-files.d.ts +8 -0
  84. package/dist/analyzers/tools/walk-source-files.d.ts.map +1 -1
  85. package/dist/analyzers/tools/walk-source-files.js +49 -4
  86. package/dist/analyzers/tools/walk-source-files.js.map +1 -1
  87. package/dist/analyzers/xlsx/licenses.d.ts +7 -7
  88. package/dist/analyzers/xlsx/licenses.js +7 -7
  89. package/dist/baseline/baseline-file.d.ts +8 -0
  90. package/dist/baseline/baseline-file.d.ts.map +1 -1
  91. package/dist/baseline/baseline-file.js.map +1 -1
  92. package/dist/baseline/check-renderers.d.ts.map +1 -1
  93. package/dist/baseline/check-renderers.js +10 -0
  94. package/dist/baseline/check-renderers.js.map +1 -1
  95. package/dist/baseline/check.d.ts +7 -0
  96. package/dist/baseline/check.d.ts.map +1 -1
  97. package/dist/baseline/check.js +2 -0
  98. package/dist/baseline/check.js.map +1 -1
  99. package/dist/baseline/coverage.d.ts +57 -0
  100. package/dist/baseline/coverage.d.ts.map +1 -0
  101. package/dist/baseline/coverage.js +62 -0
  102. package/dist/baseline/coverage.js.map +1 -0
  103. package/dist/baseline/create.d.ts +13 -0
  104. package/dist/baseline/create.d.ts.map +1 -1
  105. package/dist/baseline/create.js +21 -0
  106. package/dist/baseline/create.js.map +1 -1
  107. package/dist/cli.d.ts.map +1 -1
  108. package/dist/cli.js +123 -4
  109. package/dist/cli.js.map +1 -1
  110. package/dist/dashboard/graph-adapter.d.ts +151 -0
  111. package/dist/dashboard/graph-adapter.d.ts.map +1 -0
  112. package/dist/dashboard/graph-adapter.js +415 -0
  113. package/dist/dashboard/graph-adapter.js.map +1 -0
  114. package/dist/dashboard/graph-tab.d.ts +109 -0
  115. package/dist/dashboard/graph-tab.d.ts.map +1 -0
  116. package/dist/dashboard/graph-tab.js +297 -0
  117. package/dist/dashboard/graph-tab.js.map +1 -0
  118. package/dist/dashboard/vendor/vis-network.min.js +34 -0
  119. package/dist/doctor.d.ts.map +1 -1
  120. package/dist/doctor.js +6 -7
  121. package/dist/doctor.js.map +1 -1
  122. package/dist/explore/cli/api-surface.d.ts +12 -0
  123. package/dist/explore/cli/api-surface.d.ts.map +1 -0
  124. package/dist/explore/cli/api-surface.js +57 -0
  125. package/dist/explore/cli/api-surface.js.map +1 -0
  126. package/dist/explore/cli/communities.d.ts +10 -0
  127. package/dist/explore/cli/communities.d.ts.map +1 -0
  128. package/dist/explore/cli/communities.js +47 -0
  129. package/dist/explore/cli/communities.js.map +1 -0
  130. package/dist/explore/cli/context.d.ts +16 -0
  131. package/dist/explore/cli/context.d.ts.map +1 -0
  132. package/dist/explore/cli/context.js +118 -0
  133. package/dist/explore/cli/context.js.map +1 -0
  134. package/dist/explore/cli/entry-points.d.ts +12 -0
  135. package/dist/explore/cli/entry-points.d.ts.map +1 -0
  136. package/dist/explore/cli/entry-points.js +85 -0
  137. package/dist/explore/cli/entry-points.js.map +1 -0
  138. package/dist/explore/cli/feature.d.ts +16 -0
  139. package/dist/explore/cli/feature.d.ts.map +1 -0
  140. package/dist/explore/cli/feature.js +89 -0
  141. package/dist/explore/cli/feature.js.map +1 -0
  142. package/dist/explore/cli/file.d.ts +12 -0
  143. package/dist/explore/cli/file.d.ts.map +1 -0
  144. package/dist/explore/cli/file.js +139 -0
  145. package/dist/explore/cli/file.js.map +1 -0
  146. package/dist/explore/cli/hot-files.d.ts +11 -0
  147. package/dist/explore/cli/hot-files.d.ts.map +1 -0
  148. package/dist/explore/cli/hot-files.js +63 -0
  149. package/dist/explore/cli/hot-files.js.map +1 -0
  150. package/dist/explore/context-hook.d.ts +42 -0
  151. package/dist/explore/context-hook.d.ts.map +1 -0
  152. package/dist/explore/context-hook.js +131 -0
  153. package/dist/explore/context-hook.js.map +1 -0
  154. package/dist/explore/finding-context.d.ts +69 -0
  155. package/dist/explore/finding-context.d.ts.map +1 -0
  156. package/dist/explore/finding-context.js +102 -0
  157. package/dist/explore/finding-context.js.map +1 -0
  158. package/dist/explore/format.d.ts +64 -0
  159. package/dist/explore/format.d.ts.map +1 -0
  160. package/dist/explore/format.js +99 -0
  161. package/dist/explore/format.js.map +1 -0
  162. package/dist/explore/load.d.ts +50 -0
  163. package/dist/explore/load.d.ts.map +1 -0
  164. package/dist/explore/load.js +197 -0
  165. package/dist/explore/load.js.map +1 -0
  166. package/dist/explore/queries.d.ts +413 -0
  167. package/dist/explore/queries.d.ts.map +1 -0
  168. package/dist/explore/queries.js +855 -0
  169. package/dist/explore/queries.js.map +1 -0
  170. package/dist/explore/types.d.ts +130 -0
  171. package/dist/explore/types.d.ts.map +1 -0
  172. package/dist/explore/types.js +28 -0
  173. package/dist/explore/types.js.map +1 -0
  174. package/dist/explore-cli.d.ts +45 -0
  175. package/dist/explore-cli.d.ts.map +1 -0
  176. package/dist/explore-cli.js +213 -0
  177. package/dist/explore-cli.js.map +1 -0
  178. package/dist/generator.d.ts.map +1 -1
  179. package/dist/generator.js +19 -0
  180. package/dist/generator.js.map +1 -1
  181. package/dist/languages/csharp.d.ts.map +1 -1
  182. package/dist/languages/csharp.js +58 -26
  183. package/dist/languages/csharp.js.map +1 -1
  184. package/dist/languages/go.d.ts.map +1 -1
  185. package/dist/languages/go.js +17 -14
  186. package/dist/languages/go.js.map +1 -1
  187. package/dist/languages/index.d.ts +27 -0
  188. package/dist/languages/index.d.ts.map +1 -1
  189. package/dist/languages/index.js +35 -0
  190. package/dist/languages/index.js.map +1 -1
  191. package/dist/languages/java.d.ts.map +1 -1
  192. package/dist/languages/java.js +13 -10
  193. package/dist/languages/java.js.map +1 -1
  194. package/dist/languages/kotlin.d.ts.map +1 -1
  195. package/dist/languages/kotlin.js +13 -10
  196. package/dist/languages/kotlin.js.map +1 -1
  197. package/dist/languages/python.d.ts.map +1 -1
  198. package/dist/languages/python.js +31 -20
  199. package/dist/languages/python.js.map +1 -1
  200. package/dist/languages/ruby.d.ts.map +1 -1
  201. package/dist/languages/ruby.js +30 -16
  202. package/dist/languages/ruby.js.map +1 -1
  203. package/dist/languages/rust.d.ts.map +1 -1
  204. package/dist/languages/rust.js +16 -13
  205. package/dist/languages/rust.js.map +1 -1
  206. package/dist/languages/types.d.ts +54 -0
  207. package/dist/languages/types.d.ts.map +1 -1
  208. package/dist/languages/typescript.d.ts.map +1 -1
  209. package/dist/languages/typescript.js +22 -19
  210. package/dist/languages/typescript.js.map +1 -1
  211. package/dist/tools-cli.d.ts.map +1 -1
  212. package/dist/tools-cli.js +10 -4
  213. package/dist/tools-cli.js.map +1 -1
  214. package/dist/upgrade.js +2 -2
  215. package/dist/upgrade.js.map +1 -1
  216. package/package.json +2 -1
  217. package/templates/.claude/skills/dxkit-action/SKILL.md +21 -1
  218. package/templates/.claude/skills/dxkit-config/SKILL.md +26 -0
  219. package/templates/.claude/skills/dxkit-fix/SKILL.md +10 -0
  220. package/templates/.claude/skills/dxkit-reports/SKILL.md +3 -1
  221. package/templates/AGENTS.md.template +8 -1
@@ -0,0 +1,415 @@
1
+ "use strict";
2
+ /**
3
+ * Pure-function adapter — converts the in-memory `Graph` into the
4
+ * shape cytoscape.js consumes (`ElementsDefinition` equivalent).
5
+ *
6
+ * Three tiers, matching the dashboard's three-level drill-down:
7
+ *
8
+ * Tier 1 — community view (default tab landing)
9
+ * N community bubbles + inter-community edges, sized by
10
+ * member-count (sqrt scale) and labeled by dominantSourceDir.
11
+ *
12
+ * Tier 2 — file view (within one community)
13
+ * File nodes for every file in the community, sized by call
14
+ * in-degree, edges = imports_from between member files plus
15
+ * the strongest cross-community import edges.
16
+ *
17
+ * Tier 3 — symbol view (within one file)
18
+ * Symbol nodes for every function / class / method in the file,
19
+ * sized by call in-degree, edges = calls within the file plus
20
+ * thin external-call indicators that the renderer can wire as
21
+ * "click → jump to the target file."
22
+ *
23
+ * Pure: no DOM access, no cytoscape import, no I/O. Tested with
24
+ * synthetic `Graph` fixtures (see test/dashboard/graph-adapter.test.ts).
25
+ * The DOM-bound mounter (Part B's `graph-tab.ts`) consumes these
26
+ * elements and hands them to cytoscape.
27
+ *
28
+ * Per CLAUDE.md Rule 12: every graph traversal here goes through
29
+ * `src/explore/queries.ts` — no callers / callees / community lookup
30
+ * code is reimplemented in this module. The arch gate enforces.
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.adaptToTier1 = adaptToTier1;
34
+ exports.adaptToTier2 = adaptToTier2;
35
+ exports.adaptToTier3 = adaptToTier3;
36
+ const queries_1 = require("../explore/queries");
37
+ // ─── Tier 1 — community bubbles ──────────────────────────────────────────────
38
+ /**
39
+ * Build the cytoscape elements for the community-view (Tier 1) of a
40
+ * graph. Each community becomes one node; inter-community edges are
41
+ * synthesized by counting cross-community `calls` + `imports_from`
42
+ * edges.
43
+ *
44
+ * Limit defaults to the top-20 communities by node-count — beyond
45
+ * that the layout gets dense without adding information. The CLI's
46
+ * `explore communities` default is 8; the viz needs more breadth to
47
+ * communicate "this repo has lots of natural modules" so we lift
48
+ * the cap.
49
+ */
50
+ function adaptToTier1(graph, opts = {}) {
51
+ const limit = opts.limit ?? 20;
52
+ // Use the canonical query for the per-community summary (Rule 12).
53
+ // Rank-by-node-count is identical to communitiesQuery's behavior;
54
+ // we just want the top-N rendered.
55
+ const summaries = (0, queries_1.communitiesQuery)(graph, limit);
56
+ const communityIds = new Set(summaries.map((s) => s.id));
57
+ // Largest community → size 1.0; sqrt scale ensures a 4× node-count
58
+ // community renders ~2× the radius (visual area still proportional).
59
+ const maxNodeCount = summaries.reduce((m, s) => Math.max(m, s.nodeCount), 0);
60
+ const nodes = summaries.map((s) => ({
61
+ group: 'nodes',
62
+ data: {
63
+ id: communityId(s.id),
64
+ label: s.dominantSourceDir || `community-${s.id}`,
65
+ size: maxNodeCount > 0 ? Math.sqrt(s.nodeCount / maxNodeCount) : 0,
66
+ colorGroup: s.dominantPack || 'multi',
67
+ tier: 1,
68
+ communityId: s.id,
69
+ meta: {
70
+ nodeCount: s.nodeCount,
71
+ cohesion: round2(s.cohesion),
72
+ dominantPack: s.dominantPack || 'mixed',
73
+ topHotFiles: s.topHotFiles.slice(0, 3).join(', '),
74
+ },
75
+ },
76
+ }));
77
+ // Inter-community edges — count cross-community calls + imports.
78
+ // Bidirectional pairs collapse to one undirected edge for visual
79
+ // clarity (cytoscape can still treat the underlying edge as
80
+ // directed if a layout cares).
81
+ const pairCounts = new Map();
82
+ for (const edge of graph.edges) {
83
+ if (edge.relation === 'method')
84
+ continue; // method ownership is intra-file noise
85
+ const fromComm = graph.communityByNode.get(edge.from);
86
+ const toComm = graph.communityByNode.get(edge.to);
87
+ if (!fromComm || !toComm)
88
+ continue;
89
+ if (fromComm.id === toComm.id)
90
+ continue; // intra-community
91
+ if (!communityIds.has(fromComm.id) || !communityIds.has(toComm.id))
92
+ continue;
93
+ const [a, b] = fromComm.id < toComm.id ? [fromComm.id, toComm.id] : [toComm.id, fromComm.id];
94
+ const key = `${a}->${b}`;
95
+ const existing = pairCounts.get(key);
96
+ if (existing) {
97
+ existing.count++;
98
+ }
99
+ else {
100
+ pairCounts.set(key, { from: a, to: b, count: 1 });
101
+ }
102
+ }
103
+ const maxPairCount = Math.max(0, ...[...pairCounts.values()].map((p) => p.count));
104
+ const edges = [...pairCounts.entries()].map(([key, p]) => ({
105
+ group: 'edges',
106
+ data: {
107
+ id: `e1:${key}`,
108
+ source: communityId(p.from),
109
+ target: communityId(p.to),
110
+ relation: 'community',
111
+ weight: maxPairCount > 0 ? Math.sqrt(p.count / maxPairCount) : 0,
112
+ occurrences: p.count,
113
+ },
114
+ }));
115
+ return { nodes, edges };
116
+ }
117
+ // ─── Tier 2 — files within a community ───────────────────────────────────────
118
+ /**
119
+ * Build the cytoscape elements for the file-view (Tier 2) of one
120
+ * community. File nodes are the union of `sourceFile` across all
121
+ * nodes whose community is the target.
122
+ *
123
+ * Edges are intra-community `imports_from` + `calls` aggregated to
124
+ * the file level (a 12-call cluster from src/foo.ts → src/bar.ts
125
+ * becomes one edge with `occurrences: 12`).
126
+ *
127
+ * Empty result when the community id is unknown — the renderer
128
+ * surfaces a "community not found" error in that case.
129
+ */
130
+ function adaptToTier2(graph, communityId) {
131
+ const community = graph.communityById.get(communityId);
132
+ if (!community) {
133
+ return { nodes: [], edges: [] };
134
+ }
135
+ // Files in the community: union of nodes[].sourceFile.
136
+ const filesInCommunity = new Set();
137
+ for (const nodeId of community.nodeIds) {
138
+ const node = graph.nodeById.get(nodeId);
139
+ if (node?.sourceFile)
140
+ filesInCommunity.add(node.sourceFile);
141
+ }
142
+ // Per-file call in-degree, computed via callersOf for Rule 12 compliance.
143
+ const callsInByFile = new Map();
144
+ for (const nodeId of community.nodeIds) {
145
+ const node = graph.nodeById.get(nodeId);
146
+ if (!node?.sourceFile)
147
+ continue;
148
+ const callers = (0, queries_1.callersOf)(graph, nodeId);
149
+ callsInByFile.set(node.sourceFile, (callsInByFile.get(node.sourceFile) ?? 0) + callers.length);
150
+ }
151
+ // Per-file pack id (derived from the most common extension in the file's nodes).
152
+ const packByFile = new Map();
153
+ for (const sourceFile of filesInCommunity) {
154
+ packByFile.set(sourceFile, packFromExt(sourceFile));
155
+ }
156
+ // Per-file line-of-code aggregation surfaces on hover.
157
+ const symbolCountByFile = new Map();
158
+ for (const sourceFile of filesInCommunity) {
159
+ symbolCountByFile.set(sourceFile, (0, queries_1.nodesInFile)(graph, sourceFile).length);
160
+ }
161
+ const maxCallsIn = Math.max(0, ...callsInByFile.values());
162
+ const fileToNodeId = (sourceFile) => `f2:${sourceFile}`;
163
+ const nodes = [...filesInCommunity].sort().map((sourceFile) => {
164
+ const callsIn = callsInByFile.get(sourceFile) ?? 0;
165
+ return {
166
+ group: 'nodes',
167
+ data: {
168
+ id: fileToNodeId(sourceFile),
169
+ label: basename(sourceFile),
170
+ size: maxCallsIn > 0 ? Math.sqrt(callsIn / maxCallsIn) : 0,
171
+ colorGroup: packByFile.get(sourceFile) || 'multi',
172
+ tier: 2,
173
+ communityId: community.id,
174
+ sourceFile,
175
+ meta: {
176
+ callsIn,
177
+ symbolCount: symbolCountByFile.get(sourceFile) ?? 0,
178
+ path: sourceFile,
179
+ },
180
+ },
181
+ };
182
+ });
183
+ // Aggregate edges to the file level. Walk every node in the
184
+ // community + every outbound edge; bucket by (sourceFile,
185
+ // targetFile, relation).
186
+ const edgeKey = (from, to, rel) => `${from}\x00${to}\x00${rel}`;
187
+ const edgeBuckets = new Map();
188
+ for (const nodeId of community.nodeIds) {
189
+ const fromNode = graph.nodeById.get(nodeId);
190
+ if (!fromNode?.sourceFile)
191
+ continue;
192
+ const fromFile = fromNode.sourceFile;
193
+ for (const e of graph.edgesFromNode.get(nodeId) ?? []) {
194
+ if (e.relation === 'method')
195
+ continue;
196
+ const toNode = graph.nodeById.get(e.to);
197
+ if (!toNode?.sourceFile)
198
+ continue;
199
+ const toFile = toNode.sourceFile;
200
+ if (fromFile === toFile)
201
+ continue;
202
+ if (!filesInCommunity.has(toFile))
203
+ continue; // intra-community only at Tier 2
204
+ const k = edgeKey(fromFile, toFile, e.relation);
205
+ const existing = edgeBuckets.get(k);
206
+ if (existing) {
207
+ existing.occurrences += e.occurrences ?? 1;
208
+ }
209
+ else {
210
+ edgeBuckets.set(k, {
211
+ from: fromFile,
212
+ to: toFile,
213
+ relation: e.relation,
214
+ occurrences: e.occurrences ?? 1,
215
+ });
216
+ }
217
+ }
218
+ }
219
+ const maxOcc = Math.max(0, ...[...edgeBuckets.values()].map((b) => b.occurrences));
220
+ const edges = [...edgeBuckets.values()].map((b, i) => ({
221
+ group: 'edges',
222
+ data: {
223
+ id: `e2:${i}`,
224
+ source: fileToNodeId(b.from),
225
+ target: fileToNodeId(b.to),
226
+ relation: b.relation,
227
+ weight: maxOcc > 0 ? Math.sqrt(b.occurrences / maxOcc) : 0,
228
+ occurrences: b.occurrences,
229
+ },
230
+ }));
231
+ return { nodes, edges };
232
+ }
233
+ // ─── Tier 3 — symbols within a file ──────────────────────────────────────────
234
+ /**
235
+ * Build the cytoscape elements for the symbol-view (Tier 3) of one
236
+ * file. Symbol nodes are the function / class / method declarations
237
+ * (module nodes are excluded — they're file-as-a-whole markers, not
238
+ * navigable symbols).
239
+ *
240
+ * Edges are `calls` edges between symbols within the file. Calls
241
+ * that LEAVE the file become "external" indicators carrying the
242
+ * target file path — the renderer styles them as dim arrows and
243
+ * makes them clickable for navigation.
244
+ *
245
+ * Empty result when no symbols are declared in the file (the file
246
+ * isn't in the graph) — the renderer surfaces a "no symbols
247
+ * extracted" message.
248
+ */
249
+ function adaptToTier3(graph, sourceFile) {
250
+ const fileNodes = (0, queries_1.nodesInFile)(graph, sourceFile);
251
+ if (fileNodes.length === 0) {
252
+ return { nodes: [], edges: [] };
253
+ }
254
+ const symbolNodes = fileNodes.filter((n) => n.kind !== 'module');
255
+ const symbolIds = new Set(symbolNodes.map((n) => n.id));
256
+ // Per-symbol call in-degree drives size.
257
+ const callsInBySymbol = new Map();
258
+ for (const n of symbolNodes) {
259
+ callsInBySymbol.set(n.id, (0, queries_1.callersOf)(graph, n.id).length);
260
+ }
261
+ const maxCallsIn = Math.max(0, ...callsInBySymbol.values());
262
+ const nodes = symbolNodes.map((n) => ({
263
+ group: 'nodes',
264
+ data: {
265
+ id: `s3:${n.id}`,
266
+ label: stripParens(n.label),
267
+ size: maxCallsIn > 0 ? Math.sqrt((callsInBySymbol.get(n.id) ?? 0) / maxCallsIn) : 0,
268
+ colorGroup: n.kind, // 'function' | 'class' | 'method'
269
+ tier: 3,
270
+ sourceFile,
271
+ line: n.line,
272
+ meta: {
273
+ kind: n.kind,
274
+ callsIn: callsInBySymbol.get(n.id) ?? 0,
275
+ callsOut: (0, queries_1.calleesOf)(graph, n.id).length,
276
+ exported: n.exported === undefined ? 'unknown' : n.exported,
277
+ },
278
+ },
279
+ }));
280
+ const intraEdges = [];
281
+ const externalBuckets = new Map();
282
+ for (const n of symbolNodes) {
283
+ for (const e of graph.edgesFromNode.get(n.id) ?? []) {
284
+ if (e.relation !== 'calls')
285
+ continue;
286
+ if (symbolIds.has(e.to)) {
287
+ // Intra-file call — render as a real edge between two Tier 3 nodes.
288
+ intraEdges.push({
289
+ group: 'edges',
290
+ data: {
291
+ id: `i3:${e.from}->${e.to}`,
292
+ source: `s3:${e.from}`,
293
+ target: `s3:${e.to}`,
294
+ relation: 'calls',
295
+ weight: 0, // weight assigned below once max is known
296
+ occurrences: e.occurrences ?? 1,
297
+ },
298
+ });
299
+ }
300
+ else {
301
+ // Out-of-file call — bucket by (source symbol, target file).
302
+ const target = graph.nodeById.get(e.to);
303
+ const targetFile = target?.sourceFile;
304
+ if (!targetFile || targetFile === sourceFile)
305
+ continue;
306
+ const key = `${n.id}\x00${targetFile}`;
307
+ const existing = externalBuckets.get(key);
308
+ if (existing) {
309
+ existing.occurrences += e.occurrences ?? 1;
310
+ }
311
+ else {
312
+ externalBuckets.set(key, {
313
+ sourceSymbol: n.id,
314
+ targetFile,
315
+ occurrences: e.occurrences ?? 1,
316
+ });
317
+ }
318
+ }
319
+ }
320
+ }
321
+ // Weight scaling — share the same denominator across intra + external
322
+ // for visual consistency.
323
+ const allOcc = [
324
+ ...intraEdges.map((e) => e.data.occurrences ?? 1),
325
+ ...[...externalBuckets.values()].map((b) => b.occurrences),
326
+ ];
327
+ const maxOcc = Math.max(0, ...allOcc);
328
+ for (const edge of intraEdges) {
329
+ edge.data.weight = maxOcc > 0 ? Math.sqrt((edge.data.occurrences ?? 1) / maxOcc) : 0;
330
+ }
331
+ const externalEdges = [...externalBuckets.values()].map((b, i) => ({
332
+ group: 'edges',
333
+ data: {
334
+ id: `x3:${i}`,
335
+ source: `s3:${b.sourceSymbol}`,
336
+ target: `ext3:${b.targetFile}`,
337
+ relation: 'calls',
338
+ weight: maxOcc > 0 ? Math.sqrt(b.occurrences / maxOcc) : 0,
339
+ occurrences: b.occurrences,
340
+ externalTargetFile: b.targetFile,
341
+ },
342
+ }));
343
+ // Virtual "external file" nodes — one per distinct target file —
344
+ // sized small + neutral-colored. Renderer wires them as clickable
345
+ // "leaves this file" affordances.
346
+ const externalFiles = new Set([...externalBuckets.values()].map((b) => b.targetFile));
347
+ const externalNodes = [...externalFiles].sort().map((f) => ({
348
+ group: 'nodes',
349
+ data: {
350
+ id: `ext3:${f}`,
351
+ label: basename(f),
352
+ size: 0.1,
353
+ colorGroup: 'external',
354
+ tier: 3,
355
+ sourceFile: f,
356
+ meta: {
357
+ external: true,
358
+ path: f,
359
+ },
360
+ },
361
+ }));
362
+ return {
363
+ nodes: [...nodes, ...externalNodes],
364
+ edges: [...intraEdges, ...externalEdges],
365
+ };
366
+ }
367
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
368
+ function communityId(id) {
369
+ return `c1:${id}`;
370
+ }
371
+ function basename(p) {
372
+ if (!p)
373
+ return '';
374
+ const i = Math.max(p.lastIndexOf('/'), p.lastIndexOf('\\'));
375
+ return i >= 0 ? p.slice(i + 1) : p;
376
+ }
377
+ function stripParens(label) {
378
+ if (!label)
379
+ return '';
380
+ let s = label.replace(/\(\)$/, '');
381
+ if (s.includes('.'))
382
+ s = s.split('.').pop() ?? s;
383
+ return s;
384
+ }
385
+ function round2(n) {
386
+ return Math.round(n * 100) / 100;
387
+ }
388
+ // Tier 2's pack derivation mirrors `queries.ts:packFromExt` — kept
389
+ // inline rather than re-exported from queries.ts because the public
390
+ // queries.ts surface should remain the documented "graph queries"
391
+ // API (per Rule 12) and not leak a per-extension lookup table.
392
+ function packFromExt(sourceFile) {
393
+ const i = sourceFile.lastIndexOf('.');
394
+ if (i < 0)
395
+ return '';
396
+ const ext = sourceFile.slice(i).toLowerCase();
397
+ const map = {
398
+ '.ts': 'typescript',
399
+ '.tsx': 'typescript',
400
+ '.js': 'typescript',
401
+ '.jsx': 'typescript',
402
+ '.mjs': 'typescript',
403
+ '.cjs': 'typescript',
404
+ '.py': 'python',
405
+ '.go': 'go',
406
+ '.rs': 'rust',
407
+ '.cs': 'csharp',
408
+ '.kt': 'kotlin',
409
+ '.kts': 'kotlin',
410
+ '.java': 'java',
411
+ '.rb': 'ruby',
412
+ };
413
+ return map[ext] ?? '';
414
+ }
415
+ //# sourceMappingURL=graph-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-adapter.js","sourceRoot":"","sources":["../../src/dashboard/graph-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Dashboard graph-viz tab renderer — embeds graphify's vis.js viewer.
3
+ *
4
+ * Sprint 3 pivot (2026-05-27): rather than build a custom cytoscape
5
+ * tier drill-down, we embed the interactive viewer graphify itself
6
+ * ships. The upstream `graphify.export.to_html` writes a self-
7
+ * contained vis.js HTML page to `.dxkit/reports/graph.html` as a
8
+ * side-effect of `gatherGraphifyGraph` (see `analyzers/tools/
9
+ * graphify.ts`). This renderer:
10
+ *
11
+ * 1. reads that HTML
12
+ * 2. swaps graphify's unpkg.com `<script src=…vis-network…>` tag for
13
+ * an inline `<script>` containing the locally-bundled
14
+ * `vis-network.min.js` (offline-friendly per dxkit's posture —
15
+ * no third-party fetch when the user opens the dashboard)
16
+ * 3. emits the swapped HTML inside an `<iframe srcdoc>` so the
17
+ * embedded viewer's CSS + JS namespace stays isolated from the
18
+ * host dashboard
19
+ *
20
+ * Empty-state branches when `graph.html` is missing (gather never
21
+ * ran, graph exceeded the 5000-node viz cap, etc.). Vendor-missing
22
+ * branch when `dist/dashboard/vendor/vis-network.min.js` is absent
23
+ * (`npm run build` hasn't run).
24
+ *
25
+ * Per CLAUDE.md Rule 12, we still flow `graph.json` reads through
26
+ * `loadGraph` even though the renderer doesn't consume `graph.json`
27
+ * itself — the loader doubles as our existence check before we go
28
+ * read `graph.html` off disk.
29
+ */
30
+ /** Options accepted by the tab renderer. */
31
+ export interface GraphTabOptions {
32
+ /**
33
+ * Project root. The renderer reads `.dxkit/reports/graph.json` for
34
+ * the existence check (via Rule 12's `loadGraph`) and then loads
35
+ * `.dxkit/reports/graph.html` from disk for embedding.
36
+ */
37
+ cwd?: string;
38
+ /**
39
+ * Override the vendor directory. Tests pass a tmpdir with a fake
40
+ * `vis-network.min.js` so they don't depend on `npm run build`
41
+ * having populated `dist/dashboard/vendor/`.
42
+ */
43
+ vendorDir?: string;
44
+ /**
45
+ * Override the on-disk path to graphify's `graph.html`. Defaults
46
+ * to `<cwd>/.dxkit/reports/graph.html`. Tests use a fixture path.
47
+ */
48
+ graphHtmlPath?: string;
49
+ }
50
+ /**
51
+ * One-stop renderer. Returns:
52
+ * - `html`: the HTML fragment to splice into the dashboard body
53
+ * (the new "Graph" tab pane).
54
+ * - `navBadge`: the badge text the sidebar shows next to "Graph"
55
+ * (community count when ready; "—" otherwise).
56
+ * - `hasData`: convenience boolean — true when a viewable graph
57
+ * was found and the iframe will render.
58
+ */
59
+ export declare function renderGraphTab(opts: GraphTabOptions): {
60
+ html: string;
61
+ navBadge: string;
62
+ hasData: boolean;
63
+ };
64
+ /** Sidecar metadata produced by the graphify gather. */
65
+ interface GraphHtmlMeta {
66
+ mode: 'full' | 'aggregated';
67
+ totalNodes: number;
68
+ totalEdges: number;
69
+ communities: number;
70
+ aggregatedNodeCount: number | null;
71
+ }
72
+ /**
73
+ * Prepend a small banner inside graphify's `<body>` explaining that
74
+ * the visible view is community-aggregated. Surfaced for honesty —
75
+ * the user should understand each node is a cluster, not a symbol,
76
+ * when the full graph exceeded the 5000-node viz cap.
77
+ *
78
+ * Exported for tests.
79
+ */
80
+ export declare function injectAggregateBanner(html: string, meta: GraphHtmlMeta): string;
81
+ /**
82
+ * Replace graphify's `<script src="https://unpkg.com/vis-network/...">`
83
+ * with an inline `<script>` containing the bundled vis-network source.
84
+ * The replacement is conservative — we match the upstream tag exactly
85
+ * (with optional version pin + path variations) and bail to the
86
+ * untouched HTML if the pattern doesn't fit. That way an upstream
87
+ * graphify change to a different CDN URL is surfaced as "viewer works
88
+ * online only" rather than a corrupt swap.
89
+ *
90
+ * Exported for tests; downstream consumers should use `renderGraphTab`.
91
+ */
92
+ export declare function inlineVisNetwork(upstreamHtml: string, visBundle: string): string;
93
+ /**
94
+ * HTML-encode the supplied HTML so it can sit safely inside an
95
+ * `<iframe srcdoc="…">` attribute. Only the characters that
96
+ * specifically break the attribute boundary — `&`, `"`, and `<` — get
97
+ * escaped. (`<` would prematurely close the iframe's start tag in the
98
+ * outer document if naive UTF-8 left it unescaped.)
99
+ */
100
+ export declare function encodeForSrcdoc(html: string): string;
101
+ /**
102
+ * CSS for the graph tab. The host dashboard at
103
+ * `src/analyzers/dashboard/index.ts` splices this into its global
104
+ * `<style>` block via a sibling import. The iframe gets a fixed-height
105
+ * fill of the tab area; the empty-state card centers vertically.
106
+ */
107
+ export declare const GRAPH_TAB_CSS = "\n.graph-tab-pane { flex: 1; flex-direction: column; padding: 24px 28px; overflow: hidden; }\n.graph-tab-empty.graph-tab-pane { display: flex; align-items: center; justify-content: center; min-height: 400px; padding: 60px 32px; }\n.graph-empty-card { text-align: center; padding: 48px 32px; background: var(--bg-card); border-radius: 12px; border: 1px solid var(--border); max-width: 640px; }\n.graph-empty-icon { font-size: 56px; margin-bottom: 16px; }\n.graph-empty-card h2 { font-size: 22px; color: var(--text-primary); margin-bottom: 12px; }\n.graph-empty-card p { color: var(--text-secondary); line-height: 1.55; }\n.graph-empty-card code { background: var(--bg-tertiary); padding: 2px 6px; border-radius: 4px; font-family: ui-monospace, \"SF Mono\", Menlo, monospace; font-size: 0.92em; }\n.graph-iframe { width: 100%; height: 100%; min-height: 600px; border: 1px solid var(--border); border-radius: 10px; background: var(--bg-primary); }\n";
108
+ export {};
109
+ //# sourceMappingURL=graph-tab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-tab.d.ts","sourceRoot":"","sources":["../../src/dashboard/graph-tab.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAUH,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB,CAgFA;AAUD,wDAAwD;AACxD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,GAAG,YAAY,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAsBD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CAe/E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAsBhF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAwCD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,u7BASzB,CAAC"}