claude-code-workflow 6.1.4 → 6.2.2

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 (437) hide show
  1. package/.claude/CLAUDE.md +10 -0
  2. package/.claude/agents/action-planning-agent.md +857 -778
  3. package/.claude/agents/cli-execution-agent.md +266 -269
  4. package/.claude/agents/cli-explore-agent.md +2 -2
  5. package/.claude/agents/cli-lite-planning-agent.md +142 -92
  6. package/.claude/agents/cli-planning-agent.md +4 -4
  7. package/.claude/agents/code-developer.md +7 -6
  8. package/.claude/agents/conceptual-planning-agent.md +2 -2
  9. package/.claude/agents/context-search-agent.md +31 -32
  10. package/.claude/agents/doc-generator.md +4 -4
  11. package/.claude/agents/memory-bridge.md +93 -93
  12. package/.claude/agents/test-context-search-agent.md +8 -7
  13. package/.claude/agents/test-fix-agent.md +7 -6
  14. package/.claude/commands/clean.md +516 -0
  15. package/.claude/commands/memory/compact.md +383 -0
  16. package/.claude/commands/memory/docs-full-cli.md +471 -471
  17. package/.claude/commands/memory/docs-related-cli.md +386 -386
  18. package/.claude/commands/memory/docs.md +615 -615
  19. package/.claude/commands/memory/load.md +5 -5
  20. package/.claude/commands/memory/tech-research-rules.md +310 -0
  21. package/.claude/commands/memory/update-full.md +332 -332
  22. package/.claude/commands/memory/workflow-skill-memory.md +4 -4
  23. package/.claude/commands/task/create.md +151 -151
  24. package/.claude/commands/version.md +254 -254
  25. package/.claude/commands/workflow/brainstorm/api-designer.md +587 -585
  26. package/.claude/commands/workflow/brainstorm/artifacts.md +1 -0
  27. package/.claude/commands/workflow/brainstorm/auto-parallel.md +443 -443
  28. package/.claude/commands/workflow/brainstorm/data-architect.md +220 -220
  29. package/.claude/commands/workflow/brainstorm/product-manager.md +200 -200
  30. package/.claude/commands/workflow/brainstorm/product-owner.md +200 -200
  31. package/.claude/commands/workflow/brainstorm/scrum-master.md +200 -200
  32. package/.claude/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
  33. package/.claude/commands/workflow/brainstorm/system-architect.md +389 -387
  34. package/.claude/commands/workflow/brainstorm/ui-designer.md +221 -221
  35. package/.claude/commands/workflow/brainstorm/ux-expert.md +221 -221
  36. package/.claude/commands/workflow/debug.md +321 -0
  37. package/.claude/commands/workflow/execute.md +13 -0
  38. package/.claude/commands/workflow/init.md +165 -164
  39. package/.claude/commands/workflow/lite-execute.md +119 -13
  40. package/.claude/commands/workflow/lite-fix.md +623 -621
  41. package/.claude/commands/workflow/lite-plan.md +610 -592
  42. package/.claude/commands/workflow/plan.md +5 -5
  43. package/.claude/commands/workflow/review-module-cycle.md +2 -0
  44. package/.claude/commands/workflow/review-session-cycle.md +2 -0
  45. package/.claude/commands/workflow/review.md +297 -291
  46. package/.claude/commands/workflow/session/complete.md +153 -500
  47. package/.claude/commands/workflow/session/list.md +95 -95
  48. package/.claude/commands/workflow/session/resume.md +60 -60
  49. package/.claude/commands/workflow/session/start.md +199 -199
  50. package/.claude/commands/workflow/tdd-plan.md +3 -3
  51. package/.claude/commands/workflow/tdd-verify.md +23 -9
  52. package/.claude/commands/workflow/test-cycle-execute.md +2 -0
  53. package/.claude/commands/workflow/test-fix-gen.md +699 -699
  54. package/.claude/commands/workflow/tools/conflict-resolution.md +104 -18
  55. package/.claude/commands/workflow/tools/context-gather.md +436 -434
  56. package/.claude/commands/workflow/tools/task-generate-agent.md +490 -291
  57. package/.claude/commands/workflow/tools/task-generate-tdd.md +18 -10
  58. package/.claude/commands/workflow/tools/test-concept-enhanced.md +2 -1
  59. package/.claude/commands/workflow/tools/test-context-gather.md +1 -0
  60. package/.claude/commands/workflow/tools/test-task-generate.md +1 -0
  61. package/.claude/commands/workflow/ui-design/import-from-code.md +9 -6
  62. package/.claude/skills/command-guide/SKILL.md +5 -5
  63. package/.claude/skills/command-guide/index/all-commands.json +1 -1
  64. package/.claude/skills/command-guide/index/by-category.json +1 -1
  65. package/.claude/skills/command-guide/index/by-use-case.json +1 -1
  66. package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +857 -778
  67. package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +266 -269
  68. package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +2 -2
  69. package/.claude/skills/command-guide/reference/agents/cli-lite-planning-agent.md +142 -92
  70. package/.claude/skills/command-guide/reference/agents/cli-planning-agent.md +4 -4
  71. package/.claude/skills/command-guide/reference/agents/code-developer.md +7 -6
  72. package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +2 -2
  73. package/.claude/skills/command-guide/reference/agents/context-search-agent.md +31 -32
  74. package/.claude/skills/command-guide/reference/agents/doc-generator.md +4 -4
  75. package/.claude/skills/command-guide/reference/agents/memory-bridge.md +93 -93
  76. package/.claude/skills/command-guide/reference/agents/test-context-search-agent.md +8 -7
  77. package/.claude/skills/command-guide/reference/agents/test-fix-agent.md +7 -6
  78. package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +471 -471
  79. package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +386 -386
  80. package/.claude/skills/command-guide/reference/commands/memory/docs.md +17 -16
  81. package/.claude/skills/command-guide/reference/commands/memory/load.md +5 -5
  82. package/.claude/skills/command-guide/reference/commands/memory/tech-research.md +194 -357
  83. package/.claude/skills/command-guide/reference/commands/memory/update-full.md +332 -332
  84. package/.claude/skills/command-guide/reference/commands/memory/workflow-skill-memory.md +4 -4
  85. package/.claude/skills/command-guide/reference/commands/task/create.md +151 -151
  86. package/.claude/skills/command-guide/reference/commands/version.md +254 -254
  87. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/api-designer.md +585 -585
  88. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +443 -443
  89. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/data-architect.md +220 -220
  90. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-manager.md +200 -200
  91. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-owner.md +200 -200
  92. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/scrum-master.md +200 -200
  93. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
  94. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/system-architect.md +387 -387
  95. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ui-designer.md +221 -221
  96. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ux-expert.md +221 -221
  97. package/.claude/skills/command-guide/reference/commands/workflow/execute.md +25 -20
  98. package/.claude/skills/command-guide/reference/commands/workflow/init.md +164 -164
  99. package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +748 -686
  100. package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +664 -621
  101. package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +645 -592
  102. package/.claude/skills/command-guide/reference/commands/workflow/plan.md +5 -5
  103. package/.claude/skills/command-guide/reference/commands/workflow/review.md +25 -18
  104. package/.claude/skills/command-guide/reference/commands/workflow/session/complete.md +547 -500
  105. package/.claude/skills/command-guide/reference/commands/workflow/session/list.md +45 -27
  106. package/.claude/skills/command-guide/reference/commands/workflow/session/resume.md +35 -19
  107. package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +90 -33
  108. package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +3 -3
  109. package/.claude/skills/command-guide/reference/commands/workflow/tdd-verify.md +23 -9
  110. package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +699 -699
  111. package/.claude/skills/command-guide/reference/commands/workflow/tools/conflict-resolution.md +103 -17
  112. package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +434 -434
  113. package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +487 -291
  114. package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +17 -10
  115. package/.claude/skills/command-guide/reference/commands/workflow/tools/test-concept-enhanced.md +1 -1
  116. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +6 -6
  117. package/.claude/workflows/chinese-response.md +38 -0
  118. package/.claude/workflows/cli-templates/prompts/rules/rule-api.txt +122 -0
  119. package/.claude/workflows/cli-templates/prompts/rules/rule-components.txt +122 -0
  120. package/.claude/workflows/cli-templates/prompts/rules/rule-config.txt +89 -0
  121. package/.claude/workflows/cli-templates/prompts/rules/rule-core.txt +60 -0
  122. package/.claude/workflows/cli-templates/prompts/rules/rule-patterns.txt +70 -0
  123. package/.claude/workflows/cli-templates/prompts/rules/rule-testing.txt +81 -0
  124. package/.claude/workflows/cli-templates/prompts/rules/tech-rules-agent-prompt.txt +89 -0
  125. package/.claude/workflows/cli-templates/prompts/workflow/gemini-solution-design.txt +131 -131
  126. package/.claude/workflows/cli-templates/prompts/workflow/skill-conflict-patterns.txt +5 -9
  127. package/.claude/workflows/cli-templates/prompts/workflow/skill-lessons-learned.txt +5 -9
  128. package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +112 -0
  129. package/.claude/workflows/cli-templates/protocols/write-protocol.md +201 -0
  130. package/.claude/workflows/cli-templates/schemas/conflict-resolution-schema.json +137 -0
  131. package/.claude/workflows/cli-templates/schemas/debug-log-json-schema.json +127 -0
  132. package/.claude/workflows/cli-templates/schemas/fix-plan-json-schema.json +25 -0
  133. package/.claude/workflows/cli-templates/schemas/plan-json-schema.json +25 -0
  134. package/.claude/workflows/cli-tools-usage.md +526 -0
  135. package/{CLAUDE.md → .claude/workflows/coding-philosophy.md} +24 -45
  136. package/.claude/workflows/context-tools.md +84 -0
  137. package/.claude/workflows/file-modification.md +64 -0
  138. package/.claude/workflows/tool-strategy.md +216 -79
  139. package/.claude/workflows/windows-platform.md +16 -0
  140. package/.claude/workflows/workflow-architecture.md +942 -942
  141. package/.codex/AGENTS.md +63 -330
  142. package/.codex/prompts/debug.md +318 -0
  143. package/.codex/prompts/execute.md +273 -0
  144. package/.codex/prompts/lite-execute.md +164 -0
  145. package/.codex/prompts/lite-plan.md +469 -0
  146. package/.codex/prompts.zip +0 -0
  147. package/.gemini/GEMINI.md +25 -164
  148. package/.qwen/QWEN.md +0 -139
  149. package/README.md +29 -9
  150. package/ccw/README.md +30 -6
  151. package/ccw/bin/ccw-mcp.js +7 -0
  152. package/ccw/bin/ccw.js +9 -9
  153. package/ccw/package.json +65 -47
  154. package/ccw/src/.workflow/.cli-history/history.db +0 -0
  155. package/ccw/src/.workflow/.cli-history/history.db-shm +0 -0
  156. package/ccw/src/.workflow/.cli-history/history.db-wal +0 -0
  157. package/ccw/src/cli.ts +244 -0
  158. package/ccw/src/commands/cli.ts +740 -0
  159. package/ccw/src/commands/core-memory.ts +770 -0
  160. package/ccw/src/commands/hook.ts +315 -0
  161. package/ccw/src/commands/install.ts +519 -0
  162. package/ccw/src/commands/{list.js → list.ts} +1 -1
  163. package/ccw/src/commands/memory.ts +1090 -0
  164. package/ccw/src/commands/{serve.js → serve.ts} +14 -5
  165. package/ccw/src/commands/session-path-resolver.ts +372 -0
  166. package/ccw/src/commands/session.ts +1141 -0
  167. package/ccw/src/commands/{stop.js → stop.ts} +16 -6
  168. package/ccw/src/commands/tool.ts +201 -0
  169. package/ccw/src/commands/{uninstall.js → uninstall.ts} +89 -40
  170. package/ccw/src/commands/{upgrade.js → upgrade.ts} +68 -23
  171. package/ccw/src/commands/{view.js → view.ts} +22 -8
  172. package/ccw/src/config/storage-paths.ts +670 -0
  173. package/ccw/src/core/cache-manager.ts +294 -0
  174. package/ccw/src/core/claude-freshness.ts +319 -0
  175. package/ccw/src/core/core-memory-store.ts +1528 -0
  176. package/ccw/src/core/{dashboard-generator-patch.js → dashboard-generator-patch.ts} +18 -0
  177. package/ccw/src/core/{dashboard-generator.js → dashboard-generator.ts} +69 -12
  178. package/ccw/src/core/data-aggregator.ts +584 -0
  179. package/ccw/src/core/history-importer.ts +625 -0
  180. package/ccw/src/core/{lite-scanner.js → lite-scanner-complete.ts} +162 -66
  181. package/ccw/src/core/lite-scanner.ts +469 -0
  182. package/ccw/src/core/{manifest.js → manifest.ts} +104 -34
  183. package/ccw/src/core/memory-embedder-bridge.ts +262 -0
  184. package/ccw/src/core/memory-store.ts +978 -0
  185. package/ccw/src/core/routes/ccw-routes.ts +96 -0
  186. package/ccw/src/core/routes/claude-routes.ts +1183 -0
  187. package/ccw/src/core/routes/cli-routes.ts +561 -0
  188. package/ccw/src/core/routes/codexlens-routes.ts +806 -0
  189. package/ccw/src/core/routes/core-memory-routes.ts +605 -0
  190. package/ccw/src/core/routes/files-routes.ts +428 -0
  191. package/ccw/src/core/routes/graph-routes.md +164 -0
  192. package/ccw/src/core/routes/graph-routes.ts +626 -0
  193. package/ccw/src/core/routes/help-routes.ts +308 -0
  194. package/ccw/src/core/routes/hooks-routes.ts +405 -0
  195. package/ccw/src/core/routes/mcp-routes.ts +1271 -0
  196. package/ccw/src/core/routes/mcp-routes.ts.backup +550 -0
  197. package/ccw/src/core/routes/mcp-templates-db.ts +268 -0
  198. package/ccw/src/core/routes/memory-routes.ts +1206 -0
  199. package/ccw/src/core/routes/rules-routes.ts +526 -0
  200. package/ccw/src/core/routes/session-routes.ts +467 -0
  201. package/ccw/src/core/routes/skills-routes.ts +599 -0
  202. package/ccw/src/core/routes/status-routes.ts +57 -0
  203. package/ccw/src/core/routes/system-routes.ts +427 -0
  204. package/ccw/src/core/server.ts +431 -0
  205. package/ccw/src/core/session-clustering-service.ts +1258 -0
  206. package/ccw/src/core/session-scanner.ts +283 -0
  207. package/ccw/src/core/websocket.ts +190 -0
  208. package/ccw/src/{index.js → index.ts} +1 -0
  209. package/ccw/src/mcp-server/index.ts +186 -0
  210. package/ccw/src/templates/assets/css/github-dark.min.css +10 -0
  211. package/ccw/src/templates/assets/css/github.min.css +10 -0
  212. package/ccw/src/templates/assets/js/cytoscape.min.js +32 -0
  213. package/ccw/src/templates/assets/js/d3.min.js +2 -0
  214. package/ccw/src/templates/assets/js/highlight.min.js +1244 -0
  215. package/ccw/src/templates/assets/js/lucide.min.js +12 -0
  216. package/ccw/src/templates/assets/js/marked.min.js +69 -0
  217. package/ccw/src/templates/assets/js/tailwind.js +83 -0
  218. package/ccw/src/templates/dashboard-css/01-base.css +11 -0
  219. package/ccw/src/templates/dashboard-css/02-session.css +22 -0
  220. package/ccw/src/templates/dashboard-css/04-lite-tasks.css +10 -0
  221. package/ccw/src/templates/dashboard-css/06-cards.css +10 -4
  222. package/ccw/src/templates/dashboard-css/07-managers.css +1178 -7
  223. package/ccw/src/templates/dashboard-css/09-explorer.css +23 -12
  224. package/ccw/src/templates/dashboard-css/10-cli-status.css +337 -0
  225. package/ccw/src/templates/dashboard-css/11-cli-history.css +271 -0
  226. package/ccw/src/templates/dashboard-css/12-cli-legacy.css +796 -0
  227. package/ccw/src/templates/dashboard-css/13-cli-ccw.css +199 -0
  228. package/ccw/src/templates/dashboard-css/14-cli-modals.css +258 -0
  229. package/ccw/src/templates/dashboard-css/15-cli-endpoints.css +305 -0
  230. package/ccw/src/templates/dashboard-css/16-cli-session.css +241 -0
  231. package/ccw/src/templates/dashboard-css/17-cli-conversation.css +283 -0
  232. package/ccw/src/templates/dashboard-css/18-cli-settings.css +160 -0
  233. package/ccw/src/templates/dashboard-css/19-cli-native-session.css +496 -0
  234. package/ccw/src/templates/dashboard-css/20-cli-taskqueue.css +188 -0
  235. package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +310 -0
  236. package/ccw/src/templates/dashboard-css/22-cli-semantic.css +240 -0
  237. package/ccw/src/templates/dashboard-css/23-memory.css +2390 -0
  238. package/ccw/src/templates/dashboard-css/24-prompt-history.css +1089 -0
  239. package/ccw/src/templates/dashboard-css/25-skills-rules.css +326 -0
  240. package/ccw/src/templates/dashboard-css/26-claude-manager.css +908 -0
  241. package/ccw/src/templates/dashboard-css/27-graph-explorer.css +1678 -0
  242. package/ccw/src/templates/dashboard-css/28-mcp-manager.css +748 -0
  243. package/ccw/src/templates/dashboard-css/29-help.css +264 -0
  244. package/ccw/src/templates/dashboard-css/30-core-memory.css +1700 -0
  245. package/ccw/src/templates/dashboard-js/api.js +162 -142
  246. package/ccw/src/templates/dashboard-js/components/carousel.js +4 -4
  247. package/ccw/src/templates/dashboard-js/components/cli-history.js +876 -0
  248. package/ccw/src/templates/dashboard-js/components/cli-status.js +978 -0
  249. package/ccw/src/templates/dashboard-js/components/global-notifications.js +508 -219
  250. package/ccw/src/templates/dashboard-js/components/hook-manager.js +1277 -282
  251. package/ccw/src/templates/dashboard-js/components/index-manager.js +302 -0
  252. package/ccw/src/templates/dashboard-js/components/mcp-manager.js +718 -27
  253. package/ccw/src/templates/dashboard-js/components/modals.js +66 -0
  254. package/ccw/src/templates/dashboard-js/components/navigation.js +80 -12
  255. package/ccw/src/templates/dashboard-js/components/notifications.js +758 -194
  256. package/ccw/src/templates/dashboard-js/components/storage-manager.js +478 -0
  257. package/ccw/src/templates/dashboard-js/components/tabs-other.js +157 -6
  258. package/ccw/src/templates/dashboard-js/components/task-queue-sidebar.js +716 -0
  259. package/ccw/src/templates/dashboard-js/help-i18n.js +272 -0
  260. package/ccw/src/templates/dashboard-js/i18n.js +2807 -0
  261. package/ccw/src/templates/dashboard-js/main.js +15 -0
  262. package/ccw/src/templates/dashboard-js/state.js +243 -42
  263. package/ccw/src/templates/dashboard-js/utils.js +47 -1
  264. package/ccw/src/templates/dashboard-js/views/claude-manager.js +912 -0
  265. package/ccw/src/templates/dashboard-js/views/cli-manager.js +2272 -0
  266. package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +964 -0
  267. package/ccw/src/templates/dashboard-js/views/core-memory-clusters.js +503 -0
  268. package/ccw/src/templates/dashboard-js/views/core-memory.js +782 -0
  269. package/ccw/src/templates/dashboard-js/views/explorer.js +888 -852
  270. package/ccw/src/templates/dashboard-js/views/graph-explorer.js +1157 -0
  271. package/ccw/src/templates/dashboard-js/views/help.js +856 -0
  272. package/ccw/src/templates/dashboard-js/views/history.js +337 -0
  273. package/ccw/src/templates/dashboard-js/views/home.js +61 -15
  274. package/ccw/src/templates/dashboard-js/views/hook-manager.js +311 -43
  275. package/ccw/src/templates/dashboard-js/views/lite-tasks.js +204 -28
  276. package/ccw/src/templates/dashboard-js/views/mcp-manager.js +2187 -411
  277. package/ccw/src/templates/dashboard-js/views/mcp-manager.js.backup +1729 -0
  278. package/ccw/src/templates/dashboard-js/views/mcp-manager.js.new +928 -0
  279. package/ccw/src/templates/dashboard-js/views/memory.js +1221 -0
  280. package/ccw/src/templates/dashboard-js/views/prompt-history.js +713 -0
  281. package/ccw/src/templates/dashboard-js/views/rules-manager.js +828 -0
  282. package/ccw/src/templates/dashboard-js/views/session-detail.js +54 -53
  283. package/ccw/src/templates/dashboard-js/views/skills-manager.js +819 -0
  284. package/ccw/src/templates/dashboard.html +185 -85
  285. package/ccw/src/templates/hooks-config-example.json +60 -0
  286. package/ccw/src/tools/classify-folders.ts +245 -0
  287. package/ccw/src/tools/cli-config-manager.ts +268 -0
  288. package/ccw/src/tools/cli-executor.ts +2014 -0
  289. package/ccw/src/tools/cli-history-store.ts +1195 -0
  290. package/ccw/src/tools/codex-lens.ts +1141 -0
  291. package/ccw/src/tools/{convert-tokens-to-css.js → convert-tokens-to-css.ts} +73 -23
  292. package/ccw/src/tools/core-memory.ts +444 -0
  293. package/ccw/src/tools/detect-changed-modules.ts +325 -0
  294. package/ccw/src/tools/{discover-design-files.js → discover-design-files.ts} +74 -24
  295. package/ccw/src/tools/edit-file.ts +568 -0
  296. package/ccw/src/tools/{generate-module-docs.js → generate-module-docs.ts} +207 -185
  297. package/ccw/src/tools/{get-modules-by-depth.js → get-modules-by-depth.ts} +120 -79
  298. package/ccw/src/tools/index.ts +370 -0
  299. package/ccw/src/tools/native-session-discovery.ts +795 -0
  300. package/ccw/src/tools/notifier.ts +129 -0
  301. package/ccw/src/tools/read-file.ts +410 -0
  302. package/ccw/src/tools/resume-strategy.ts +345 -0
  303. package/ccw/src/tools/session-content-parser.ts +619 -0
  304. package/ccw/src/tools/session-manager.ts +1026 -0
  305. package/ccw/src/tools/smart-context.ts +228 -0
  306. package/ccw/src/tools/smart-search.ts +2065 -0
  307. package/ccw/src/tools/smart-search.ts.backup +1233 -0
  308. package/ccw/src/tools/storage-manager.ts +455 -0
  309. package/ccw/src/tools/write-file.ts +222 -0
  310. package/ccw/src/types/config.ts +11 -0
  311. package/ccw/src/types/index.ts +3 -0
  312. package/ccw/src/types/session.ts +25 -0
  313. package/ccw/src/types/tool.ts +41 -0
  314. package/ccw/src/utils/{browser-launcher.js → browser-launcher.ts} +10 -8
  315. package/ccw/src/utils/file-utils.ts +48 -0
  316. package/ccw/src/utils/{path-resolver.js → path-resolver.ts} +114 -78
  317. package/ccw/src/utils/path-validator.ts +153 -0
  318. package/ccw/src/utils/{ui.js → ui.ts} +32 -25
  319. package/codex-lens/pyproject.toml +48 -0
  320. package/codex-lens/src/codexlens/.workflow/.cli-history/history.db +0 -0
  321. package/codex-lens/src/codexlens/__init__.py +28 -0
  322. package/codex-lens/src/codexlens/__main__.py +14 -0
  323. package/codex-lens/src/codexlens/__pycache__/__init__.cpython-313.pyc +0 -0
  324. package/codex-lens/src/codexlens/__pycache__/__main__.cpython-313.pyc +0 -0
  325. package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
  326. package/codex-lens/src/codexlens/__pycache__/entities.cpython-313.pyc +0 -0
  327. package/codex-lens/src/codexlens/__pycache__/errors.cpython-313.pyc +0 -0
  328. package/codex-lens/src/codexlens/cli/__init__.py +27 -0
  329. package/codex-lens/src/codexlens/cli/__pycache__/__init__.cpython-313.pyc +0 -0
  330. package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
  331. package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
  332. package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
  333. package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
  334. package/codex-lens/src/codexlens/cli/commands.py +1931 -0
  335. package/codex-lens/src/codexlens/cli/embedding_manager.py +620 -0
  336. package/codex-lens/src/codexlens/cli/model_manager.py +289 -0
  337. package/codex-lens/src/codexlens/cli/output.py +124 -0
  338. package/codex-lens/src/codexlens/config.py +201 -0
  339. package/codex-lens/src/codexlens/entities.py +121 -0
  340. package/codex-lens/src/codexlens/errors.py +55 -0
  341. package/codex-lens/src/codexlens/indexing/README.md +77 -0
  342. package/codex-lens/src/codexlens/indexing/__init__.py +4 -0
  343. package/codex-lens/src/codexlens/indexing/__pycache__/__init__.cpython-313.pyc +0 -0
  344. package/codex-lens/src/codexlens/indexing/__pycache__/symbol_extractor.cpython-313.pyc +0 -0
  345. package/codex-lens/src/codexlens/indexing/symbol_extractor.py +243 -0
  346. package/codex-lens/src/codexlens/parsers/__init__.py +8 -0
  347. package/codex-lens/src/codexlens/parsers/__pycache__/__init__.cpython-313.pyc +0 -0
  348. package/codex-lens/src/codexlens/parsers/__pycache__/encoding.cpython-313.pyc +0 -0
  349. package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-313.pyc +0 -0
  350. package/codex-lens/src/codexlens/parsers/__pycache__/tokenizer.cpython-313.pyc +0 -0
  351. package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-313.pyc +0 -0
  352. package/codex-lens/src/codexlens/parsers/encoding.py +202 -0
  353. package/codex-lens/src/codexlens/parsers/factory.py +256 -0
  354. package/codex-lens/src/codexlens/parsers/tokenizer.py +98 -0
  355. package/codex-lens/src/codexlens/parsers/treesitter_parser.py +335 -0
  356. package/codex-lens/src/codexlens/search/__init__.py +15 -0
  357. package/codex-lens/src/codexlens/search/__pycache__/__init__.cpython-313.pyc +0 -0
  358. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
  359. package/codex-lens/src/codexlens/search/__pycache__/enrichment.cpython-313.pyc +0 -0
  360. package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
  361. package/codex-lens/src/codexlens/search/__pycache__/query_parser.cpython-313.pyc +0 -0
  362. package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
  363. package/codex-lens/src/codexlens/search/chain_search.py +647 -0
  364. package/codex-lens/src/codexlens/search/enrichment.py +150 -0
  365. package/codex-lens/src/codexlens/search/hybrid_search.py +313 -0
  366. package/codex-lens/src/codexlens/search/query_parser.py +242 -0
  367. package/codex-lens/src/codexlens/search/ranking.py +274 -0
  368. package/codex-lens/src/codexlens/semantic/__init__.py +39 -0
  369. package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
  370. package/codex-lens/src/codexlens/semantic/__pycache__/ann_index.cpython-313.pyc +0 -0
  371. package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
  372. package/codex-lens/src/codexlens/semantic/__pycache__/code_extractor.cpython-313.pyc +0 -0
  373. package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
  374. package/codex-lens/src/codexlens/semantic/__pycache__/graph_analyzer.cpython-313.pyc +0 -0
  375. package/codex-lens/src/codexlens/semantic/__pycache__/llm_enhancer.cpython-313.pyc +0 -0
  376. package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
  377. package/codex-lens/src/codexlens/semantic/ann_index.py +414 -0
  378. package/codex-lens/src/codexlens/semantic/chunker.py +448 -0
  379. package/codex-lens/src/codexlens/semantic/code_extractor.py +274 -0
  380. package/codex-lens/src/codexlens/semantic/embedder.py +185 -0
  381. package/codex-lens/src/codexlens/semantic/vector_store.py +955 -0
  382. package/codex-lens/src/codexlens/storage/__init__.py +29 -0
  383. package/codex-lens/src/codexlens/storage/__pycache__/__init__.cpython-313.pyc +0 -0
  384. package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
  385. package/codex-lens/src/codexlens/storage/__pycache__/file_cache.cpython-313.pyc +0 -0
  386. package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
  387. package/codex-lens/src/codexlens/storage/__pycache__/migration_manager.cpython-313.pyc +0 -0
  388. package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
  389. package/codex-lens/src/codexlens/storage/__pycache__/registry.cpython-313.pyc +0 -0
  390. package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-313.pyc +0 -0
  391. package/codex-lens/src/codexlens/storage/__pycache__/sqlite_utils.cpython-313.pyc +0 -0
  392. package/codex-lens/src/codexlens/storage/dir_index.py +1850 -0
  393. package/codex-lens/src/codexlens/storage/file_cache.py +32 -0
  394. package/codex-lens/src/codexlens/storage/index_tree.py +776 -0
  395. package/codex-lens/src/codexlens/storage/migration_manager.py +154 -0
  396. package/codex-lens/src/codexlens/storage/migrations/__init__.py +1 -0
  397. package/codex-lens/src/codexlens/storage/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
  398. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_001_normalize_keywords.cpython-313.pyc +0 -0
  399. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_002_add_token_metadata.cpython-313.pyc +0 -0
  400. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_003_code_relationships.cpython-313.pyc +0 -0
  401. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
  402. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_005_cleanup_unused_fields.cpython-313.pyc +0 -0
  403. package/codex-lens/src/codexlens/storage/migrations/migration_001_normalize_keywords.py +123 -0
  404. package/codex-lens/src/codexlens/storage/migrations/migration_002_add_token_metadata.py +48 -0
  405. package/codex-lens/src/codexlens/storage/migrations/migration_004_dual_fts.py +232 -0
  406. package/codex-lens/src/codexlens/storage/migrations/migration_005_cleanup_unused_fields.py +196 -0
  407. package/codex-lens/src/codexlens/storage/path_mapper.py +274 -0
  408. package/codex-lens/src/codexlens/storage/registry.py +670 -0
  409. package/codex-lens/src/codexlens/storage/sqlite_store.py +576 -0
  410. package/codex-lens/src/codexlens/storage/sqlite_utils.py +64 -0
  411. package/package.json +4 -1
  412. package/.claude/commands/memory/tech-research.md +0 -477
  413. package/.claude/scripts/classify-folders.sh +0 -39
  414. package/.claude/scripts/convert_tokens_to_css.sh +0 -229
  415. package/.claude/scripts/detect_changed_modules.sh +0 -161
  416. package/.claude/scripts/discover-design-files.sh +0 -87
  417. package/.claude/scripts/extract-animations.js +0 -243
  418. package/.claude/scripts/extract-computed-styles.js +0 -118
  419. package/.claude/scripts/extract-layout-structure.js +0 -411
  420. package/.claude/scripts/generate_module_docs.sh +0 -717
  421. package/.claude/scripts/get_modules_by_depth.sh +0 -170
  422. package/.claude/scripts/ui-generate-preview.sh +0 -395
  423. package/.claude/scripts/ui-instantiate-prototypes.sh +0 -815
  424. package/.claude/scripts/update_module_claude.sh +0 -337
  425. package/.claude/workflows/context-search-strategy.md +0 -77
  426. package/.claude/workflows/intelligent-tools-strategy.md +0 -662
  427. package/ccw/src/cli.js +0 -119
  428. package/ccw/src/commands/install.js +0 -324
  429. package/ccw/src/commands/tool.js +0 -138
  430. package/ccw/src/core/data-aggregator.js +0 -409
  431. package/ccw/src/core/server.js +0 -2063
  432. package/ccw/src/core/session-scanner.js +0 -235
  433. package/ccw/src/tools/classify-folders.js +0 -204
  434. package/ccw/src/tools/detect-changed-modules.js +0 -288
  435. package/ccw/src/tools/edit-file.js +0 -266
  436. package/ccw/src/tools/index.js +0 -176
  437. package/ccw/src/utils/file-utils.js +0 -48
@@ -0,0 +1,1157 @@
1
+ // Graph Explorer View
2
+ // Interactive code relationship visualization using Cytoscape.js
3
+
4
+ // ========== State Variables ==========
5
+ var graphData = { nodes: [], edges: [] };
6
+ var cyInstance = null;
7
+ var activeTab = 'graph';
8
+ var activeDataSource = 'code';
9
+ var nodeFilters = {
10
+ MODULE: true,
11
+ CLASS: true,
12
+ FUNCTION: true,
13
+ METHOD: true,
14
+ VARIABLE: true
15
+ };
16
+ var edgeFilters = {
17
+ CALLS: true,
18
+ IMPORTS: true,
19
+ INHERITS: true
20
+ };
21
+ var selectedNode = null;
22
+ var searchProcessData = null;
23
+ var availableFiles = [];
24
+ var availableModules = [];
25
+ var selectedFile = null;
26
+ var selectedModule = null;
27
+ var filterMode = 'all'; // 'all', 'file', 'module'
28
+
29
+ // ========== Node/Edge Colors ==========
30
+ var NODE_COLORS = {
31
+ MODULE: '#8B5CF6',
32
+ CLASS: '#3B82F6',
33
+ FUNCTION: '#10B981',
34
+ METHOD: '#F59E0B',
35
+ VARIABLE: '#6B7280'
36
+ };
37
+
38
+ var EDGE_COLORS = {
39
+ CALLS: '#10B981',
40
+ IMPORTS: '#3B82F6',
41
+ INHERITS: '#F59E0B'
42
+ };
43
+
44
+ // ========== Main Render Function ==========
45
+ async function renderGraphExplorer() {
46
+ var container = document.getElementById('mainContent');
47
+ if (!container) return;
48
+
49
+ // Hide stats grid and carousel
50
+ hideStatsAndCarousel();
51
+
52
+ // Show loading state
53
+ container.innerHTML = '<div class="graph-explorer-view loading">' +
54
+ '<div class="loading-spinner"><i data-lucide="loader-2" class="w-8 h-8 animate-spin"></i></div>' +
55
+ '<p>' + t('common.loading') + '</p>' +
56
+ '</div>';
57
+
58
+ // Load data
59
+ await Promise.all([
60
+ loadGraphData(),
61
+ loadSearchProcessData(),
62
+ loadFilesAndModules()
63
+ ]);
64
+
65
+ // Render layout
66
+ container.innerHTML = renderGraphLayout();
67
+
68
+ // Initialize Cytoscape.js after DOM is ready
69
+ setTimeout(function() {
70
+ if (activeTab === 'graph') {
71
+ initializeCytoscape();
72
+ }
73
+ if (window.lucide) lucide.createIcons();
74
+ }, 100);
75
+ }
76
+
77
+ // ========== Data Loading ==========
78
+ async function loadGraphData() {
79
+ try {
80
+ // Build query parameters based on filter mode
81
+ var queryParams = new URLSearchParams();
82
+ if (filterMode === 'file' && selectedFile) {
83
+ queryParams.set('file', selectedFile);
84
+ } else if (filterMode === 'module' && selectedModule) {
85
+ queryParams.set('module', selectedModule);
86
+ }
87
+
88
+ var queryString = queryParams.toString();
89
+ var nodesUrl = '/api/graph/nodes' + (queryString ? '?' + queryString : '');
90
+ var edgesUrl = '/api/graph/edges' + (queryString ? '?' + queryString : '');
91
+
92
+ console.log('[Graph] Loading data with filter:', {
93
+ mode: filterMode,
94
+ file: selectedFile,
95
+ module: selectedModule,
96
+ nodesUrl: nodesUrl,
97
+ edgesUrl: edgesUrl
98
+ });
99
+
100
+ var nodesResp = await fetch(nodesUrl);
101
+ if (!nodesResp.ok) throw new Error('Failed to load graph nodes');
102
+ var nodesData = await nodesResp.json();
103
+
104
+ var edgesResp = await fetch(edgesUrl);
105
+ if (!edgesResp.ok) throw new Error('Failed to load graph edges');
106
+ var edgesData = await edgesResp.json();
107
+
108
+ graphData = {
109
+ nodes: nodesData.nodes || [],
110
+ edges: edgesData.edges || []
111
+ };
112
+
113
+ console.log('[Graph] Loaded data:', {
114
+ nodes: graphData.nodes.length,
115
+ edges: graphData.edges.length,
116
+ filters: nodesData.filters
117
+ });
118
+
119
+ return graphData;
120
+ } catch (err) {
121
+ console.error('Failed to load graph data:', err);
122
+ graphData = { nodes: [], edges: [] };
123
+ return graphData;
124
+ }
125
+ }
126
+
127
+ async function loadFilesAndModules() {
128
+ try {
129
+ var response = await fetch('/api/graph/files');
130
+ if (!response.ok) throw new Error('Failed to load files and modules');
131
+ var data = await response.json();
132
+
133
+ availableFiles = data.files || [];
134
+ availableModules = data.modules || [];
135
+ return { files: availableFiles, modules: availableModules };
136
+ } catch (err) {
137
+ console.error('Failed to load files and modules:', err);
138
+ availableFiles = [];
139
+ availableModules = [];
140
+ return { files: [], modules: [] };
141
+ }
142
+ }
143
+
144
+ async function loadCoreMemoryGraphData() {
145
+ try {
146
+ var response = await fetch('/api/core-memory/graph');
147
+ if (!response.ok) throw new Error('Failed to load core memory graph data');
148
+ var data = await response.json();
149
+
150
+ graphData = {
151
+ nodes: (data.nodes || []).map(function(node) {
152
+ return {
153
+ id: node.id || node.name,
154
+ name: node.name || node.label || node.id,
155
+ type: node.type || 'MODULE',
156
+ symbolType: node.symbol_type || node.symbolType,
157
+ path: node.path || node.file_path,
158
+ lineNumber: node.line_number || node.lineNumber,
159
+ imports: node.imports || 0,
160
+ exports: node.exports || 0,
161
+ references: node.references || 0
162
+ };
163
+ }),
164
+ edges: (data.edges || []).map(function(edge) {
165
+ return {
166
+ source: edge.source || edge.from,
167
+ target: edge.target || edge.to,
168
+ type: edge.type || edge.relation_type || 'CALLS',
169
+ weight: edge.weight || 1
170
+ };
171
+ })
172
+ };
173
+ return graphData;
174
+ } catch (err) {
175
+ console.error('Failed to load core memory graph data:', err);
176
+ graphData = { nodes: [], edges: [] };
177
+ return graphData;
178
+ }
179
+ }
180
+
181
+ async function loadSearchProcessData() {
182
+ try {
183
+ var response = await fetch('/api/graph/search-process');
184
+ if (!response.ok) throw new Error('Failed to load search process data');
185
+ var data = await response.json();
186
+ searchProcessData = data.searchProcess || null;
187
+ return searchProcessData;
188
+ } catch (err) {
189
+ console.error('Failed to load search process data:', err);
190
+ searchProcessData = null;
191
+ return null;
192
+ }
193
+ }
194
+
195
+ // ========== UI Layout ==========
196
+ function renderGraphLayout() {
197
+ return '<div class="graph-explorer-view">' +
198
+ '<div class="graph-explorer-header">' +
199
+ '<h2><i data-lucide="network" class="w-5 h-5"></i> ' + t('graph.title') + '</h2>' +
200
+ '<div class="graph-explorer-tabs">' +
201
+ '<button class="tab-btn ' + (activeTab === 'graph' ? 'active' : '') + '" onclick="switchGraphTab(\'graph\')">' +
202
+ '<i data-lucide="git-branch" class="w-4 h-4"></i> ' + t('graph.codeRelations') +
203
+ '</button>' +
204
+ '<button class="tab-btn ' + (activeTab === 'search' ? 'active' : '') + '" onclick="switchGraphTab(\'search\')">' +
205
+ '<i data-lucide="search" class="w-4 h-4"></i> ' + t('graph.searchProcess') +
206
+ '</button>' +
207
+ '</div>' +
208
+ '</div>' +
209
+ '<div class="graph-explorer-content">' +
210
+ '<div id="graphTab" class="tab-content ' + (activeTab === 'graph' ? 'active' : '') + '">' +
211
+ renderGraphView() +
212
+ '</div>' +
213
+ '<div id="searchTab" class="tab-content ' + (activeTab === 'search' ? 'active' : '') + '">' +
214
+ renderSearchProcessView() +
215
+ '</div>' +
216
+ '</div>' +
217
+ '</div>';
218
+ }
219
+
220
+ function renderGraphView() {
221
+ return '<div class="graph-view">' +
222
+ '<div class="graph-sidebar">' +
223
+ '<div class="graph-controls-section">' +
224
+ '<h3>' + t('graph.filters') + '</h3>' +
225
+ renderFilterDropdowns() +
226
+ '</div>' +
227
+ '<div class="graph-legend-section">' +
228
+ '<h3>' + t('graph.legend') + '</h3>' +
229
+ renderGraphLegend() +
230
+ '</div>' +
231
+ '<div id="nodeDetailsPanel" class="node-details-panel hidden">' +
232
+ '</div>' +
233
+ '</div>' +
234
+ '<div class="graph-main">' +
235
+ '<div class="graph-toolbar">' +
236
+ '<div class="graph-toolbar-left">' +
237
+ '<span class="graph-stats">' +
238
+ '<i data-lucide="circle" class="w-3 h-3"></i> ' +
239
+ graphData.nodes.length + ' ' + t('graph.nodes') +
240
+ '</span>' +
241
+ '<span class="graph-stats">' +
242
+ '<i data-lucide="arrow-right" class="w-3 h-3"></i> ' +
243
+ graphData.edges.length + ' ' + t('graph.edges') +
244
+ '</span>' +
245
+ '<select id="dataSourceSelect" onchange="switchDataSource(this.value)" class="data-source-select">' +
246
+ '<option value="code" ' + (activeDataSource === 'code' ? 'selected' : '') + '>' + t('graph.codeRelations') + '</option>' +
247
+ '<option value="memory" ' + (activeDataSource === 'memory' ? 'selected' : '') + '>' + t('graph.coreMemory') + '</option>' +
248
+ '</select>' +
249
+ '</div>' +
250
+ '<div class="graph-toolbar-right">' +
251
+ '<button class="btn-icon" onclick="fitCytoscape()" title="' + t('graph.fitView') + '">' +
252
+ '<i data-lucide="maximize-2" class="w-4 h-4"></i>' +
253
+ '</button>' +
254
+ '<button class="btn-icon" onclick="centerCytoscape()" title="' + t('graph.center') + '">' +
255
+ '<i data-lucide="crosshair" class="w-4 h-4"></i>' +
256
+ '</button>' +
257
+ '<button class="btn-icon" onclick="resetGraphFilters()" title="' + t('graph.resetFilters') + '">' +
258
+ '<i data-lucide="filter-x" class="w-4 h-4"></i>' +
259
+ '</button>' +
260
+ '<button class="btn-icon" onclick="refreshGraphData()" title="' + t('common.refresh') + '">' +
261
+ '<i data-lucide="refresh-cw" class="w-4 h-4"></i>' +
262
+ '</button>' +
263
+ '</div>' +
264
+ '</div>' +
265
+ '<div id="cytoscapeContainer" class="cytoscape-container"></div>' +
266
+ '</div>' +
267
+ '</div>';
268
+ }
269
+
270
+ function renderFilterDropdowns() {
271
+ return '<div class="filter-dropdowns">' +
272
+ // Scope filter
273
+ '<div class="filter-group scope-filter">' +
274
+ '<label>' + t('graph.scope') + '</label>' +
275
+ '<div class="scope-selector">' +
276
+ '<label class="filter-radio">' +
277
+ '<input type="radio" name="scopeMode" value="all" ' + (filterMode === 'all' ? 'checked' : '') + ' onchange="changeScopeMode(\'all\')">' +
278
+ '<span>' + t('graph.allFiles') + '</span>' +
279
+ '</label>' +
280
+ '<label class="filter-radio">' +
281
+ '<input type="radio" name="scopeMode" value="module" ' + (filterMode === 'module' ? 'checked' : '') + ' onchange="changeScopeMode(\'module\')">' +
282
+ '<span>' + t('graph.byModule') + '</span>' +
283
+ '</label>' +
284
+ '<label class="filter-radio">' +
285
+ '<input type="radio" name="scopeMode" value="file" ' + (filterMode === 'file' ? 'checked' : '') + ' onchange="changeScopeMode(\'file\')">' +
286
+ '<span>' + t('graph.byFile') + '</span>' +
287
+ '</label>' +
288
+ '</div>' +
289
+ // Module selector (shown when filterMode === 'module')
290
+ (filterMode === 'module' ?
291
+ '<select id="moduleSelect" class="filter-select" onchange="selectModule(this.value)">' +
292
+ '<option value="">' + t('graph.selectModule') + '</option>' +
293
+ availableModules.map(function(module) {
294
+ return '<option value="' + escapeHtml(module) + '" ' + (selectedModule === module ? 'selected' : '') + '>' + escapeHtml(module) + '</option>';
295
+ }).join('') +
296
+ '</select>' : '') +
297
+ // File selector (shown when filterMode === 'file')
298
+ (filterMode === 'file' ?
299
+ '<select id="fileSelect" class="filter-select" onchange="selectFile(this.value)">' +
300
+ '<option value="">' + t('graph.selectFile') + '</option>' +
301
+ availableFiles.map(function(file) {
302
+ return '<option value="' + escapeHtml(file) + '" ' + (selectedFile === file ? 'selected' : '') + '>' + escapeHtml(file) + '</option>';
303
+ }).join('') +
304
+ '</select>' : '') +
305
+ '</div>' +
306
+ '<div class="filter-group">' +
307
+ '<label>' + t('graph.nodeTypes') + '</label>' +
308
+ Object.keys(NODE_COLORS).map(function(type) {
309
+ return '<label class="filter-checkbox">' +
310
+ '<input type="checkbox" ' + (nodeFilters[type] ? 'checked' : '') + ' onchange="toggleNodeFilter(\'' + type + '\', this.checked)">' +
311
+ '<span class="filter-color" style="background-color: ' + NODE_COLORS[type] + '"></span>' +
312
+ '<span>' + type + '</span>' +
313
+ '</label>';
314
+ }).join('') +
315
+ '</div>' +
316
+ '<div class="filter-group">' +
317
+ '<label>' + t('graph.edgeTypes') + '</label>' +
318
+ Object.keys(EDGE_COLORS).map(function(type) {
319
+ return '<label class="filter-checkbox">' +
320
+ '<input type="checkbox" ' + (edgeFilters[type] ? 'checked' : '') + ' onchange="toggleEdgeFilter(\'' + type + '\', this.checked)">' +
321
+ '<span class="filter-color" style="background-color: ' + EDGE_COLORS[type] + '"></span>' +
322
+ '<span>' + type + '</span>' +
323
+ '</label>';
324
+ }).join('') +
325
+ '</div>' +
326
+ '</div>';
327
+ }
328
+
329
+ function renderGraphLegend() {
330
+ return '<div class="graph-legend">' +
331
+ '<div class="legend-title">' + t('graph.nodeTypes') + '</div>' +
332
+ Object.keys(NODE_COLORS).map(function(type) {
333
+ return '<div class="legend-item">' +
334
+ '<span class="legend-dot" style="background-color: ' + NODE_COLORS[type] + '"></span>' +
335
+ '<span>' + type + '</span>' +
336
+ '</div>';
337
+ }).join('') +
338
+ '<div class="legend-title" style="margin-top: 1rem;">' + t('graph.edgeTypes') + '</div>' +
339
+ Object.keys(EDGE_COLORS).map(function(type) {
340
+ return '<div class="legend-item">' +
341
+ '<span class="legend-line" style="background-color: ' + EDGE_COLORS[type] + '"></span>' +
342
+ '<span>' + type + '</span>' +
343
+ '</div>';
344
+ }).join('') +
345
+ '</div>';
346
+ }
347
+
348
+ function renderSearchProcessView() {
349
+ if (!searchProcessData) {
350
+ return '<div class="search-process-empty">' +
351
+ '<i data-lucide="search-x" class="w-8 h-8"></i>' +
352
+ '<p>' + t('graph.noSearchData') + '</p>' +
353
+ '</div>';
354
+ }
355
+
356
+ return '<div class="search-process-view">' +
357
+ '<div class="search-process-header">' +
358
+ '<h3>' + t('graph.searchProcessTitle') + '</h3>' +
359
+ '<p class="search-process-desc">' + t('graph.searchProcessDesc') + '</p>' +
360
+ '</div>' +
361
+ '<div class="search-process-timeline">' +
362
+ (searchProcessData.steps || []).map(function(step, index) {
363
+ return '<div class="search-step">' +
364
+ '<div class="search-step-number">' + (index + 1) + '</div>' +
365
+ '<div class="search-step-content">' +
366
+ '<h4>' + escapeHtml(step.name || 'Step ' + (index + 1)) + '</h4>' +
367
+ '<p>' + escapeHtml(step.description || '') + '</p>' +
368
+ (step.results ? '<div class="search-step-results">' +
369
+ '<span class="result-count">' + (step.results.length || 0) + ' ' + t('graph.resultsFound') + '</span>' +
370
+ '</div>' : '') +
371
+ '</div>' +
372
+ '</div>';
373
+ }).join('') +
374
+ '</div>' +
375
+ '</div>';
376
+ }
377
+
378
+ // ========== Tab Switching ==========
379
+ function switchGraphTab(tab) {
380
+ activeTab = tab;
381
+
382
+ // Update tab buttons
383
+ var tabBtns = document.querySelectorAll('.graph-explorer-tabs .tab-btn');
384
+ tabBtns.forEach(function(btn) {
385
+ btn.classList.remove('active');
386
+ });
387
+ event.target.closest('.tab-btn').classList.add('active');
388
+
389
+ // Update tab content
390
+ document.getElementById('graphTab').classList.toggle('active', tab === 'graph');
391
+ document.getElementById('searchTab').classList.toggle('active', tab === 'search');
392
+
393
+ // Initialize Cytoscape if switching to graph tab
394
+ if (tab === 'graph' && !cyInstance) {
395
+ setTimeout(function() {
396
+ initializeCytoscape();
397
+ }, 100);
398
+ }
399
+ }
400
+
401
+ // ========== Cytoscape.js Integration ==========
402
+ function initializeCytoscape() {
403
+ var container = document.getElementById('cytoscapeContainer');
404
+ if (!container) return;
405
+
406
+ // Check if Cytoscape.js is loaded
407
+ if (typeof cytoscape === 'undefined') {
408
+ container.innerHTML = '<div class="cytoscape-error">' +
409
+ '<i data-lucide="alert-triangle" class="w-6 h-6"></i>' +
410
+ '<p>' + t('graph.cytoscapeNotLoaded') + '</p>' +
411
+ '</div>';
412
+ if (window.lucide) lucide.createIcons();
413
+ return;
414
+ }
415
+
416
+ if (graphData.nodes.length === 0) {
417
+ container.innerHTML = '<div class="cytoscape-empty">' +
418
+ '<i data-lucide="network" class="w-8 h-8"></i>' +
419
+ '<p>' + t('graph.noGraphData') + '</p>' +
420
+ '</div>';
421
+ if (window.lucide) lucide.createIcons();
422
+ return;
423
+ }
424
+
425
+ // Transform data for Cytoscape
426
+ var elements = transformDataForCytoscape();
427
+
428
+ // Create Cytoscape instance
429
+ cyInstance = cytoscape({
430
+ container: container,
431
+ elements: elements,
432
+ style: getCytoscapeStyles(),
433
+ layout: {
434
+ name: 'cose',
435
+ idealEdgeLength: 180,
436
+ nodeOverlap: 50,
437
+ refresh: 20,
438
+ fit: true,
439
+ padding: 50,
440
+ randomize: false,
441
+ componentSpacing: 150,
442
+ nodeRepulsion: 600000,
443
+ edgeElasticity: 100,
444
+ nestingFactor: 5,
445
+ gravity: 60,
446
+ numIter: 1000,
447
+ initialTemp: 200,
448
+ coolingFactor: 0.95,
449
+ minTemp: 1.0
450
+ },
451
+ minZoom: 0.1,
452
+ maxZoom: 3,
453
+ wheelSensitivity: 0.2
454
+ });
455
+
456
+ // Bind events
457
+ cyInstance.on('tap', 'node', function(evt) {
458
+ var node = evt.target;
459
+ selectNode(node.data());
460
+ });
461
+
462
+ cyInstance.on('tap', function(evt) {
463
+ if (evt.target === cyInstance) {
464
+ deselectNode();
465
+ }
466
+ });
467
+
468
+ // Mouse hover events for nodes
469
+ cyInstance.on('mouseover', 'node', function(evt) {
470
+ var node = evt.target;
471
+ node.addClass('hover');
472
+ // Highlight connected edges
473
+ node.connectedEdges().addClass('hover');
474
+ });
475
+
476
+ cyInstance.on('mouseout', 'node', function(evt) {
477
+ var node = evt.target;
478
+ node.removeClass('hover');
479
+ // Remove edge highlights (unless they are highlighted due to selection)
480
+ node.connectedEdges().removeClass('hover');
481
+ });
482
+
483
+ // Mouse hover events for edges
484
+ cyInstance.on('mouseover', 'edge', function(evt) {
485
+ var edge = evt.target;
486
+ edge.addClass('hover');
487
+ // Also highlight connected nodes
488
+ edge.source().addClass('hover');
489
+ edge.target().addClass('hover');
490
+ });
491
+
492
+ cyInstance.on('mouseout', 'edge', function(evt) {
493
+ var edge = evt.target;
494
+ edge.removeClass('hover');
495
+ // Remove node highlights
496
+ edge.source().removeClass('hover');
497
+ edge.target().removeClass('hover');
498
+ });
499
+
500
+ // Fit view after layout
501
+ setTimeout(function() {
502
+ fitCytoscape();
503
+ }, 100);
504
+ }
505
+
506
+ function transformDataForCytoscape() {
507
+ var elements = [];
508
+
509
+ // Filter nodes
510
+ var filteredNodes = graphData.nodes.filter(function(node) {
511
+ var type = node.type || 'MODULE';
512
+ return nodeFilters[type];
513
+ });
514
+
515
+ // Create node ID set and name-to-id mapping for edge resolution
516
+ var nodeIdSet = new Set();
517
+ var nodeNameToIds = {}; // Map symbol names to their node IDs
518
+
519
+ filteredNodes.forEach(function(node) {
520
+ var nodeId = node.id;
521
+ nodeIdSet.add(nodeId);
522
+
523
+ // Extract symbol name for matching
524
+ var name = node.name || '';
525
+ if (!nodeNameToIds[name]) {
526
+ nodeNameToIds[name] = [];
527
+ }
528
+ nodeNameToIds[name].push(nodeId);
529
+ });
530
+
531
+ // Add nodes
532
+ filteredNodes.forEach(function(node) {
533
+ elements.push({
534
+ group: 'nodes',
535
+ data: {
536
+ id: node.id,
537
+ label: node.name || node.id,
538
+ type: node.type || 'MODULE',
539
+ symbolType: node.symbolType,
540
+ path: node.path || node.file,
541
+ lineNumber: node.lineNumber || node.line,
542
+ imports: node.imports || 0,
543
+ exports: node.exports || 0,
544
+ references: node.references || 0
545
+ }
546
+ });
547
+ });
548
+
549
+ // Filter and resolve edges
550
+ var filteredEdges = graphData.edges.filter(function(edge) {
551
+ var type = edge.type || 'CALLS';
552
+ return edgeFilters[type];
553
+ });
554
+
555
+ // Process edges with target resolution
556
+ var edgeCount = 0;
557
+ filteredEdges.forEach(function(edge) {
558
+ var sourceId = edge.source;
559
+ var targetId = edge.target;
560
+
561
+ // Check if source exists
562
+ if (!nodeIdSet.has(sourceId)) {
563
+ return; // Skip if source node doesn't exist
564
+ }
565
+
566
+ // Try to resolve target
567
+ var resolvedTargetId = null;
568
+
569
+ // 1. Direct match
570
+ if (nodeIdSet.has(targetId)) {
571
+ resolvedTargetId = targetId;
572
+ }
573
+ // 2. Try to match by qualified name (extract symbol name)
574
+ else if (targetId) {
575
+ // Try to extract symbol name from qualified name
576
+ var targetName = targetId;
577
+
578
+ // Handle qualified names like "module.ClassName.methodName" or "file:name:line"
579
+ if (targetId.includes('.')) {
580
+ var parts = targetId.split('.');
581
+ targetName = parts[parts.length - 1]; // Get last part
582
+ } else if (targetId.includes(':')) {
583
+ var colonParts = targetId.split(':');
584
+ if (colonParts.length >= 2) {
585
+ targetName = colonParts[1]; // file:name:line format
586
+ }
587
+ }
588
+
589
+ // Look up in name-to-id mapping
590
+ if (nodeNameToIds[targetName] && nodeNameToIds[targetName].length > 0) {
591
+ // If multiple matches, prefer one in the same file
592
+ var sourceFile = edge.sourceFile || '';
593
+ var matchInSameFile = nodeNameToIds[targetName].find(function(id) {
594
+ return id.startsWith(sourceFile);
595
+ });
596
+ resolvedTargetId = matchInSameFile || nodeNameToIds[targetName][0];
597
+ }
598
+ }
599
+
600
+ // Only add edge if both source and target are resolved
601
+ if (resolvedTargetId && sourceId !== resolvedTargetId) {
602
+ elements.push({
603
+ group: 'edges',
604
+ data: {
605
+ id: 'edge-' + edgeCount++,
606
+ source: sourceId,
607
+ target: resolvedTargetId,
608
+ type: edge.type || 'CALLS',
609
+ weight: edge.weight || 1
610
+ }
611
+ });
612
+ }
613
+ });
614
+
615
+ console.log('[Graph] Transformed elements:', {
616
+ nodes: filteredNodes.length,
617
+ edges: edgeCount,
618
+ totalRawEdges: filteredEdges.length
619
+ });
620
+
621
+ return elements;
622
+ }
623
+
624
+ function getCytoscapeStyles() {
625
+ var styles = [
626
+ // Node styles by type - no label by default
627
+ {
628
+ selector: 'node',
629
+ style: {
630
+ 'background-color': function(ele) {
631
+ return NODE_COLORS[ele.data('type')] || '#6B7280';
632
+ },
633
+ 'label': '', // No label by default
634
+ 'width': function(ele) {
635
+ var refs = ele.data('references') || 0;
636
+ return Math.max(20, Math.min(48, 20 + refs * 1.5));
637
+ },
638
+ 'height': function(ele) {
639
+ var refs = ele.data('references') || 0;
640
+ return Math.max(20, Math.min(48, 20 + refs * 1.5));
641
+ },
642
+ 'border-width': 2,
643
+ 'border-color': function(ele) {
644
+ var color = NODE_COLORS[ele.data('type')] || '#6B7280';
645
+ return darkenColor(color, 20);
646
+ },
647
+ 'overlay-padding': 6
648
+ }
649
+ },
650
+ // Hovered node - show label
651
+ {
652
+ selector: 'node.hover',
653
+ style: {
654
+ 'label': 'data(label)',
655
+ 'text-valign': 'top',
656
+ 'text-halign': 'center',
657
+ 'text-margin-y': -8,
658
+ 'font-size': '11px',
659
+ 'font-weight': 'bold',
660
+ 'color': '#1f2937',
661
+ 'text-outline-color': '#fff',
662
+ 'text-outline-width': 2,
663
+ 'text-background-color': '#fff',
664
+ 'text-background-opacity': 0.9,
665
+ 'text-background-padding': '4px',
666
+ 'text-background-shape': 'roundrectangle',
667
+ 'z-index': 999
668
+ }
669
+ },
670
+ // Selected node - show label
671
+ {
672
+ selector: 'node:selected',
673
+ style: {
674
+ 'label': 'data(label)',
675
+ 'border-width': 4,
676
+ 'border-color': '#000',
677
+ 'text-valign': 'top',
678
+ 'text-halign': 'center',
679
+ 'text-margin-y': -8,
680
+ 'font-size': '11px',
681
+ 'font-weight': 'bold',
682
+ 'color': '#1f2937',
683
+ 'text-outline-color': '#fff',
684
+ 'text-outline-width': 2,
685
+ 'text-background-color': '#fff',
686
+ 'text-background-opacity': 0.9,
687
+ 'text-background-padding': '4px',
688
+ 'text-background-shape': 'roundrectangle',
689
+ 'overlay-color': '#000',
690
+ 'overlay-opacity': 0.2,
691
+ 'z-index': 999
692
+ }
693
+ },
694
+ // Edge styles by type - enhanced visibility
695
+ {
696
+ selector: 'edge',
697
+ style: {
698
+ 'width': function(ele) {
699
+ return Math.max(2, (ele.data('weight') || 1) * 1.5);
700
+ },
701
+ 'line-color': function(ele) {
702
+ return EDGE_COLORS[ele.data('type')] || '#6B7280';
703
+ },
704
+ 'target-arrow-color': function(ele) {
705
+ return EDGE_COLORS[ele.data('type')] || '#6B7280';
706
+ },
707
+ 'target-arrow-shape': 'triangle',
708
+ 'curve-style': 'bezier',
709
+ 'arrow-scale': 1.5,
710
+ 'opacity': 0.8,
711
+ 'z-index': 1
712
+ }
713
+ },
714
+ // Hovered edge
715
+ {
716
+ selector: 'edge.hover',
717
+ style: {
718
+ 'width': 4,
719
+ 'opacity': 1,
720
+ 'z-index': 100
721
+ }
722
+ },
723
+ // Highlighted edge (connected to selected node)
724
+ {
725
+ selector: 'edge.highlighted',
726
+ style: {
727
+ 'width': 3,
728
+ 'opacity': 1,
729
+ 'z-index': 50
730
+ }
731
+ },
732
+ // Selected edge
733
+ {
734
+ selector: 'edge:selected',
735
+ style: {
736
+ 'line-color': '#000',
737
+ 'target-arrow-color': '#000',
738
+ 'width': 4,
739
+ 'opacity': 1,
740
+ 'z-index': 100
741
+ }
742
+ }
743
+ ];
744
+
745
+ return styles;
746
+ }
747
+
748
+ // Helper function to darken a color
749
+ function darkenColor(hex, percent) {
750
+ var num = parseInt(hex.replace('#', ''), 16);
751
+ var amt = Math.round(2.55 * percent);
752
+ var R = Math.max(0, (num >> 16) - amt);
753
+ var G = Math.max(0, ((num >> 8) & 0x00FF) - amt);
754
+ var B = Math.max(0, (num & 0x0000FF) - amt);
755
+ return '#' + (0x1000000 + R * 0x10000 + G * 0x100 + B).toString(16).slice(1);
756
+ }
757
+
758
+ // ========== Node Selection ==========
759
+ function selectNode(nodeData) {
760
+ selectedNode = nodeData;
761
+
762
+ // Highlight in cytoscape
763
+ if (cyInstance) {
764
+ cyInstance.nodes().removeClass('selected');
765
+ var node = cyInstance.getElementById(nodeData.id);
766
+ if (node) {
767
+ node.addClass('selected');
768
+ // Highlight connected edges
769
+ cyInstance.edges().removeClass('highlighted');
770
+ node.connectedEdges().addClass('highlighted');
771
+ }
772
+ }
773
+
774
+ // Show details panel
775
+ var panel = document.getElementById('nodeDetailsPanel');
776
+ if (panel) {
777
+ panel.classList.remove('hidden');
778
+ panel.innerHTML = renderNodeDetails(nodeData);
779
+ if (window.lucide) lucide.createIcons();
780
+
781
+ // Attach event listener for impact analysis button (prevents XSS)
782
+ var impactBtn = document.getElementById('impactAnalysisBtn');
783
+ if (impactBtn) {
784
+ impactBtn.addEventListener('click', function() {
785
+ var nodeId = this.getAttribute('data-node-id');
786
+ if (nodeId) showImpactAnalysis(nodeId);
787
+ });
788
+ }
789
+ }
790
+ }
791
+
792
+ function deselectNode() {
793
+ selectedNode = null;
794
+
795
+ // Remove highlights
796
+ if (cyInstance) {
797
+ cyInstance.nodes().removeClass('selected');
798
+ cyInstance.edges().removeClass('highlighted');
799
+ }
800
+
801
+ // Hide details panel
802
+ var panel = document.getElementById('nodeDetailsPanel');
803
+ if (panel) {
804
+ panel.classList.add('hidden');
805
+ }
806
+ }
807
+
808
+ function renderNodeDetails(node) {
809
+ var typeIcon = node.type === 'MODULE' ? 'package' :
810
+ node.type === 'CLASS' ? 'box' :
811
+ node.type === 'FUNCTION' ? 'code' :
812
+ node.type === 'METHOD' ? 'code-2' :
813
+ 'variable';
814
+
815
+ return '<div class="node-details-content">' +
816
+ '<div class="node-details-header">' +
817
+ '<h4><i data-lucide="' + typeIcon + '" class="w-4 h-4"></i> ' + escapeHtml(node.label || node.id) + '</h4>' +
818
+ '<button class="btn-icon btn-sm" onclick="deselectNode()" title="' + t('common.close') + '">' +
819
+ '<i data-lucide="x" class="w-3 h-3"></i>' +
820
+ '</button>' +
821
+ '</div>' +
822
+ '<div class="node-details-meta">' +
823
+ '<div class="meta-item">' +
824
+ '<span class="meta-label">' + t('graph.type') + '</span>' +
825
+ '<span class="meta-value">' + (node.type || 'MODULE') + '</span>' +
826
+ '</div>' +
827
+ (node.symbolType ? '<div class="meta-item">' +
828
+ '<span class="meta-label">' + t('graph.symbolType') + '</span>' +
829
+ '<span class="meta-value">' + escapeHtml(node.symbolType) + '</span>' +
830
+ '</div>' : '') +
831
+ (node.path ? '<div class="meta-item">' +
832
+ '<span class="meta-label">' + t('graph.path') + '</span>' +
833
+ '<span class="meta-value path-value">' + escapeHtml(node.path) + '</span>' +
834
+ '</div>' : '') +
835
+ (node.lineNumber ? '<div class="meta-item">' +
836
+ '<span class="meta-label">' + t('graph.line') + '</span>' +
837
+ '<span class="meta-value">' + node.lineNumber + '</span>' +
838
+ '</div>' : '') +
839
+ '</div>' +
840
+ '<div class="node-details-stats">' +
841
+ '<div class="stat-item">' +
842
+ '<i data-lucide="download" class="w-3 h-3"></i>' +
843
+ '<span>' + (node.imports || 0) + ' ' + t('graph.imports') + '</span>' +
844
+ '</div>' +
845
+ '<div class="stat-item">' +
846
+ '<i data-lucide="upload" class="w-3 h-3"></i>' +
847
+ '<span>' + (node.exports || 0) + ' ' + t('graph.exports') + '</span>' +
848
+ '</div>' +
849
+ '<div class="stat-item">' +
850
+ '<i data-lucide="link" class="w-3 h-3"></i>' +
851
+ '<span>' + (node.references || 0) + ' ' + t('graph.references') + '</span>' +
852
+ '</div>' +
853
+ '</div>' +
854
+ '<div class="node-details-actions">' +
855
+ '<button class="btn btn-sm btn-primary" id="impactAnalysisBtn" data-node-id="' + escapeHtml(node.id) + '">' +
856
+ '<i data-lucide="target" class="w-3 h-3"></i> ' + t('graph.impactAnalysis') +
857
+ '</button>' +
858
+ '</div>' +
859
+ '</div>';
860
+ }
861
+
862
+ // ========== Filter Actions ==========
863
+ function toggleNodeFilter(type, checked) {
864
+ nodeFilters[type] = checked;
865
+ refreshCytoscape();
866
+ }
867
+
868
+ function toggleEdgeFilter(type, checked) {
869
+ edgeFilters[type] = checked;
870
+ refreshCytoscape();
871
+ }
872
+
873
+ function resetGraphFilters() {
874
+ // Reset all filters to true
875
+ Object.keys(nodeFilters).forEach(function(key) {
876
+ nodeFilters[key] = true;
877
+ });
878
+ Object.keys(edgeFilters).forEach(function(key) {
879
+ edgeFilters[key] = true;
880
+ });
881
+
882
+ // Update checkboxes
883
+ var checkboxes = document.querySelectorAll('.filter-checkbox input[type="checkbox"]');
884
+ checkboxes.forEach(function(cb) {
885
+ cb.checked = true;
886
+ });
887
+
888
+ refreshCytoscape();
889
+ }
890
+
891
+ function refreshCytoscape() {
892
+ if (!cyInstance) return;
893
+
894
+ var elements = transformDataForCytoscape();
895
+ cyInstance.elements().remove();
896
+ cyInstance.add(elements);
897
+ cyInstance.layout({
898
+ name: 'cose',
899
+ idealEdgeLength: 180,
900
+ nodeOverlap: 50,
901
+ refresh: 20,
902
+ fit: true,
903
+ padding: 50,
904
+ componentSpacing: 150,
905
+ nodeRepulsion: 600000,
906
+ gravity: 60
907
+ }).run();
908
+
909
+ deselectNode();
910
+ }
911
+
912
+ // ========== Cytoscape Controls ==========
913
+ function fitCytoscape() {
914
+ if (cyInstance) {
915
+ cyInstance.fit(null, 50);
916
+ }
917
+ }
918
+
919
+ function centerCytoscape() {
920
+ if (cyInstance) {
921
+ cyInstance.center();
922
+ }
923
+ }
924
+
925
+ // ========== Impact Analysis ==========
926
+ async function showImpactAnalysis(symbolId) {
927
+ try {
928
+ var response = await fetch('/api/graph/impact?symbol=' + encodeURIComponent(symbolId));
929
+ if (!response.ok) throw new Error('Failed to fetch impact analysis');
930
+ var data = await response.json();
931
+
932
+ // Show modal with impact analysis results
933
+ showImpactModal(data.impact);
934
+ } catch (err) {
935
+ console.error('Failed to fetch impact analysis:', err);
936
+ if (window.showToast) {
937
+ showToast(t('graph.impactAnalysisError'), 'error');
938
+ }
939
+ }
940
+ }
941
+
942
+ function showImpactModal(impact) {
943
+ var modal = document.createElement('div');
944
+ modal.className = 'modal-overlay';
945
+ modal.innerHTML = '<div class="modal-container">' +
946
+ '<div class="modal-header">' +
947
+ '<h3><i data-lucide="target" class="w-4 h-4"></i> ' + t('graph.impactAnalysis') + '</h3>' +
948
+ '<button class="btn-icon" onclick="closeImpactModal()">' +
949
+ '<i data-lucide="x" class="w-4 h-4"></i>' +
950
+ '</button>' +
951
+ '</div>' +
952
+ '<div class="modal-body">' +
953
+ '<div class="impact-summary">' +
954
+ '<div class="impact-stat">' +
955
+ '<span class="impact-stat-value">' + (impact.affectedFiles || 0) + '</span>' +
956
+ '<span class="impact-stat-label">' + t('graph.affectedFiles') + '</span>' +
957
+ '</div>' +
958
+ '<div class="impact-stat">' +
959
+ '<span class="impact-stat-value">' + (impact.affectedSymbols || 0) + '</span>' +
960
+ '<span class="impact-stat-label">' + t('graph.affectedSymbols') + '</span>' +
961
+ '</div>' +
962
+ '<div class="impact-stat">' +
963
+ '<span class="impact-stat-value">' + (impact.depth || 0) + '</span>' +
964
+ '<span class="impact-stat-label">' + t('graph.depth') + '</span>' +
965
+ '</div>' +
966
+ '</div>' +
967
+ (impact.files && impact.files.length > 0 ? '<div class="impact-files">' +
968
+ '<h4>' + t('graph.affectedFiles') + '</h4>' +
969
+ '<div class="impact-files-list">' +
970
+ impact.files.map(function(file) {
971
+ return '<div class="impact-file-item">' +
972
+ '<i data-lucide="file" class="w-3 h-3"></i>' +
973
+ '<span>' + escapeHtml(file) + '</span>' +
974
+ '</div>';
975
+ }).join('') +
976
+ '</div>' +
977
+ '</div>' : '') +
978
+ '</div>' +
979
+ '<div class="modal-footer">' +
980
+ '<button class="btn btn-secondary" onclick="closeImpactModal()">' + t('common.close') + '</button>' +
981
+ '</div>' +
982
+ '</div>';
983
+
984
+ document.body.appendChild(modal);
985
+ if (window.lucide) lucide.createIcons();
986
+
987
+ // Close on overlay click
988
+ modal.addEventListener('click', function(e) {
989
+ if (e.target === modal) {
990
+ closeImpactModal();
991
+ }
992
+ });
993
+ }
994
+
995
+ function closeImpactModal() {
996
+ var modal = document.querySelector('.modal-overlay');
997
+ if (modal) {
998
+ modal.remove();
999
+ }
1000
+ }
1001
+
1002
+ // ========== Data Source Switching ==========
1003
+ async function switchDataSource(source) {
1004
+ activeDataSource = source;
1005
+
1006
+ // Show loading state
1007
+ var container = document.getElementById('cytoscapeContainer');
1008
+ if (container) {
1009
+ container.innerHTML = '<div class="cytoscape-empty">' +
1010
+ '<i data-lucide="loader-2" class="w-8 h-8 animate-spin"></i>' +
1011
+ '<p>' + t('common.loading') + '</p>' +
1012
+ '</div>';
1013
+ if (window.lucide) lucide.createIcons();
1014
+ }
1015
+
1016
+ // Load data based on source
1017
+ if (source === 'memory') {
1018
+ await loadCoreMemoryGraphData();
1019
+ } else {
1020
+ await loadGraphData();
1021
+ }
1022
+
1023
+ // Update stats display
1024
+ updateGraphStats();
1025
+
1026
+ // Reinitialize Cytoscape with new data
1027
+ if (cyInstance) {
1028
+ cyInstance.destroy();
1029
+ cyInstance = null;
1030
+ }
1031
+ initializeCytoscape();
1032
+
1033
+ // Show toast notification
1034
+ if (window.showToast) {
1035
+ var sourceName = source === 'memory' ? t('graph.coreMemory') : t('graph.codeRelations');
1036
+ showToast(t('graph.dataSourceSwitched') + ': ' + sourceName, 'success');
1037
+ }
1038
+ }
1039
+
1040
+ // ========== Data Refresh ==========
1041
+ async function refreshGraphData() {
1042
+ if (window.showToast) {
1043
+ showToast(t('common.refreshing'), 'info');
1044
+ }
1045
+
1046
+ // Show loading state in container
1047
+ var container = document.getElementById('cytoscapeContainer');
1048
+ if (container) {
1049
+ container.innerHTML = '<div class="cytoscape-empty">' +
1050
+ '<i data-lucide="loader-2" class="w-8 h-8 animate-spin"></i>' +
1051
+ '<p>' + t('common.loading') + '</p>' +
1052
+ '</div>';
1053
+ if (window.lucide) lucide.createIcons();
1054
+ }
1055
+
1056
+ // Load data based on source
1057
+ if (activeDataSource === 'memory') {
1058
+ await loadCoreMemoryGraphData();
1059
+ } else {
1060
+ await loadGraphData();
1061
+ }
1062
+
1063
+ // Update stats display
1064
+ updateGraphStats();
1065
+
1066
+ // Reinitialize Cytoscape with new data
1067
+ if (cyInstance) {
1068
+ cyInstance.destroy();
1069
+ cyInstance = null;
1070
+ }
1071
+
1072
+ if (activeTab === 'graph') {
1073
+ initializeCytoscape();
1074
+ }
1075
+
1076
+ if (window.showToast) {
1077
+ showToast(t('common.refreshed'), 'success');
1078
+ }
1079
+ }
1080
+
1081
+ // Update graph statistics display
1082
+ function updateGraphStats() {
1083
+ var statsSpans = document.querySelectorAll('.graph-stats');
1084
+ if (statsSpans.length >= 2) {
1085
+ statsSpans[0].innerHTML = '<i data-lucide="circle" class="w-3 h-3"></i> ' +
1086
+ graphData.nodes.length + ' ' + t('graph.nodes');
1087
+ statsSpans[1].innerHTML = '<i data-lucide="arrow-right" class="w-3 h-3"></i> ' +
1088
+ graphData.edges.length + ' ' + t('graph.edges');
1089
+ if (window.lucide) lucide.createIcons();
1090
+ }
1091
+ }
1092
+
1093
+ // ========== Utility ==========
1094
+ function hideStatsAndCarousel() {
1095
+ var statsGrid = document.getElementById('statsGrid');
1096
+ var carousel = document.getElementById('carouselContainer');
1097
+ if (statsGrid) statsGrid.style.display = 'none';
1098
+ if (carousel) carousel.style.display = 'none';
1099
+ }
1100
+
1101
+ // ========== Cleanup Function ==========
1102
+ /**
1103
+ * Clean up Cytoscape instance to prevent memory leaks
1104
+ * Should be called when navigating away from the graph explorer view
1105
+ */
1106
+ function cleanupGraphExplorer() {
1107
+ if (cyInstance) {
1108
+ cyInstance.destroy();
1109
+ cyInstance = null;
1110
+ }
1111
+ selectedNode = null;
1112
+ searchProcessData = null;
1113
+ }
1114
+
1115
+ // ========== Scope Filter Actions ==========
1116
+ async function changeScopeMode(mode) {
1117
+ console.log('[Graph] Changing scope mode to:', mode);
1118
+ filterMode = mode;
1119
+ selectedFile = null;
1120
+ selectedModule = null;
1121
+
1122
+ // Re-render the filter panel
1123
+ var sidebar = document.querySelector('.graph-sidebar');
1124
+ if (sidebar) {
1125
+ var controlsSection = sidebar.querySelector('.graph-controls-section');
1126
+ if (controlsSection) {
1127
+ controlsSection.innerHTML = '<h3>' + t('graph.filters') + '</h3>' + renderFilterDropdowns();
1128
+ if (window.lucide) lucide.createIcons();
1129
+ }
1130
+ }
1131
+
1132
+ // If mode is 'all', reload graph immediately
1133
+ if (mode === 'all') {
1134
+ await refreshGraphData();
1135
+ }
1136
+ }
1137
+
1138
+ async function selectModule(modulePath) {
1139
+ console.log('[Graph] Selecting module:', modulePath);
1140
+ selectedModule = modulePath;
1141
+ if (modulePath) {
1142
+ await refreshGraphData();
1143
+ }
1144
+ }
1145
+
1146
+ async function selectFile(filePath) {
1147
+ console.log('[Graph] Selecting file:', filePath);
1148
+ selectedFile = filePath;
1149
+ if (filePath) {
1150
+ await refreshGraphData();
1151
+ }
1152
+ }
1153
+
1154
+ // Register cleanup on navigation (called by navigation.js before switching views)
1155
+ if (typeof window !== 'undefined') {
1156
+ window.cleanupGraphExplorer = cleanupGraphExplorer;
1157
+ }