@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,297 @@
1
+ "use strict";
2
+ /**
3
+ * Dashboard graph-viz tab renderer — embeds graphify's vis.js viewer.
4
+ *
5
+ * Sprint 3 pivot (2026-05-27): rather than build a custom cytoscape
6
+ * tier drill-down, we embed the interactive viewer graphify itself
7
+ * ships. The upstream `graphify.export.to_html` writes a self-
8
+ * contained vis.js HTML page to `.dxkit/reports/graph.html` as a
9
+ * side-effect of `gatherGraphifyGraph` (see `analyzers/tools/
10
+ * graphify.ts`). This renderer:
11
+ *
12
+ * 1. reads that HTML
13
+ * 2. swaps graphify's unpkg.com `<script src=…vis-network…>` tag for
14
+ * an inline `<script>` containing the locally-bundled
15
+ * `vis-network.min.js` (offline-friendly per dxkit's posture —
16
+ * no third-party fetch when the user opens the dashboard)
17
+ * 3. emits the swapped HTML inside an `<iframe srcdoc>` so the
18
+ * embedded viewer's CSS + JS namespace stays isolated from the
19
+ * host dashboard
20
+ *
21
+ * Empty-state branches when `graph.html` is missing (gather never
22
+ * ran, graph exceeded the 5000-node viz cap, etc.). Vendor-missing
23
+ * branch when `dist/dashboard/vendor/vis-network.min.js` is absent
24
+ * (`npm run build` hasn't run).
25
+ *
26
+ * Per CLAUDE.md Rule 12, we still flow `graph.json` reads through
27
+ * `loadGraph` even though the renderer doesn't consume `graph.json`
28
+ * itself — the loader doubles as our existence check before we go
29
+ * read `graph.html` off disk.
30
+ */
31
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
32
+ if (k2 === undefined) k2 = k;
33
+ var desc = Object.getOwnPropertyDescriptor(m, k);
34
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
35
+ desc = { enumerable: true, get: function() { return m[k]; } };
36
+ }
37
+ Object.defineProperty(o, k2, desc);
38
+ }) : (function(o, m, k, k2) {
39
+ if (k2 === undefined) k2 = k;
40
+ o[k2] = m[k];
41
+ }));
42
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
43
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
44
+ }) : function(o, v) {
45
+ o["default"] = v;
46
+ });
47
+ var __importStar = (this && this.__importStar) || (function () {
48
+ var ownKeys = function(o) {
49
+ ownKeys = Object.getOwnPropertyNames || function (o) {
50
+ var ar = [];
51
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
52
+ return ar;
53
+ };
54
+ return ownKeys(o);
55
+ };
56
+ return function (mod) {
57
+ if (mod && mod.__esModule) return mod;
58
+ var result = {};
59
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
60
+ __setModuleDefault(result, mod);
61
+ return result;
62
+ };
63
+ })();
64
+ Object.defineProperty(exports, "__esModule", { value: true });
65
+ exports.GRAPH_TAB_CSS = void 0;
66
+ exports.renderGraphTab = renderGraphTab;
67
+ exports.injectAggregateBanner = injectAggregateBanner;
68
+ exports.inlineVisNetwork = inlineVisNetwork;
69
+ exports.encodeForSrcdoc = encodeForSrcdoc;
70
+ const fs = __importStar(require("fs"));
71
+ const path = __importStar(require("path"));
72
+ const load_1 = require("../explore/load");
73
+ /** Default vendor + report locations, relative to module + cwd. */
74
+ const VENDOR_DIR = path.join(__dirname, 'vendor');
75
+ const GRAPH_HTML_REL = path.join('.dxkit', 'reports', 'graph.html');
76
+ /**
77
+ * One-stop renderer. Returns:
78
+ * - `html`: the HTML fragment to splice into the dashboard body
79
+ * (the new "Graph" tab pane).
80
+ * - `navBadge`: the badge text the sidebar shows next to "Graph"
81
+ * (community count when ready; "—" otherwise).
82
+ * - `hasData`: convenience boolean — true when a viewable graph
83
+ * was found and the iframe will render.
84
+ */
85
+ function renderGraphTab(opts) {
86
+ const cwd = opts.cwd;
87
+ const graphHtmlPath = opts.graphHtmlPath ?? (cwd ? path.join(cwd, GRAPH_HTML_REL) : '');
88
+ const vendorDir = opts.vendorDir ?? VENDOR_DIR;
89
+ // Rule-12-friendly existence check via the canonical loader. Failure
90
+ // = missing/corrupt graph.json = empty state regardless of whether
91
+ // graph.html happens to be on disk.
92
+ let communityCount = 0;
93
+ if (cwd) {
94
+ try {
95
+ const graph = (0, load_1.loadGraph)(cwd);
96
+ communityCount = graph.communities.length;
97
+ }
98
+ catch {
99
+ // fall through to empty-state
100
+ }
101
+ }
102
+ if (!cwd || communityCount === 0) {
103
+ return {
104
+ html: renderEmptyState('No graph data found.', emptyStateMessage()),
105
+ navBadge: '—',
106
+ hasData: false,
107
+ };
108
+ }
109
+ if (!graphHtmlPath || !fs.existsSync(graphHtmlPath)) {
110
+ // Graph.json exists but graph.html doesn't — the gather ran but
111
+ // skipped the viz emission (most likely the 5000-node MAX_NODES_FOR_VIZ
112
+ // guard tripped, or graphify is too old to know about to_html). Tell
113
+ // the user what we know.
114
+ return {
115
+ html: renderEmptyState('Interactive viewer skipped.', `Graph data exists (\`.dxkit/reports/graph.json\`, ${communityCount} communities) but graphify's interactive viewer wasn't generated. Common causes: the graph exceeds graphify's 5000-node viewer cap, or the installed graphify is older than v0.5 (run \`npx vyuh-dxkit tools install\` to refresh).`),
116
+ navBadge: String(communityCount),
117
+ hasData: false,
118
+ };
119
+ }
120
+ const visBundle = readVisNetworkBundle(vendorDir);
121
+ if (!visBundle) {
122
+ return {
123
+ html: renderEmptyState('vis-network bundle missing.', 'The dashboard ships an offline-friendly vis-network alongside the graphify viewer; the bundle at `dist/dashboard/vendor/vis-network.min.js` is not present. This typically means dxkit was built without `npm run build`. Run the build and regenerate the dashboard.'),
124
+ navBadge: String(communityCount),
125
+ hasData: false,
126
+ };
127
+ }
128
+ let upstreamHtml;
129
+ try {
130
+ upstreamHtml = fs.readFileSync(graphHtmlPath, 'utf-8');
131
+ }
132
+ catch (err) {
133
+ const msg = err instanceof Error ? err.message : String(err);
134
+ return {
135
+ html: renderEmptyState('Failed to read graph.html.', `Error: ${msg}`),
136
+ navBadge: '—',
137
+ hasData: false,
138
+ };
139
+ }
140
+ // Read the sidecar meta if present so we can surface "aggregated view"
141
+ // honestly to the user. Absent meta = older graphify run before the
142
+ // sidecar landed; treat as 'full' and skip the banner.
143
+ const meta = readGraphHtmlMeta(graphHtmlPath);
144
+ const annotatedHtml = meta?.mode === 'aggregated' ? injectAggregateBanner(upstreamHtml, meta) : upstreamHtml;
145
+ const offlineHtml = inlineVisNetwork(annotatedHtml, visBundle);
146
+ const iframe = buildSrcdocIframe(offlineHtml);
147
+ return {
148
+ html: `<div id="graph-tab-pane" class="graph-tab-pane" style="display:none">${iframe}</div>`,
149
+ navBadge: String(communityCount),
150
+ hasData: true,
151
+ };
152
+ }
153
+ // ─── Vendor + HTML manipulation ──────────────────────────────────────────────
154
+ function readVisNetworkBundle(vendorDir) {
155
+ const file = path.join(vendorDir, 'vis-network.min.js');
156
+ if (!fs.existsSync(file))
157
+ return undefined;
158
+ return fs.readFileSync(file, 'utf-8');
159
+ }
160
+ function readGraphHtmlMeta(graphHtmlPath) {
161
+ const metaPath = `${graphHtmlPath}.meta.json`;
162
+ if (!fs.existsSync(metaPath))
163
+ return undefined;
164
+ try {
165
+ const parsed = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
166
+ if (parsed &&
167
+ typeof parsed === 'object' &&
168
+ 'mode' in parsed &&
169
+ parsed.mode &&
170
+ typeof parsed.mode === 'string') {
171
+ return parsed;
172
+ }
173
+ }
174
+ catch {
175
+ // ignore — absent/corrupt meta = no banner, viewer still works
176
+ }
177
+ return undefined;
178
+ }
179
+ /**
180
+ * Prepend a small banner inside graphify's `<body>` explaining that
181
+ * the visible view is community-aggregated. Surfaced for honesty —
182
+ * the user should understand each node is a cluster, not a symbol,
183
+ * when the full graph exceeded the 5000-node viz cap.
184
+ *
185
+ * Exported for tests.
186
+ */
187
+ function injectAggregateBanner(html, meta) {
188
+ const banner = `
189
+ <div id="dxkit-aggregated-banner" style="position:fixed;top:8px;left:8px;right:300px;z-index:1000;padding:10px 14px;background:rgba(78,121,167,0.92);color:#fff;border-radius:6px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;font-size:12px;line-height:1.45;box-shadow:0 2px 8px rgba(0,0,0,0.4);">
190
+ <strong>Community-aggregated view.</strong>
191
+ Each node is a Louvain cluster of related symbols, not an individual symbol — the full graph (${meta.totalNodes.toLocaleString()} symbols, ${meta.totalEdges.toLocaleString()} edges) exceeds vis.js's 5,000-node interactive cap.
192
+ Showing ${meta.communities.toLocaleString()} communities; node size = member count.
193
+ Use <code style="background:rgba(255,255,255,0.18);padding:1px 5px;border-radius:3px;">npx vyuh-dxkit explore</code> to drill into a specific community.
194
+ </div>`;
195
+ // Inject right after <body> so the banner sits above the canvas
196
+ // without disturbing graphify's existing flex layout.
197
+ const bodyIdx = html.indexOf('<body');
198
+ if (bodyIdx === -1)
199
+ return html;
200
+ const tagEnd = html.indexOf('>', bodyIdx);
201
+ if (tagEnd === -1)
202
+ return html;
203
+ return html.slice(0, tagEnd + 1) + banner + html.slice(tagEnd + 1);
204
+ }
205
+ /**
206
+ * Replace graphify's `<script src="https://unpkg.com/vis-network/...">`
207
+ * with an inline `<script>` containing the bundled vis-network source.
208
+ * The replacement is conservative — we match the upstream tag exactly
209
+ * (with optional version pin + path variations) and bail to the
210
+ * untouched HTML if the pattern doesn't fit. That way an upstream
211
+ * graphify change to a different CDN URL is surfaced as "viewer works
212
+ * online only" rather than a corrupt swap.
213
+ *
214
+ * Exported for tests; downstream consumers should use `renderGraphTab`.
215
+ */
216
+ function inlineVisNetwork(upstreamHtml, visBundle) {
217
+ // Conservative match for the upstream HTML's
218
+ // `<script ... src="...vis-network...">` tag. Inline-script body is
219
+ // JS, so a `<` inside the bundle would close the surrounding
220
+ // <script> tag prematurely if we naively concatenated —
221
+ // vis-network's minified UMD doesn't contain `</script>` substrings,
222
+ // but defensively escape just in case.
223
+ const safeBundle = visBundle.replace(/<\/script>/gi, '<\\/script>');
224
+ const inline = `<script>${safeBundle}</script>`;
225
+ const pattern = /<script\b[^>]*\bsrc=(["'])[^"']*vis-network[^"']*\1[^>]*><\/script>/i;
226
+ if (!pattern.test(upstreamHtml)) {
227
+ // No CDN script to swap. Return upstream verbatim — graphify either
228
+ // already bundles vis-network or the upstream format changed; in
229
+ // either case our offline-conversion is a no-op rather than a corruption.
230
+ return upstreamHtml;
231
+ }
232
+ // Use a function-form replacement so $1/$&/$' inside the bundle source
233
+ // are not interpreted as `replace`'s magic backreferences. vis-network's
234
+ // minified UMD contains `"$1"` (a regex capture-group reference inside
235
+ // a string literal); a bare string replacement would silently eat it
236
+ // and corrupt the bundle.
237
+ return upstreamHtml.replace(pattern, () => inline);
238
+ }
239
+ /**
240
+ * HTML-encode the supplied HTML so it can sit safely inside an
241
+ * `<iframe srcdoc="…">` attribute. Only the characters that
242
+ * specifically break the attribute boundary — `&`, `"`, and `<` — get
243
+ * escaped. (`<` would prematurely close the iframe's start tag in the
244
+ * outer document if naive UTF-8 left it unescaped.)
245
+ */
246
+ function encodeForSrcdoc(html) {
247
+ return html.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;');
248
+ }
249
+ function buildSrcdocIframe(html) {
250
+ const encoded = encodeForSrcdoc(html);
251
+ return `<iframe
252
+ id="graph-iframe"
253
+ class="graph-iframe"
254
+ title="Code graph — interactive viewer"
255
+ loading="lazy"
256
+ sandbox="allow-scripts allow-same-origin"
257
+ srcdoc="${encoded}"
258
+ ></iframe>`;
259
+ }
260
+ // ─── Empty-state rendering ───────────────────────────────────────────────────
261
+ function emptyStateMessage() {
262
+ return 'Run `npx vyuh-dxkit health .` to generate the repo graph (graphify produces `.dxkit/reports/graph.json` + `graph.html` automatically), then reload this dashboard.';
263
+ }
264
+ function renderEmptyState(headline, body) {
265
+ return `<div id="graph-tab-pane" class="graph-tab-pane graph-tab-empty" style="display:none">
266
+ <div class="graph-empty-card">
267
+ <div class="graph-empty-icon">🗺️</div>
268
+ <h2>${escapeHtml(headline)}</h2>
269
+ <p>${body}</p>
270
+ </div>
271
+ </div>`;
272
+ }
273
+ function escapeHtml(s) {
274
+ return s
275
+ .replace(/&/g, '&amp;')
276
+ .replace(/</g, '&lt;')
277
+ .replace(/>/g, '&gt;')
278
+ .replace(/"/g, '&quot;');
279
+ }
280
+ // ─── Embedded CSS (spliced into the host dashboard's style block) ────────────
281
+ /**
282
+ * CSS for the graph tab. The host dashboard at
283
+ * `src/analyzers/dashboard/index.ts` splices this into its global
284
+ * `<style>` block via a sibling import. The iframe gets a fixed-height
285
+ * fill of the tab area; the empty-state card centers vertically.
286
+ */
287
+ exports.GRAPH_TAB_CSS = `
288
+ .graph-tab-pane { flex: 1; flex-direction: column; padding: 24px 28px; overflow: hidden; }
289
+ .graph-tab-empty.graph-tab-pane { display: flex; align-items: center; justify-content: center; min-height: 400px; padding: 60px 32px; }
290
+ .graph-empty-card { text-align: center; padding: 48px 32px; background: var(--bg-card); border-radius: 12px; border: 1px solid var(--border); max-width: 640px; }
291
+ .graph-empty-icon { font-size: 56px; margin-bottom: 16px; }
292
+ .graph-empty-card h2 { font-size: 22px; color: var(--text-primary); margin-bottom: 12px; }
293
+ .graph-empty-card p { color: var(--text-secondary); line-height: 1.55; }
294
+ .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; }
295
+ .graph-iframe { width: 100%; height: 100%; min-height: 600px; border: 1px solid var(--border); border-radius: 10px; background: var(--bg-primary); }
296
+ `;
297
+ //# sourceMappingURL=graph-tab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-tab.js","sourceRoot":"","sources":["../../src/dashboard/graph-tab.ts"],"names":[],"mappings":"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"}