speccore 8.3.349 → 8.3.366

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 (274) hide show
  1. package/.agents/skills/spec-unitize/SKILL.md +5 -1
  2. package/.agents/skills/spec-verify/SKILL.md +22 -1
  3. package/dist/cli.js +19 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/about.d.ts.map +1 -1
  6. package/dist/commands/about.js +36 -1
  7. package/dist/commands/about.js.map +1 -1
  8. package/dist/commands/analyze/add-platform.d.ts +3 -0
  9. package/dist/commands/analyze/add-platform.d.ts.map +1 -0
  10. package/dist/commands/analyze/add-platform.js +82 -0
  11. package/dist/commands/analyze/add-platform.js.map +1 -0
  12. package/dist/commands/analyze/audit-fix.d.ts +3 -0
  13. package/dist/commands/analyze/audit-fix.d.ts.map +1 -0
  14. package/dist/commands/analyze/audit-fix.js +73 -0
  15. package/dist/commands/analyze/audit-fix.js.map +1 -0
  16. package/dist/commands/analyze/context-guard.d.ts +3 -0
  17. package/dist/commands/analyze/context-guard.d.ts.map +1 -0
  18. package/dist/commands/analyze/context-guard.js +75 -0
  19. package/dist/commands/analyze/context-guard.js.map +1 -0
  20. package/dist/commands/analyze/doc.d.ts +3 -0
  21. package/dist/commands/analyze/doc.d.ts.map +1 -0
  22. package/dist/commands/analyze/doc.js +77 -0
  23. package/dist/commands/analyze/doc.js.map +1 -0
  24. package/dist/commands/analyze/feature.d.ts +3 -0
  25. package/dist/commands/analyze/feature.d.ts.map +1 -0
  26. package/dist/commands/analyze/feature.js +75 -0
  27. package/dist/commands/analyze/feature.js.map +1 -0
  28. package/dist/commands/analyze/from-code.d.ts +3 -0
  29. package/dist/commands/analyze/from-code.d.ts.map +1 -0
  30. package/dist/commands/analyze/from-code.js +94 -0
  31. package/dist/commands/analyze/from-code.js.map +1 -0
  32. package/dist/commands/analyze/incremental.d.ts +3 -0
  33. package/dist/commands/analyze/incremental.d.ts.map +1 -0
  34. package/dist/commands/analyze/incremental.js +90 -0
  35. package/dist/commands/analyze/incremental.js.map +1 -0
  36. package/dist/commands/analyze/modes.d.ts +13 -0
  37. package/dist/commands/analyze/modes.d.ts.map +1 -0
  38. package/dist/commands/analyze/modes.js +147 -0
  39. package/dist/commands/analyze/modes.js.map +1 -0
  40. package/dist/commands/analyze/module.d.ts +3 -0
  41. package/dist/commands/analyze/module.d.ts.map +1 -0
  42. package/dist/commands/analyze/module.js +95 -0
  43. package/dist/commands/analyze/module.js.map +1 -0
  44. package/dist/commands/analyze/overview.d.ts +3 -0
  45. package/dist/commands/analyze/overview.d.ts.map +1 -0
  46. package/dist/commands/analyze/overview.js +125 -0
  47. package/dist/commands/analyze/overview.js.map +1 -0
  48. package/dist/commands/analyze/shared.d.ts +53 -0
  49. package/dist/commands/analyze/shared.d.ts.map +1 -0
  50. package/dist/commands/analyze/shared.js +34 -0
  51. package/dist/commands/analyze/shared.js.map +1 -0
  52. package/dist/commands/analyze/units.d.ts +46 -0
  53. package/dist/commands/analyze/units.d.ts.map +1 -0
  54. package/dist/commands/analyze/units.js +950 -0
  55. package/dist/commands/analyze/units.js.map +1 -0
  56. package/dist/commands/analyze.d.ts +6 -88
  57. package/dist/commands/analyze.d.ts.map +1 -1
  58. package/dist/commands/analyze.js +167 -1419
  59. package/dist/commands/analyze.js.map +1 -1
  60. package/dist/commands/ask.d.ts.map +1 -1
  61. package/dist/commands/ask.js +4 -2
  62. package/dist/commands/ask.js.map +1 -1
  63. package/dist/commands/dashboard.d.ts.map +1 -1
  64. package/dist/commands/dashboard.js +36 -1
  65. package/dist/commands/dashboard.js.map +1 -1
  66. package/dist/commands/deploy.d.ts +6 -0
  67. package/dist/commands/deploy.d.ts.map +1 -1
  68. package/dist/commands/deploy.js +153 -0
  69. package/dist/commands/deploy.js.map +1 -1
  70. package/dist/commands/doc2spec.d.ts +1 -1
  71. package/dist/commands/doc2spec.d.ts.map +1 -1
  72. package/dist/commands/doc2spec.js +39 -24
  73. package/dist/commands/doc2spec.js.map +1 -1
  74. package/dist/commands/doctor.js +60 -13
  75. package/dist/commands/doctor.js.map +1 -1
  76. package/dist/commands/execute.d.ts.map +1 -1
  77. package/dist/commands/execute.js +22 -0
  78. package/dist/commands/execute.js.map +1 -1
  79. package/dist/commands/help.js +36 -1
  80. package/dist/commands/help.js.map +1 -1
  81. package/dist/commands/init.js +1 -1
  82. package/dist/commands/init.js.map +1 -1
  83. package/dist/commands/pipeline.d.ts.map +1 -1
  84. package/dist/commands/pipeline.js +15 -0
  85. package/dist/commands/pipeline.js.map +1 -1
  86. package/dist/commands/plan.js +2 -0
  87. package/dist/commands/plan.js.map +1 -1
  88. package/dist/commands/pr.d.ts.map +1 -1
  89. package/dist/commands/pr.js +14 -3
  90. package/dist/commands/pr.js.map +1 -1
  91. package/dist/commands/prompts.d.ts +11 -1
  92. package/dist/commands/prompts.d.ts.map +1 -1
  93. package/dist/commands/prompts.js +197 -15
  94. package/dist/commands/prompts.js.map +1 -1
  95. package/dist/commands/reindex.d.ts.map +1 -1
  96. package/dist/commands/reindex.js +23 -0
  97. package/dist/commands/reindex.js.map +1 -1
  98. package/dist/commands/retro.d.ts.map +1 -1
  99. package/dist/commands/retro.js +3 -1
  100. package/dist/commands/retro.js.map +1 -1
  101. package/dist/commands/status-panel.d.ts.map +1 -1
  102. package/dist/commands/status-panel.js +9 -1
  103. package/dist/commands/status-panel.js.map +1 -1
  104. package/dist/commands/unitize.d.ts +3 -0
  105. package/dist/commands/unitize.d.ts.map +1 -1
  106. package/dist/commands/unitize.js +183 -6
  107. package/dist/commands/unitize.js.map +1 -1
  108. package/dist/commands/update-env-configs.d.ts.map +1 -1
  109. package/dist/commands/update-env-configs.js +10 -0
  110. package/dist/commands/update-env-configs.js.map +1 -1
  111. package/dist/commands/verify.d.ts +8 -0
  112. package/dist/commands/verify.d.ts.map +1 -1
  113. package/dist/commands/verify.js +383 -16
  114. package/dist/commands/verify.js.map +1 -1
  115. package/dist/commands/welcome.d.ts.map +1 -1
  116. package/dist/commands/welcome.js +3 -1
  117. package/dist/commands/welcome.js.map +1 -1
  118. package/dist/core/ai-context-generator.d.ts +21 -0
  119. package/dist/core/ai-context-generator.d.ts.map +1 -1
  120. package/dist/core/ai-context-generator.js +54 -1
  121. package/dist/core/ai-context-generator.js.map +1 -1
  122. package/dist/core/ai-verify/plan-generator.d.ts +94 -0
  123. package/dist/core/ai-verify/plan-generator.d.ts.map +1 -0
  124. package/dist/core/ai-verify/plan-generator.js +598 -0
  125. package/dist/core/ai-verify/plan-generator.js.map +1 -0
  126. package/dist/core/ai-verify/result-parser.d.ts +27 -0
  127. package/dist/core/ai-verify/result-parser.d.ts.map +1 -0
  128. package/dist/core/ai-verify/result-parser.js +212 -0
  129. package/dist/core/ai-verify/result-parser.js.map +1 -0
  130. package/dist/core/ai-verify/scope-resolver.d.ts +34 -0
  131. package/dist/core/ai-verify/scope-resolver.d.ts.map +1 -0
  132. package/dist/core/ai-verify/scope-resolver.js +183 -0
  133. package/dist/core/ai-verify/scope-resolver.js.map +1 -0
  134. package/dist/core/ai-verify/types.d.ts +171 -0
  135. package/dist/core/ai-verify/types.d.ts.map +1 -0
  136. package/dist/core/ai-verify/types.js +9 -0
  137. package/dist/core/ai-verify/types.js.map +1 -0
  138. package/dist/core/ai-verify/visual-judge.d.ts +33 -0
  139. package/dist/core/ai-verify/visual-judge.d.ts.map +1 -0
  140. package/dist/core/ai-verify/visual-judge.js +123 -0
  141. package/dist/core/ai-verify/visual-judge.js.map +1 -0
  142. package/dist/core/analyze-engine.d.ts.map +1 -1
  143. package/dist/core/analyze-engine.js +2 -1
  144. package/dist/core/analyze-engine.js.map +1 -1
  145. package/dist/core/ask-engine.d.ts +6 -0
  146. package/dist/core/ask-engine.d.ts.map +1 -1
  147. package/dist/core/ask-engine.js +83 -3
  148. package/dist/core/ask-engine.js.map +1 -1
  149. package/dist/core/code-graph/builder.d.ts.map +1 -1
  150. package/dist/core/code-graph/builder.js +93 -75
  151. package/dist/core/code-graph/builder.js.map +1 -1
  152. package/dist/core/code-graph/incremental-build.d.ts.map +1 -1
  153. package/dist/core/code-graph/incremental-build.js +13 -19
  154. package/dist/core/code-graph/incremental-build.js.map +1 -1
  155. package/dist/core/code-graph/index.d.ts +1 -1
  156. package/dist/core/code-graph/index.d.ts.map +1 -1
  157. package/dist/core/code-graph/index.js +15 -12
  158. package/dist/core/code-graph/index.js.map +1 -1
  159. package/dist/core/code-graph/multimodal.js +1 -1
  160. package/dist/core/code-graph/parser.js +1 -1
  161. package/dist/core/code-graph/query.d.ts +1 -1
  162. package/dist/core/code-graph/reporter.d.ts +1 -1
  163. package/dist/core/code-graph/reporter.d.ts.map +1 -1
  164. package/dist/core/code-graph/reporter.js +18 -10
  165. package/dist/core/code-graph/reporter.js.map +1 -1
  166. package/dist/core/code-graph/requirement-linker.d.ts.map +1 -1
  167. package/dist/core/code-graph/requirement-linker.js +24 -14
  168. package/dist/core/code-graph/requirement-linker.js.map +1 -1
  169. package/dist/core/code-graph/types.d.ts +1 -1
  170. package/dist/core/code-graph/types.js +1 -1
  171. package/dist/core/code-graph/visualizer.d.ts +1 -7
  172. package/dist/core/code-graph/visualizer.d.ts.map +1 -1
  173. package/dist/core/code-graph/visualizer.js +476 -49
  174. package/dist/core/code-graph/visualizer.js.map +1 -1
  175. package/dist/core/code-scanner.d.ts +2 -0
  176. package/dist/core/code-scanner.d.ts.map +1 -1
  177. package/dist/core/code-scanner.js +13 -1
  178. package/dist/core/code-scanner.js.map +1 -1
  179. package/dist/core/deploy/engine.d.ts +21 -0
  180. package/dist/core/deploy/engine.d.ts.map +1 -1
  181. package/dist/core/deploy/engine.js +276 -0
  182. package/dist/core/deploy/engine.js.map +1 -1
  183. package/dist/core/deploy-ledger.d.ts +12 -0
  184. package/dist/core/deploy-ledger.d.ts.map +1 -0
  185. package/dist/core/deploy-ledger.js +35 -0
  186. package/dist/core/deploy-ledger.js.map +1 -0
  187. package/dist/core/environment-config.d.ts +11 -0
  188. package/dist/core/environment-config.d.ts.map +1 -1
  189. package/dist/core/environment-config.js +4 -0
  190. package/dist/core/environment-config.js.map +1 -1
  191. package/dist/core/intent-cache.d.ts.map +1 -1
  192. package/dist/core/intent-cache.js +6 -0
  193. package/dist/core/intent-cache.js.map +1 -1
  194. package/dist/core/knowledge-visualizer.js +1 -1
  195. package/dist/core/page-bundle.d.ts +2 -0
  196. package/dist/core/page-bundle.d.ts.map +1 -1
  197. package/dist/core/page-bundle.js +18 -1
  198. package/dist/core/page-bundle.js.map +1 -1
  199. package/dist/core/plan-html.js +1 -1
  200. package/dist/core/platform-inference.d.ts +35 -0
  201. package/dist/core/platform-inference.d.ts.map +1 -1
  202. package/dist/core/platform-inference.js +92 -0
  203. package/dist/core/platform-inference.js.map +1 -1
  204. package/dist/core/prompt-plugins/analyze-graph-plugin.d.ts.map +1 -1
  205. package/dist/core/prompt-plugins/analyze-graph-plugin.js +16 -1
  206. package/dist/core/prompt-plugins/analyze-graph-plugin.js.map +1 -1
  207. package/dist/core/prompt-plugins/execute-graph-plugin.d.ts +2 -0
  208. package/dist/core/prompt-plugins/execute-graph-plugin.d.ts.map +1 -1
  209. package/dist/core/prompt-plugins/execute-graph-plugin.js +127 -27
  210. package/dist/core/prompt-plugins/execute-graph-plugin.js.map +1 -1
  211. package/dist/core/quality-audit.d.ts.map +1 -1
  212. package/dist/core/quality-audit.js +18 -0
  213. package/dist/core/quality-audit.js.map +1 -1
  214. package/dist/core/rag-engine.d.ts.map +1 -1
  215. package/dist/core/rag-engine.js +12 -243
  216. package/dist/core/rag-engine.js.map +1 -1
  217. package/dist/core/reindex-engine.d.ts +20 -0
  218. package/dist/core/reindex-engine.d.ts.map +1 -1
  219. package/dist/core/reindex-engine.js +142 -0
  220. package/dist/core/reindex-engine.js.map +1 -1
  221. package/dist/core/requirement-clarifier.d.ts.map +1 -1
  222. package/dist/core/requirement-clarifier.js +22 -6
  223. package/dist/core/requirement-clarifier.js.map +1 -1
  224. package/dist/core/reverse-requirement.d.ts +37 -0
  225. package/dist/core/reverse-requirement.d.ts.map +1 -1
  226. package/dist/core/reverse-requirement.js +84 -9
  227. package/dist/core/reverse-requirement.js.map +1 -1
  228. package/dist/core/spec-paths.d.ts +5 -0
  229. package/dist/core/spec-paths.d.ts.map +1 -1
  230. package/dist/core/spec-paths.js +1 -0
  231. package/dist/core/spec-paths.js.map +1 -1
  232. package/dist/core/test-config.d.ts +7 -1
  233. package/dist/core/test-config.d.ts.map +1 -1
  234. package/dist/core/test-config.js +59 -11
  235. package/dist/core/test-config.js.map +1 -1
  236. package/dist/core/ui-verify/index.d.ts +1 -1
  237. package/dist/core/ui-verify/index.d.ts.map +1 -1
  238. package/dist/core/ui-verify/index.js +2 -1
  239. package/dist/core/ui-verify/index.js.map +1 -1
  240. package/dist/core/ui-verify/smoke-engine.js +71 -15
  241. package/dist/core/ui-verify/smoke-engine.js.map +1 -1
  242. package/dist/core/ui-verify/spec-generator.d.ts +5 -9
  243. package/dist/core/ui-verify/spec-generator.d.ts.map +1 -1
  244. package/dist/core/ui-verify/spec-generator.js +66 -3
  245. package/dist/core/ui-verify/spec-generator.js.map +1 -1
  246. package/dist/core/ui-verify/types.d.ts +25 -0
  247. package/dist/core/ui-verify/types.d.ts.map +1 -1
  248. package/dist/core/ui-verify/visual-model-client.d.ts +2 -0
  249. package/dist/core/ui-verify/visual-model-client.d.ts.map +1 -1
  250. package/dist/core/ui-verify/visual-model-client.js +4 -4
  251. package/dist/core/ui-verify/visual-model-client.js.map +1 -1
  252. package/dist/core/unified-config.d.ts +27 -0
  253. package/dist/core/unified-config.d.ts.map +1 -1
  254. package/dist/core/unified-config.js +37 -0
  255. package/dist/core/unified-config.js.map +1 -1
  256. package/dist/core/unified-retrieval.d.ts +8 -0
  257. package/dist/core/unified-retrieval.d.ts.map +1 -1
  258. package/dist/core/unified-retrieval.js +18 -0
  259. package/dist/core/unified-retrieval.js.map +1 -1
  260. package/dist/utils/synonyms.d.ts.map +1 -1
  261. package/dist/utils/synonyms.js +4 -0
  262. package/dist/utils/synonyms.js.map +1 -1
  263. package/package.json +1 -1
  264. package/templates/accounts-example.yaml +49 -0
  265. package/templates/html/fonts/JetBrainsMono.woff2 +0 -0
  266. package/templates/html/fonts/Orbitron.woff2 +0 -0
  267. package/templates/html/speccore-ask-explain.html +1 -1
  268. package/templates/html/speccore-ask-guide.html +2 -2
  269. package/templates/html/speccore-ask-match.html +1 -1
  270. package/templates/html/speccore-ask-pipeline.html +1 -1
  271. package/templates/html/speccore-ask-result.html +2 -2
  272. package/templates/html/speccore-help.html +2 -2
  273. package/templates/html/speccore-setup-guide.html +16 -1
  274. package/templates/speccore-yml-example.yml +12 -0
@@ -1,48 +1,178 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildCodeGraphHtml = buildCodeGraphHtml;
4
- function buildCodeGraphHtml(graph) {
5
- const palette = [
6
- '#0ea5e9', '#14b8a6', '#f97316', '#8b5cf6',
7
- '#ec4899', '#22c55e', '#eab308', '#6366f1',
8
- '#06b6d4', '#f43f5e',
9
- ];
10
- const nodes = graph.nodes.map(n => ({
11
- id: n.id,
12
- label: n.name,
13
- group: n.community ?? -1,
14
- title: `<b>${n.name}</b><br>type: ${n.type}<br>file: ${n.filePath}<br>line: ${n.line}<br>degree: ${n.degree}`,
15
- value: n.degree || 1,
16
- color: n.community !== undefined ? palette[n.community % palette.length] : '#94a3b8',
17
- }));
18
- const edges = graph.edges.map((e, i) => ({
19
- from: e.source,
20
- to: e.target,
21
- label: e.type,
22
- title: `${e.type} (${e.confidence})`,
23
- dashes: e.confidence === 'INFERRED',
24
- color: e.confidence === 'EXTRACTED' ? { color: '#0ea5e9', opacity: 0.6 } : { color: '#94a3b8', opacity: 0.4 },
25
- arrows: { to: { enabled: true, scaleFactor: 0.5 } },
26
- }));
27
- const godNodeSet = new Set(graph.godNodes);
28
- for (const n of nodes) {
29
- if (godNodeSet.has(n.id)) {
30
- n.value = (n.value || 1) * 2;
31
- n.font = { size: 16, bold: true };
4
+ /**
5
+ * Code Knowledge Graph — graph.html 可视化生成器
6
+ * v8.3.356: vis-network 单层全量渲染(节点过万成毛线球)
7
+ * v8.3.358: 双层视图重构 —— 社区总览(30 节点秒开)→ 双击钻入成员层;
8
+ * 需求↔代码联动侧栏 + 边类型/God 开关 + 节点详情面板;
9
+ * 连续色相调色板(30 社区各归其色,修复 %10 同色);
10
+ * 边字段压缩(f/t/ty/c)瘦身 + 桥接聚合边(跨社区边按社区对合并)。
11
+ */
12
+ const fs_extra_1 = require("fs-extra");
13
+ const path_1 = require("path");
14
+ /**
15
+ * v8.3.360+: 把 vis-network UMD 落地到 .speccore/code-graph/(离线可开)。
16
+ * 本地缺失时尝试从 unpkg 下载一次(8s 超时),失败静默回退 CDN 引用。
17
+ */
18
+ async function ensureVisNetworkLocal(root) {
19
+ const localJs = (0, path_1.join)(root, '.speccore', 'code-graph', 'vis-network.min.js');
20
+ if (await (0, fs_extra_1.pathExists)(localJs))
21
+ return true;
22
+ try {
23
+ const res = await fetch('https://unpkg.com/vis-network/standalone/umd/vis-network.min.js', {
24
+ signal: AbortSignal.timeout(8000),
25
+ });
26
+ if (!res.ok)
27
+ return false;
28
+ await (0, fs_extra_1.writeFile)(localJs, Buffer.from(await res.arrayBuffer()));
29
+ return true;
30
+ }
31
+ catch { /* 无网络时回退 CDN */
32
+ return false;
33
+ }
34
+ }
35
+ async function buildCodeGraphHtml(graph, projectRoot) {
36
+ const root = projectRoot || process.cwd();
37
+ await ensureVisNetworkLocal(root);
38
+ const idToNode = new Map(graph.nodes.map(n => [n.id, n]));
39
+ const godSet = new Set(graph.godNodes);
40
+ // ── 1. 连续色相调色板(30 社区各归其色,v8.3.358 修复 %10 同色)──
41
+ const orphanNodes = graph.nodes.filter(n => n.community === undefined);
42
+ const commCount = Math.max(graph.communities.length + (orphanNodes.length > 0 ? 1 : 0), 1);
43
+ const colorOf = (i) => `hsl(${(i * 360) / commCount + 15 % 360}, 65%, 55%)`;
44
+ // ── 2. 社区总览层:社区节点 + 桥接聚合边 ──
45
+ const communities = graph.communities.map((c, i) => {
46
+ const members = c.nodes
47
+ .map(id => idToNode.get(id))
48
+ .filter((n) => Boolean(n));
49
+ const godCount = c.nodes.filter(id => godSet.has(id)).length;
50
+ return {
51
+ id: c.id,
52
+ label: c.label,
53
+ memberCount: c.nodes.length,
54
+ godCount,
55
+ color: colorOf(i),
56
+ topMembers: members
57
+ .sort((a, b) => (b.degree || 0) - (a.degree || 0))
58
+ .slice(0, 5)
59
+ .map(n => n.name),
60
+ };
61
+ });
62
+ // 无社区节点(社区检测只聚类边连通节点,孤立节点 community 为 undefined)
63
+ // 归入「未分类」社区,保证成员层全量覆盖(v8.3.358)
64
+ if (orphanNodes.length > 0) {
65
+ communities.push({
66
+ id: -1,
67
+ label: '未分类',
68
+ memberCount: orphanNodes.length,
69
+ godCount: orphanNodes.filter(n => godSet.has(n.id)).length,
70
+ color: '#64748b',
71
+ topMembers: orphanNodes
72
+ .sort((a, b) => (b.degree || 0) - (a.degree || 0))
73
+ .slice(0, 5)
74
+ .map(n => n.name),
75
+ });
76
+ }
77
+ // 桥接聚合边:跨社区边按社区对合并(from/to 用社区 id,count 计边数)
78
+ // v8.3.358: community 为 undefined 的一端按「未分类(-1)」参与聚合
79
+ const commOf = (n) => n.community ?? -1;
80
+ const bridgeAgg = new Map();
81
+ for (const e of graph.edges) {
82
+ const s = idToNode.get(e.source);
83
+ const t = idToNode.get(e.target);
84
+ if (!s || !t)
85
+ continue;
86
+ const sc = commOf(s);
87
+ const tc = commOf(t);
88
+ if (sc === tc)
89
+ continue;
90
+ const key = sc < tc ? `${sc}-${tc}` : `${tc}-${sc}`;
91
+ const agg = bridgeAgg.get(key) || { from: Math.min(sc, tc), to: Math.max(sc, tc), count: 0, extracted: 0 };
92
+ agg.count++;
93
+ if (e.confidence === 'EXTRACTED')
94
+ agg.extracted++;
95
+ bridgeAgg.set(key, agg);
96
+ }
97
+ const bridgeEdges = [...bridgeAgg.values()].map(b => ({ ...b, type: b.extracted === b.count ? 'EXTRACTED' : 'MIXED' }));
98
+ // ── 3. 成员层:按社区分组节点与边(字段压缩)──
99
+ const nodeCommunity = new Map();
100
+ const members = {};
101
+ for (const n of graph.nodes) {
102
+ const c = commOf(n);
103
+ nodeCommunity.set(n.id, c);
104
+ const key = String(c);
105
+ if (!members[key])
106
+ members[key] = { nodes: [], internalEdges: [], crossEdges: [] };
107
+ members[key].nodes.push({
108
+ i: n.id,
109
+ l: n.name,
110
+ ty: n.type,
111
+ d: n.degree || 1,
112
+ f: n.filePath,
113
+ ln: n.line,
114
+ g: godSet.has(n.id),
115
+ });
116
+ }
117
+ for (const e of graph.edges) {
118
+ const s = idToNode.get(e.source);
119
+ const t = idToNode.get(e.target);
120
+ if (!s || !t)
121
+ continue;
122
+ const sc = commOf(s);
123
+ const tc = commOf(t);
124
+ const slim = { f: e.source, t: e.target, ty: e.type, c: e.confidence };
125
+ if (sc === tc) {
126
+ members[String(sc)]?.internalEdges.push(slim);
127
+ }
128
+ else {
129
+ // 跨边两端进各自社区的 crossEdges,target 改指向对方社区节点
130
+ members[String(sc)]?.crossEdges.push({ ...slim, t: `comm-${tc}` });
131
+ members[String(tc)]?.crossEdges.push({ ...slim, f: `comm-${sc}` });
132
+ }
133
+ }
134
+ // ── 4. 需求↔代码联动(v8.3.358+: REQ_CODE_LINK 侧栏数据)──
135
+ const reqLinks = [];
136
+ try {
137
+ const linkPath = (0, path_1.join)(root, '.speccore', 'code-graph', 'REQ_CODE_LINK.json');
138
+ if (await (0, fs_extra_1.pathExists)(linkPath)) {
139
+ const report = JSON.parse(await (0, fs_extra_1.readFile)(linkPath, 'utf-8'));
140
+ for (const l of (report.links || [])) {
141
+ if (l.linkedNodeIds && l.linkedNodeIds.length > 0) {
142
+ reqLinks.push({ req: l.requirement, nodeIds: l.linkedNodeIds });
143
+ }
144
+ }
145
+ }
146
+ }
147
+ catch { /* 联动数据缺失时侧栏为空 */ }
148
+ // 节点 → 需求 反向索引(详情面板用)
149
+ const nodeReqs = new Map();
150
+ for (const l of reqLinks) {
151
+ for (const id of l.nodeIds) {
152
+ const arr = nodeReqs.get(id) || [];
153
+ if (arr.length < 3)
154
+ arr.push(l.req);
155
+ nodeReqs.set(id, arr);
32
156
  }
33
157
  }
34
158
  const meta = graph.metadata;
159
+ // ── 5. HTML 渲染 ──
35
160
  return `<!DOCTYPE html>
36
161
  <html lang="zh-CN">
37
162
  <head>
38
163
  <meta charset="UTF-8">
39
164
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
40
165
  <title>${meta.projectName} — Code Graph</title>
41
- <script src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
166
+ <script src="vis-network.min.js"></script>
167
+ <script>
168
+ // v8.3.360+: 优先本地 UMD(离线可开),本地缺失时回退 unpkg CDN
169
+ // '<scr'+'ipt' 拆写避免解析器进入 double-escaped 状态,尾串转义为 '<\\/script>' 防闭合标签提前终止(注释也避字面序列)
170
+ if (!window.vis) document.write('<scr' + 'ipt src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"><\\/script>');
171
+ </script>
42
172
  <style>
43
173
  body{margin:0;font-family:'Segoe UI',system-ui,sans-serif;background:#0b1929;color:#bae6fd;overflow:hidden}
44
174
  #graph{position:fixed;inset:0}
45
- .panel{position:fixed;top:12px;left:12px;background:rgba(13,31,56,.95);border:1px solid rgba(14,165,233,.2);border-radius:10px;padding:14px;max-width:280px;z-index:10;font-size:12px}
175
+ .panel{position:fixed;top:12px;left:12px;background:rgba(13,31,56,.95);border:1px solid rgba(14,165,233,.2);border-radius:10px;padding:14px;max-width:260px;z-index:10;font-size:12px}
46
176
  .panel h2{margin:0 0 8px;font-size:14px;color:#0ea5e9}
47
177
  .panel .stat{display:flex;justify-content:space-between;padding:3px 0;border-bottom:1px solid rgba(255,255,255,.05)}
48
178
  .panel .stat span{color:#5b7fa5}
@@ -50,10 +180,24 @@ body{margin:0;font-family:'Segoe UI',system-ui,sans-serif;background:#0b1929;col
50
180
  .panel .legend-item{display:flex;align-items:center;gap:6px;margin:4px 0}
51
181
  .panel .dot{width:10px;height:10px;border-radius:50%}
52
182
  .panel .line{width:20px;height:2px}
183
+ .panel label{display:flex;align-items:center;gap:6px;margin-top:6px;cursor:pointer}
53
184
  .search{position:fixed;top:12px;right:12px;z-index:10;display:flex;gap:6px}
54
185
  .search input{background:rgba(13,31,56,.95);border:1px solid rgba(14,165,233,.2);border-radius:6px;padding:6px 10px;color:#bae6fd;font-size:12px;outline:none;width:180px}
55
186
  .search input::placeholder{color:#5b7fa5}
56
187
  .search button{background:#0ea5e9;border:none;border-radius:6px;padding:6px 12px;color:#fff;font-size:12px;cursor:pointer}
188
+ .breadcrumb{position:fixed;bottom:12px;left:12px;z-index:10;display:none}
189
+ .breadcrumb button{background:rgba(13,31,56,.95);border:1px solid rgba(14,165,233,.4);border-radius:6px;padding:6px 12px;color:#0ea5e9;font-size:12px;cursor:pointer}
190
+ .detail{position:fixed;top:48px;right:12px;z-index:10;background:rgba(13,31,56,.97);border:1px solid rgba(14,165,233,.3);border-radius:10px;padding:12px;max-width:300px;font-size:12px;display:none}
191
+ .detail h3{margin:0 0 6px;font-size:13px;color:#0ea5e9;word-break:break-all}
192
+ .detail div{margin:2px 0;color:#7dd3fc}
193
+ .detail .req{color:#fbbf24}
194
+ .reqpanel{position:fixed;bottom:12px;right:12px;z-index:10;background:rgba(13,31,56,.95);border:1px solid rgba(14,165,233,.3);border-radius:10px;padding:10px;max-width:320px;max-height:45vh;overflow:auto;font-size:12px;display:none}
195
+ .reqpanel h3{margin:0 0 6px;font-size:13px;color:#0ea5e9}
196
+ .reqpanel input{background:rgba(13,31,56,.95);border:1px solid rgba(14,165,233,.2);border-radius:4px;padding:4px 8px;color:#bae6fd;font-size:11px;width:100%;box-sizing:border-box;margin-bottom:6px}
197
+ .reqpanel .req-item{padding:3px 6px;border-radius:4px;cursor:pointer;color:#7dd3fc}
198
+ .reqpanel .req-item:hover{background:rgba(14,165,233,.15)}
199
+ .reqpanel .req-item b{color:#fbbf24}
200
+ .req-toggle{position:fixed;bottom:12px;right:12px;z-index:11;background:#0ea5e9;border:none;border-radius:6px;padding:6px 12px;color:#fff;font-size:12px;cursor:pointer}
57
201
  </style>
58
202
  </head>
59
203
  <body>
@@ -64,32 +208,315 @@ body{margin:0;font-family:'Segoe UI',system-ui,sans-serif;background:#0b1929;col
64
208
  <div class="stat">Nodes <span>${meta.totalNodes}</span></div>
65
209
  <div class="stat">Edges <span>${meta.totalEdges}</span></div>
66
210
  <div class="stat">Communities <span>${graph.communities.length}</span></div>
67
- <div class="stat">EXTRACTED <span>${meta.extractedEdges}</span></div>
68
- <div class="stat">INFERRED <span>${meta.inferredEdges}</span></div>
211
+ <div class="stat">需求联动 <span>${reqLinks.length}</span></div>
69
212
  <div class="legend">
70
- <div class="legend-item"><span class="dot" style="background:#0ea5e9"></span> EXTRACTED edge</div>
71
- <div class="legend-item"><span class="line" style="background:#94a3b8;border-top:2px dashed #94a3b8"></span> INFERRED edge</div>
72
- <div class="legend-item"><span class="dot" style="background:#f97316"></span> God node</div>
213
+ <div class="legend-item"><span class="dot" style="background:${colorOf(0)}"></span> 社区(双击钻入成员)</div>
214
+ <div class="legend-item"><span class="line" style="background:#0ea5e9"></span> EXTRACTED 边</div>
215
+ <div class="legend-item"><span class="line" style="background:#94a3b8;border-top:2px dashed #94a3b8"></span> INFERRED 边</div>
216
+ <div class="legend-item"><span class="line" style="background:#f59e0b"></span> MIXED 桥接边(总览层)</div>
217
+ <div class="legend-item"><span class="dot" style="background:#fff;border:2px solid #f97316"></span> God node / God 社区</div>
73
218
  </div>
219
+ <label><input type="checkbox" id="showExtracted" checked> EXTRACTED 边</label>
220
+ <label><input type="checkbox" id="showInferred"> INFERRED 边</label>
221
+ <label><input type="checkbox" id="showGod" checked> God 高亮</label>
74
222
  </div>
75
223
  <div class="search">
76
- <input type="text" id="searchInput" placeholder="Search node...">
77
- <button onclick="searchNode()">Find</button>
224
+ <input type="text" id="searchInput" placeholder="搜索节点 / 社区...">
225
+ <button onclick="doSearch()">Find</button>
226
+ </div>
227
+ <div class="detail" id="detail"></div>
228
+ <div class="breadcrumb" id="breadcrumb"><button onclick="exitCommunity()">← 返回社区总览</button></div>
229
+ <button class="req-toggle" onclick="toggleReqPanel()">📋 需求联动 (${reqLinks.length})</button>
230
+ <div class="reqpanel" id="reqpanel">
231
+ <h3>需求 ↔ 代码联动</h3>
232
+ <input type="text" id="reqFilter" placeholder="过滤需求..." oninput="renderReqList()">
233
+ <div id="reqList"></div>
78
234
  </div>
79
235
  <script>
80
- const nodes=new vis.DataSet(${JSON.stringify(nodes)});
81
- const edges=new vis.DataSet(${JSON.stringify(edges)});
82
- const container=document.getElementById('graph');
83
- const data={nodes,edges};
84
- const options={
85
- nodes:{shape:'dot',font:{color:'#bae6fd',size:12},borderWidth:1,borderWidthSelected:2},
86
- edges:{width:1,smooth:{type:'continuous'}},
87
- physics:{stabilization:false,barnesHut:{gravitationalConstant:-3000,springConstant:0.04,springLength:95}},
88
- interaction:{hover:true,tooltipDelay:200,hideEdgesOnDrag:true}
236
+ const LAYERS = {
237
+ communities: ${JSON.stringify(communities)},
238
+ bridgeEdges: ${JSON.stringify(bridgeEdges)},
239
+ members: ${JSON.stringify(members)},
240
+ reqLinks: ${JSON.stringify(reqLinks)},
241
+ nodeReqs: ${JSON.stringify([...nodeReqs])},
242
+ nodeCommunity: ${JSON.stringify([...nodeCommunity])},
89
243
  };
90
- const network=new vis.Network(container,data,options);
91
- function searchNode(){const v=document.getElementById('searchInput').value.toLowerCase();const found=nodes.get({filter:n=>n.label.toLowerCase().includes(v)})[0];if(found){network.focus(found.id,{scale:1.2,animation:true});network.selectNodes([found.id]);}}
92
- document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Enter')searchNode();});
244
+
245
+ const commNodes = new vis.DataSet(LAYERS.communities.map(c => ({
246
+ id: 'comm-' + c.id,
247
+ label: c.label,
248
+ group: 'comm',
249
+ title: '<b>' + c.label + '</b><br>成员: ' + c.memberCount + '<br>God nodes: ' + c.godCount + '<br>代表: ' + c.topMembers.slice(0,3).join(', '),
250
+ value: Math.max(8, Math.min(40, Math.sqrt(c.memberCount) * 1.2)),
251
+ // v8.3.360+: vis-network 绘制边框读 color.border(顶层 borderColor 被忽略),God 社区橙边星标须走 color 对象
252
+ color: c.godCount > 0 ? { background: c.color, border: '#f97316' } : c.color,
253
+ shape: 'box',
254
+ font: { color: '#e0f2fe', size: 14 },
255
+ borderWidth: c.godCount > 0 ? 2 : 1,
256
+ })));
257
+ const allEdges = LAYERS.bridgeEdges.map(b => ({
258
+ id: 'be-' + b.from + '-' + b.to,
259
+ from: 'comm-' + b.from,
260
+ to: 'comm-' + b.to,
261
+ title: '跨社区边: ' + b.count + ' 条',
262
+ label: String(b.count),
263
+ width: Math.max(1, Math.min(6, b.count / 15)),
264
+ color: b.type === 'EXTRACTED' ? { color: '#0ea5e9', opacity: 0.7 } : { color: '#f59e0b', opacity: 0.7 },
265
+ arrows: { to: { enabled: true, scaleFactor: 0.6 } },
266
+ // 初始态与开关一致:EXTRACTED 显示(默认勾选),MIXED 隐藏(showInferred 默认未勾选)
267
+ hidden: b.type === 'MIXED',
268
+ }));
269
+
270
+ const nodes = new vis.DataSet(commNodes.get());
271
+ const edges = new vis.DataSet(allEdges);
272
+ const container = document.getElementById('graph');
273
+ const network = new vis.Network(container, { nodes, edges }, {
274
+ nodes: { shape: 'dot', font: { color: '#bae6fd', size: 12 }, borderWidth: 1, borderWidthSelected: 2 },
275
+ edges: { width: 1, smooth: { type: 'continuous' }, font: { color: '#7dd3fc', size: 10 } },
276
+ physics: {
277
+ barnesHut: { gravitationalConstant: -6000, springConstant: 0.04, springLength: 130, avoidOverlap: 0.6 },
278
+ // v8.3.358+: 限定稳定化迭代次数,完成后关闭物理引擎(否则节点永远漂移)
279
+ stabilization: { iterations: 250, updateInterval: 25 },
280
+ },
281
+ interaction: { hover: true, tooltipDelay: 150, hideEdgesOnDrag: true },
282
+ });
283
+ // stabilize 完成回调统一管理(初始 250 迭代 + 钻入局部布局共用),避免连续钻入时监听堆积
284
+ let stabilizeDone = null;
285
+ function bindStabilizeDone(fn) {
286
+ if (stabilizeDone) network.off('stabilizationIterationsDone', stabilizeDone);
287
+ stabilizeDone = fn;
288
+ network.once('stabilizationIterationsDone', fn);
289
+ }
290
+ bindStabilizeDone(function () {
291
+ network.setOptions({ physics: { enabled: false } });
292
+ });
293
+
294
+ let activeComm = null;
295
+
296
+ // —— 双层视图:社区总览 → 双击钻入成员层 ——
297
+ network.on('doubleClick', function (params) {
298
+ if (params.nodes.length === 0) return;
299
+ const id = params.nodes[0];
300
+ if (id.startsWith('comm-')) enterCommunity(id);
301
+ });
302
+
303
+ // —— 点击:社区→更新详情,成员→详情面板 ——
304
+ network.on('click', function (params) {
305
+ if (params.nodes.length === 0) { hideDetail(); return; }
306
+ const id = params.nodes[0];
307
+ if (id.startsWith('comm-')) { showCommDetail(id); return; }
308
+ showNodeDetail(id);
309
+ });
310
+
311
+ function enterCommunity(commId) {
312
+ if (activeComm) exitCommunity(true);
313
+ const cid = commId.replace('comm-', '');
314
+ const layer = LAYERS.members[cid];
315
+ if (!layer || layer.nodes.length === 0) return;
316
+ activeComm = commId;
317
+ const pos = network.getPosition(commId);
318
+ const baseColor = LAYERS.communities.find(c => 'comm-' + c.id === commId)?.color || '#94a3b8';
319
+ const add = layer.nodes.map(n => {
320
+ const nd = {
321
+ id: n.i,
322
+ label: n.l,
323
+ title: n.l + ' (' + n.ty + ')\\n' + n.f + ':' + n.ln + '\\ndegree: ' + n.d,
324
+ value: Math.max(3, Math.min(18, Math.sqrt(n.d) * 1.5)),
325
+ // God node 橙边星标(vis-network 读 color.border,顶层 borderColor 无效)
326
+ color: n.g ? { background: baseColor, border: '#f97316' } : baseColor,
327
+ x: pos.x + (Math.random() - 0.5) * 300,
328
+ y: pos.y + (Math.random() - 0.5) * 300,
329
+ font: { color: '#bae6fd', size: n.g ? 14 : 10 },
330
+ borderWidth: n.g ? 2 : 1,
331
+ };
332
+ return nd;
333
+ });
334
+ const existingIds = new Set(nodes.getIds());
335
+ const fresh = add.filter(n => !existingIds.has(n.id));
336
+ const shown = add.filter(n => existingIds.has(n.id));
337
+ nodes.add(fresh);
338
+ if (shown.length) nodes.update(shown.map(n => ({ id: n.id, hidden: false })));
339
+ const inner = layer.internalEdges.map((e, i) => ({
340
+ id: 'ie-' + cid + '-' + i, from: e.f, to: e.t, title: e.ty + ' (' + e.c + ')',
341
+ dashes: e.c === 'INFERRED', color: e.c === 'EXTRACTED' ? { color: '#0ea5e9', opacity: 0.5 } : { color: '#94a3b8', opacity: 0.3 },
342
+ hidden: !edgeVisible(e.c),
343
+ }));
344
+ const cross = layer.crossEdges.map((e, i) => ({
345
+ id: 'ce-' + cid + '-' + i, from: e.f, to: e.t, title: e.ty + ' (' + e.c + ') → 跨社区',
346
+ dashes: e.c === 'INFERRED', color: { color: '#f59e0b', opacity: 0.55 },
347
+ hidden: !edgeVisible(e.c),
348
+ }));
349
+ const existingEdgeIds = new Set(edges.getIds());
350
+ const freshEdges = [...inner, ...cross].filter(e => !existingEdgeIds.has(e.id));
351
+ const shownEdges = [...inner, ...cross].filter(e => existingEdgeIds.has(e.id));
352
+ edges.add(freshEdges);
353
+ if (shownEdges.length) edges.update(shownEdges.map(e => ({ id: e.id, hidden: e.hidden })));
354
+ document.getElementById('breadcrumb').style.display = 'block';
355
+ network.focus(commId, { scale: 1.1, animation: true });
356
+ // v8.3.360+: 钻入后局部布局一轮(固定社区节点,仅新成员参与 stabilize,避免成员随机散布重叠)
357
+ stabilizeMembers(commId, layer.nodes.map(n => n.i));
358
+ }
359
+
360
+ function stabilizeMembers(commId, newIds) {
361
+ const existing = nodes.getIds().filter(id => !newIds.includes(id));
362
+ nodes.update(existing.map(id => ({ id, fixed: { x: true, y: true } })));
363
+ network.setOptions({
364
+ physics: {
365
+ enabled: true,
366
+ barnesHut: { gravitationalConstant: -6000, springConstant: 0.04, springLength: 130, avoidOverlap: 0.6 },
367
+ stabilization: { enabled: true, iterations: 150, fit: false },
368
+ },
369
+ });
370
+ bindStabilizeDone(function () {
371
+ network.setOptions({ physics: { enabled: false } });
372
+ nodes.update(existing.map(id => ({ id, fixed: { x: false, y: false } })));
373
+ nodes.update(newIds.map(id => ({ id, fixed: { x: false, y: false } })));
374
+ network.focus(commId, { scale: 1.1, animation: true });
375
+ });
376
+ }
377
+
378
+ function exitCommunity(silent) {
379
+ if (!activeComm) return;
380
+ const cid = activeComm.replace('comm-', '');
381
+ const layer = LAYERS.members[cid];
382
+ if (layer) {
383
+ // v8.3.360+: 不 remove 而是 hidden——remove 成员节点会触发 vis-network 10.x 节点层渲染损坏
384
+ // (退出后社区方块颜色丢失),hidden 保留数据与样式,重新钻入时 update 恢复即可
385
+ nodes.update(layer.nodes.map(n => ({ id: n.i, hidden: true })));
386
+ const ids = layer.internalEdges.map((e, i) => 'ie-' + cid + '-' + i).concat(layer.crossEdges.map((e, i) => 'ce-' + cid + '-' + i));
387
+ edges.update(ids.map(id => ({ id, hidden: true })));
388
+ }
389
+ activeComm = null;
390
+ document.getElementById('breadcrumb').style.display = 'none';
391
+ hideDetail();
392
+ // v8.3.360+: 终止挂起的局部 stabilize(成员已隐藏,残留完成回调的 focus 会造成视角跳动)
393
+ if (stabilizeDone) { network.off('stabilizationIterationsDone', stabilizeDone); stabilizeDone = null; }
394
+ // 解除 fixed 残留并关闭物理
395
+ network.setOptions({ physics: { enabled: false } });
396
+ nodes.update(nodes.getIds().map(id => ({ id, fixed: { x: false, y: false } })));
397
+ if (!silent) network.fit();
398
+ }
399
+
400
+ function edgeVisible(conf) {
401
+ if (conf === 'EXTRACTED') return document.getElementById('showExtracted').checked;
402
+ return document.getElementById('showInferred').checked;
403
+ }
404
+
405
+ // —— 边/God 开关 ——
406
+ document.getElementById('showExtracted').addEventListener('change', refreshEdges);
407
+ document.getElementById('showInferred').addEventListener('change', refreshEdges);
408
+ document.getElementById('showGod').addEventListener('change', function () {
409
+ const on = this.checked;
410
+ // 总览层:God 社区橙边星标(color.border 驱动)
411
+ for (const c of LAYERS.communities) {
412
+ nodes.update({ id: 'comm-' + c.id, color: (c.godCount > 0 && on) ? { background: c.color, border: '#f97316' } : c.color, borderWidth: (c.godCount > 0 && on) ? 2 : 1 });
413
+ }
414
+ // 成员层:God node 高亮
415
+ if (!activeComm) return;
416
+ const cid = activeComm.replace('comm-', '');
417
+ const layer = LAYERS.members[cid];
418
+ if (!layer) return;
419
+ const base = LAYERS.communities.find(c => 'comm-' + c.id === cid)?.color || '#94a3b8';
420
+ for (const n of layer.nodes) {
421
+ nodes.update({ id: n.i, font: { color: '#bae6fd', size: (n.g && on) ? 14 : 10 }, color: (n.g && on) ? { background: base, border: '#f97316' } : base, borderWidth: (n.g && on) ? 2 : 1 });
422
+ }
423
+ });
424
+ function refreshEdges() {
425
+ if (!activeComm) {
426
+ // 总览层:桥接边按类型过滤(EXTRACTED ↔ showExtracted,MIXED ↔ showInferred)
427
+ for (const b of LAYERS.bridgeEdges) {
428
+ const on = b.type === 'EXTRACTED' ? document.getElementById('showExtracted').checked : document.getElementById('showInferred').checked;
429
+ edges.update({ id: 'be-' + b.from + '-' + b.to, hidden: !on });
430
+ }
431
+ return;
432
+ }
433
+ const cid = activeComm.replace('comm-', '');
434
+ const layer = LAYERS.members[cid];
435
+ if (!layer) return;
436
+ layer.internalEdges.forEach((e, i) => edges.update({ id: 'ie-' + cid + '-' + i, hidden: !edgeVisible(e.c) }));
437
+ layer.crossEdges.forEach((e, i) => edges.update({ id: 'ce-' + cid + '-' + i, hidden: !edgeVisible(e.c) }));
438
+ }
439
+
440
+ // —— 详情面板 ——
441
+ function showCommDetail(commId) {
442
+ const c = LAYERS.communities.find(x => 'comm-' + x.id === commId);
443
+ if (!c) return;
444
+ const el = document.getElementById('detail');
445
+ el.style.display = 'block';
446
+ el.innerHTML = '<h3>' + c.label + '</h3><div>成员节点: ' + c.memberCount + '</div><div>God nodes: ' + c.godCount + '</div><div>代表: ' + c.topMembers.join(', ') + '</div><div class="req">双击钻入成员层</div>';
447
+ }
448
+ function showNodeDetail(id) {
449
+ const nc = LAYERS.nodeCommunity.find(x => x[0] === id);
450
+ const commId = nc ? nc[1] : null;
451
+ const layer = commId !== null && commId !== undefined ? LAYERS.members[String(commId)] : null;
452
+ const node = layer ? layer.nodes.find(n => n.i === id) : null;
453
+ const el = document.getElementById('detail');
454
+ el.style.display = 'block';
455
+ const reqs = (LAYERS.nodeReqs.find(x => x[0] === id) || [])[1] || [];
456
+ if (node) {
457
+ el.innerHTML = '<h3>' + node.l + '</h3><div>类型: ' + node.ty + '</div><div>位置: ' + node.f + ':' + node.ln + '</div><div>度: ' + node.d + '</div>' + (node.g ? '<div class="req">⭐ God node</div>' : '') + (reqs.length ? '<div class="req">关联需求: ' + reqs.join('; ') + '</div>' : '');
458
+ } else {
459
+ el.innerHTML = '<h3>' + id + '</h3>';
460
+ }
461
+ }
462
+ function hideDetail() { document.getElementById('detail').style.display = 'none'; }
463
+
464
+ // —— 搜索:当前层成员 → 社区标签 → 未展开社区成员(自动钻入)——
465
+ function doSearch() {
466
+ const v = document.getElementById('searchInput').value.trim().toLowerCase();
467
+ if (!v) return;
468
+ // 1) 当前展开社区的成员
469
+ if (activeComm) {
470
+ const cid = activeComm.replace('comm-', '');
471
+ const layer = LAYERS.members[cid];
472
+ const hit = layer && layer.nodes.find(n => n.l.toLowerCase().includes(v));
473
+ if (hit) { selectNode(hit.i); return; }
474
+ }
475
+ // 2) 社区标签
476
+ const chit = LAYERS.communities.find(c => c.label.toLowerCase().includes(v));
477
+ if (chit) { network.focus('comm-' + chit.id, { scale: 1.2, animation: true }); network.selectNodes(['comm-' + chit.id]); return; }
478
+ // 3) 全量成员(自动钻入所在社区)
479
+ for (const cid of Object.keys(LAYERS.members)) {
480
+ const hit = LAYERS.members[cid].nodes.find(n => n.l.toLowerCase().includes(v));
481
+ if (hit) { enterCommunity('comm-' + cid); selectNode(hit.i); return; }
482
+ }
483
+ }
484
+ function selectNode(id) {
485
+ network.selectNodes([id]);
486
+ network.focus(id, { scale: 1.2, animation: true });
487
+ showNodeDetail(id);
488
+ }
489
+ document.getElementById('searchInput').addEventListener('keydown', e => { if (e.key === 'Enter') doSearch(); });
490
+
491
+ // —— 需求侧栏 ——
492
+ let reqPanelOpen = false;
493
+ function toggleReqPanel() {
494
+ reqPanelOpen = !reqPanelOpen;
495
+ document.getElementById('reqpanel').style.display = reqPanelOpen ? 'block' : 'none';
496
+ if (reqPanelOpen) renderReqList();
497
+ }
498
+ function renderReqList() {
499
+ const f = document.getElementById('reqFilter').value.trim().toLowerCase();
500
+ const list = LAYERS.reqLinks.filter(r => !f || r.req.toLowerCase().includes(f));
501
+ const el = document.getElementById('reqList');
502
+ el.innerHTML = list.slice(0, 100).map((r, idx) => {
503
+ const original = LAYERS.reqLinks.findIndex(x => x === r);
504
+ return '<div class="req-item" onclick="focusReq(' + original + ')"><b>' + (original + 1) + '.</b> ' + r.req + ' <span style="color:#5b7fa5">(' + r.nodeIds.length + ')</span></div>';
505
+ }).join('') || '<div style="color:#5b7fa5">无匹配需求</div>';
506
+ }
507
+ function focusReq(idx) {
508
+ const r = LAYERS.reqLinks[idx];
509
+ if (!r || r.nodeIds.length === 0) return;
510
+ const target = r.nodeIds[0];
511
+ const nc = LAYERS.nodeCommunity.find(x => x[0] === target);
512
+ if (nc) {
513
+ enterCommunity('comm-' + nc[1]);
514
+ selectNode(target);
515
+ // 高亮该需求的全部关联节点
516
+ const sel = r.nodeIds.filter(id => nodes.get(id));
517
+ network.selectNodes(sel);
518
+ }
519
+ }
93
520
  </script>
94
521
  </body>
95
522
  </html>`;
@@ -1 +1 @@
1
- {"version":3,"file":"visualizer.js","sourceRoot":"","sources":["../../../src/core/code-graph/visualizer.ts"],"names":[],"mappings":";;AAQA,gDAiGC;AAjGD,SAAgB,kBAAkB,CAAC,KAAgB;IACjD,MAAM,OAAO,GAAG;QACd,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;QAC1C,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;QAC1C,SAAS,EAAE,SAAS;KACrB,CAAC;IAEF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClC,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC,IAAI;QACb,KAAK,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC;QACxB,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,iBAAiB,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,QAAQ,aAAa,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,MAAM,EAAE;QAC7G,KAAK,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC;QACpB,KAAK,EAAE,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;KACrF,CAAC,CAAC,CAAC;IAEJ,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACvC,IAAI,EAAE,CAAC,CAAC,MAAM;QACd,EAAE,EAAE,CAAC,CAAC,MAAM;QACZ,KAAK,EAAE,CAAC,CAAC,IAAI;QACb,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,GAAG;QACpC,MAAM,EAAE,CAAC,CAAC,UAAU,KAAK,UAAU;QACnC,KAAK,EAAE,CAAC,CAAC,UAAU,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE;QAC7G,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE;KACpD,CAAC,CAAC,CAAC;IAEJ,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC3C,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAC5B,CAAS,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC;IAE5B,OAAO;;;;;SAKA,IAAI,CAAC,WAAW;;;;;;;;;;;;;;;;;;;;;;MAsBnB,IAAI,CAAC,WAAW;gCACU,IAAI,CAAC,YAAY;gCACjB,IAAI,CAAC,UAAU;gCACf,IAAI,CAAC,UAAU;sCACT,KAAK,CAAC,WAAW,CAAC,MAAM;oCAC1B,IAAI,CAAC,cAAc;mCACpB,IAAI,CAAC,aAAa;;;;;;;;;;;;8BAYvB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;8BACrB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;;;;;;;;;;;;;;QAc3C,CAAC;AACT,CAAC"}
1
+ {"version":3,"file":"visualizer.js","sourceRoot":"","sources":["../../../src/core/code-graph/visualizer.ts"],"names":[],"mappings":";;AAiCA,gDA2eC;AA5gBD;;;;;;;GAOG;AACH,uCAA2D;AAC3D,+BAA4B;AAO5B;;;GAGG;AACH,KAAK,UAAU,qBAAqB,CAAC,IAAY;IAC/C,MAAM,OAAO,GAAG,IAAA,WAAI,EAAC,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,oBAAoB,CAAC,CAAC;IAC5E,IAAI,MAAM,IAAA,qBAAU,EAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,iEAAiE,EAAE;YACzF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,IAAA,oBAAS,EAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC,CAAC,gBAAgB;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;AAC5C,CAAC;AAEM,KAAK,UAAU,kBAAkB,CAAC,KAAgB,EAAE,WAAoB;IAC7E,MAAM,IAAI,GAAG,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1C,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEvC,gDAAgD;IAChD,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3F,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,GAAG,EAAE,GAAG,GAAG,aAAa,CAAC;IAEpF,8BAA8B;IAC9B,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK;aACpB,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;aAC3B,MAAM,CAAC,CAAC,CAAC,EAAiB,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QAC7D,OAAO;YACL,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM;YAC3B,QAAQ;YACR,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;YACjB,UAAU,EAAE,OAAO;iBAChB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;iBACjD,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;iBACX,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACpB,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,iDAAiD;IACjD,gCAAgC;IAChC,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,WAAW,CAAC,IAAI,CAAC;YACf,EAAE,EAAE,CAAC,CAAC;YACN,KAAK,EAAE,KAAK;YACZ,WAAW,EAAE,WAAW,CAAC,MAAM;YAC/B,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM;YAC1D,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,WAAW;iBACpB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;iBACjD,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;iBACX,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACpB,CAAC,CAAC;IACL,CAAC;IAED,6CAA6C;IAC7C,oDAAoD;IACpD,MAAM,MAAM,GAAG,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,GAAG,EAA0E,CAAC;IACpG,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;YAAE,SAAS;QACvB,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,EAAE,KAAK,EAAE;YAAE,SAAS;QACxB,MAAM,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;QAC3G,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,IAAI,CAAC,CAAC,UAAU,KAAK,WAAW;YAAE,GAAG,CAAC,SAAS,EAAE,CAAC;QAClD,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC1B,CAAC;IACD,MAAM,WAAW,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAExH,8BAA8B;IAC9B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,MAAM,OAAO,GAIR,EAAE,CAAC;IACR,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC3B,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QACnF,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;YACtB,CAAC,EAAE,CAAC,CAAC,EAAE;YACP,CAAC,EAAE,CAAC,CAAC,IAAI;YACT,EAAE,EAAE,CAAC,CAAC,IAAI;YACV,CAAC,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC;YAChB,CAAC,EAAE,CAAC,CAAC,QAAQ;YACb,EAAE,EAAE,CAAC,CAAC,IAAI;YACV,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;SACpB,CAAC,CAAC;IACL,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;YAAE,SAAS;QACvB,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,IAAI,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,UAAsB,EAAE,CAAC;QACnF,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,yCAAyC;YACzC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;YACnE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,MAAM,QAAQ,GAAyC,EAAE,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,oBAAoB,CAAC,CAAC;QAC7E,IAAI,MAAM,IAAA,qBAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,IAAA,mBAAQ,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;YAC7D,KAAK,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAkB,EAAE,CAAC;gBACtD,IAAI,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAClD,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC7B,sBAAsB;IACtB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC;IAE5B,mBAAmB;IACnB,OAAO;;;;;SAKA,IAAI,CAAC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAyCnB,IAAI,CAAC,WAAW;gCACU,IAAI,CAAC,YAAY;gCACjB,IAAI,CAAC,UAAU;gCACf,IAAI,CAAC,UAAU;sCACT,KAAK,CAAC,WAAW,CAAC,MAAM;+BAC/B,QAAQ,CAAC,MAAM;;+DAEiB,OAAO,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;iEAgBR,QAAQ,CAAC,MAAM;;;;;;;;iBAQ/D,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;iBAC3B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;aAC/B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;cACtB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;cACxB,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;mBACxB,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAwR7C,CAAC;AACT,CAAC"}
@@ -111,6 +111,8 @@ export declare function checkCodeIndexFreshness(scope?: string[]): Promise<{
111
111
  staleFiles: string[];
112
112
  message: string;
113
113
  }>;
114
+ export declare function expandKeywords(keywords: string[]): string[];
115
+ export declare function extractKeywords(text: string): string[];
114
116
  /**
115
117
  * v8.3.3xx+: 消费前兜底——索引缺失/过期时自动重建,并输出无索引告警
116
118
  *
@@ -1 +1 @@
1
- {"version":3,"file":"code-scanner.d.ts","sourceRoot":"","sources":["../../src/core/code-scanner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"code-scanner.d.ts","sourceRoot":"","sources":["../../src/core/code-scanner.ts"],"names":[],"mappings":"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"}