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,576 @@
1
+ """SQLite storage for CodexLens indexing and search."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import sqlite3
7
+ import threading
8
+ import time
9
+ from dataclasses import asdict
10
+ from pathlib import Path
11
+ from typing import Any, Dict, Iterable, List, Optional, Tuple
12
+
13
+ from codexlens.entities import IndexedFile, SearchResult, Symbol
14
+ from codexlens.errors import StorageError
15
+
16
+
17
+ class SQLiteStore:
18
+ """SQLiteStore providing FTS5 search and symbol lookup.
19
+
20
+ Implements thread-local connection pooling for improved performance.
21
+ """
22
+
23
+ # Maximum number of connections to keep in pool to prevent memory leaks
24
+ MAX_POOL_SIZE = 32
25
+ # Idle timeout in seconds (10 minutes)
26
+ IDLE_TIMEOUT = 600
27
+
28
+ def __init__(self, db_path: str | Path) -> None:
29
+ self.db_path = Path(db_path)
30
+ self._lock = threading.RLock()
31
+ self._local = threading.local()
32
+ self._pool_lock = threading.Lock()
33
+ # Pool stores (connection, last_access_time) tuples
34
+ self._pool: Dict[int, Tuple[sqlite3.Connection, float]] = {}
35
+ self._pool_generation = 0
36
+
37
+ def _get_connection(self) -> sqlite3.Connection:
38
+ """Get or create a thread-local database connection."""
39
+ thread_id = threading.get_ident()
40
+ current_time = time.time()
41
+
42
+ if getattr(self._local, "generation", None) == self._pool_generation:
43
+ conn = getattr(self._local, "conn", None)
44
+ if conn is not None:
45
+ # Update last access time
46
+ with self._pool_lock:
47
+ if thread_id in self._pool:
48
+ self._pool[thread_id] = (conn, current_time)
49
+ return conn
50
+
51
+ with self._pool_lock:
52
+ pool_entry = self._pool.get(thread_id)
53
+ if pool_entry is not None:
54
+ conn, _ = pool_entry
55
+ # Update last access time
56
+ self._pool[thread_id] = (conn, current_time)
57
+ else:
58
+ # Clean up stale and idle connections if pool is too large
59
+ if len(self._pool) >= self.MAX_POOL_SIZE:
60
+ self._cleanup_stale_connections()
61
+
62
+ conn = sqlite3.connect(self.db_path, check_same_thread=False)
63
+ conn.row_factory = sqlite3.Row
64
+ conn.execute("PRAGMA journal_mode=WAL")
65
+ conn.execute("PRAGMA synchronous=NORMAL")
66
+ conn.execute("PRAGMA foreign_keys=ON")
67
+ # Memory-mapped I/O for faster reads (30GB limit)
68
+ conn.execute("PRAGMA mmap_size=30000000000")
69
+ self._pool[thread_id] = (conn, current_time)
70
+
71
+ self._local.conn = conn
72
+ self._local.generation = self._pool_generation
73
+ return conn
74
+
75
+ def _cleanup_stale_connections(self) -> None:
76
+ """Remove connections for threads that no longer exist or have been idle too long."""
77
+ current_time = time.time()
78
+ # Get list of active thread IDs
79
+ active_threads = {t.ident for t in threading.enumerate() if t.ident is not None}
80
+
81
+ # Find connections to remove: dead threads or idle timeout exceeded
82
+ stale_ids = []
83
+ for tid, (conn, last_access) in list(self._pool.items()):
84
+ is_dead_thread = tid not in active_threads
85
+ is_idle = (current_time - last_access) > self.IDLE_TIMEOUT
86
+ if is_dead_thread or is_idle:
87
+ stale_ids.append(tid)
88
+
89
+ # Close and remove stale connections
90
+ for tid in stale_ids:
91
+ try:
92
+ conn, _ = self._pool[tid]
93
+ conn.close()
94
+ except Exception:
95
+ pass
96
+ del self._pool[tid]
97
+
98
+ def close(self) -> None:
99
+ """Close all pooled connections."""
100
+ with self._lock:
101
+ with self._pool_lock:
102
+ for conn, _ in self._pool.values():
103
+ conn.close()
104
+ self._pool.clear()
105
+ self._pool_generation += 1
106
+
107
+ if hasattr(self._local, "conn"):
108
+ self._local.conn = None
109
+ if hasattr(self._local, "generation"):
110
+ self._local.generation = self._pool_generation
111
+
112
+ def __enter__(self) -> SQLiteStore:
113
+ self.initialize()
114
+ return self
115
+
116
+ def __exit__(self, exc_type: object, exc: object, tb: object) -> None:
117
+ self.close()
118
+
119
+ def execute_query(
120
+ self,
121
+ sql: str,
122
+ params: tuple = (),
123
+ allow_writes: bool = False
124
+ ) -> List[Dict[str, Any]]:
125
+ """Execute a raw SQL query and return results as dictionaries.
126
+
127
+ This is the public API for executing custom queries without bypassing
128
+ encapsulation via _get_connection().
129
+
130
+ By default, only SELECT queries are allowed. Use allow_writes=True
131
+ for trusted internal code that needs to execute other statements.
132
+
133
+ Args:
134
+ sql: SQL query string with ? placeholders for parameters
135
+ params: Tuple of parameter values to bind
136
+ allow_writes: If True, allow non-SELECT statements (default False)
137
+
138
+ Returns:
139
+ List of result rows as dictionaries
140
+
141
+ Raises:
142
+ StorageError: If query execution fails or validation fails
143
+ """
144
+ # Validate query type for security
145
+ sql_stripped = sql.strip().upper()
146
+ if not allow_writes:
147
+ # Only allow SELECT and WITH (for CTEs) statements
148
+ if not (sql_stripped.startswith("SELECT") or sql_stripped.startswith("WITH")):
149
+ raise StorageError(
150
+ "Only SELECT queries are allowed. "
151
+ "Use allow_writes=True for trusted internal operations.",
152
+ db_path=str(self.db_path),
153
+ operation="execute_query",
154
+ details={"query_type": sql_stripped.split()[0] if sql_stripped else "EMPTY"}
155
+ )
156
+
157
+ try:
158
+ conn = self._get_connection()
159
+ rows = conn.execute(sql, params).fetchall()
160
+ return [dict(row) for row in rows]
161
+ except sqlite3.Error as e:
162
+ raise StorageError(
163
+ f"Query execution failed: {e}",
164
+ db_path=str(self.db_path),
165
+ operation="execute_query",
166
+ details={"error_type": type(e).__name__}
167
+ ) from e
168
+
169
+ def initialize(self) -> None:
170
+ with self._lock:
171
+ self.db_path.parent.mkdir(parents=True, exist_ok=True)
172
+ conn = self._get_connection()
173
+ self._create_schema(conn)
174
+ self._ensure_fts_external_content(conn)
175
+
176
+
177
+ def add_file(self, indexed_file: IndexedFile, content: str) -> None:
178
+ with self._lock:
179
+ conn = self._get_connection()
180
+ path = str(Path(indexed_file.path).resolve())
181
+ language = indexed_file.language
182
+ mtime = Path(path).stat().st_mtime if Path(path).exists() else None
183
+ line_count = content.count(chr(10)) + 1
184
+
185
+ conn.execute(
186
+ """
187
+ INSERT INTO files(path, language, content, mtime, line_count)
188
+ VALUES(?, ?, ?, ?, ?)
189
+ ON CONFLICT(path) DO UPDATE SET
190
+ language=excluded.language,
191
+ content=excluded.content,
192
+ mtime=excluded.mtime,
193
+ line_count=excluded.line_count
194
+ """,
195
+ (path, language, content, mtime, line_count),
196
+ )
197
+
198
+ row = conn.execute("SELECT id FROM files WHERE path=?", (path,)).fetchone()
199
+ if not row:
200
+ raise StorageError(f"Failed to read file id for {path}")
201
+ file_id = int(row["id"])
202
+
203
+ conn.execute("DELETE FROM symbols WHERE file_id=?", (file_id,))
204
+ if indexed_file.symbols:
205
+ conn.executemany(
206
+ """
207
+ INSERT INTO symbols(file_id, name, kind, start_line, end_line)
208
+ VALUES(?, ?, ?, ?, ?)
209
+ """,
210
+ [
211
+ (file_id, s.name, s.kind, s.range[0], s.range[1])
212
+ for s in indexed_file.symbols
213
+ ],
214
+ )
215
+ conn.commit()
216
+
217
+ def add_files(self, files_data: List[tuple[IndexedFile, str]]) -> None:
218
+ """Add multiple files in a single transaction for better performance.
219
+
220
+ Args:
221
+ files_data: List of (indexed_file, content) tuples
222
+ """
223
+ with self._lock:
224
+ conn = self._get_connection()
225
+ try:
226
+ conn.execute("BEGIN")
227
+
228
+ for indexed_file, content in files_data:
229
+ path = str(Path(indexed_file.path).resolve())
230
+ language = indexed_file.language
231
+ mtime = Path(path).stat().st_mtime if Path(path).exists() else None
232
+ line_count = content.count(chr(10)) + 1
233
+
234
+ conn.execute(
235
+ """
236
+ INSERT INTO files(path, language, content, mtime, line_count)
237
+ VALUES(?, ?, ?, ?, ?)
238
+ ON CONFLICT(path) DO UPDATE SET
239
+ language=excluded.language,
240
+ content=excluded.content,
241
+ mtime=excluded.mtime,
242
+ line_count=excluded.line_count
243
+ """,
244
+ (path, language, content, mtime, line_count),
245
+ )
246
+
247
+ row = conn.execute("SELECT id FROM files WHERE path=?", (path,)).fetchone()
248
+ if not row:
249
+ raise StorageError(f"Failed to read file id for {path}")
250
+ file_id = int(row["id"])
251
+
252
+ conn.execute("DELETE FROM symbols WHERE file_id=?", (file_id,))
253
+ if indexed_file.symbols:
254
+ conn.executemany(
255
+ """
256
+ INSERT INTO symbols(file_id, name, kind, start_line, end_line)
257
+ VALUES(?, ?, ?, ?, ?)
258
+ """,
259
+ [
260
+ (file_id, s.name, s.kind, s.range[0], s.range[1])
261
+ for s in indexed_file.symbols
262
+ ],
263
+ )
264
+
265
+ conn.commit()
266
+ except Exception:
267
+ conn.rollback()
268
+ raise
269
+
270
+ def remove_file(self, path: str | Path) -> bool:
271
+ """Remove a file from the index."""
272
+ with self._lock:
273
+ conn = self._get_connection()
274
+ resolved_path = str(Path(path).resolve())
275
+
276
+ row = conn.execute(
277
+ "SELECT id FROM files WHERE path=?", (resolved_path,)
278
+ ).fetchone()
279
+
280
+ if not row:
281
+ return False
282
+
283
+ file_id = int(row["id"])
284
+ conn.execute("DELETE FROM files WHERE id=?", (file_id,))
285
+ conn.commit()
286
+ return True
287
+
288
+ def file_exists(self, path: str | Path) -> bool:
289
+ """Check if a file exists in the index."""
290
+ with self._lock:
291
+ conn = self._get_connection()
292
+ resolved_path = str(Path(path).resolve())
293
+ row = conn.execute(
294
+ "SELECT 1 FROM files WHERE path=?", (resolved_path,)
295
+ ).fetchone()
296
+ return row is not None
297
+
298
+ def get_file_mtime(self, path: str | Path) -> float | None:
299
+ """Get the stored mtime for a file."""
300
+ with self._lock:
301
+ conn = self._get_connection()
302
+ resolved_path = str(Path(path).resolve())
303
+ row = conn.execute(
304
+ "SELECT mtime FROM files WHERE path=?", (resolved_path,)
305
+ ).fetchone()
306
+ return float(row["mtime"]) if row and row["mtime"] else None
307
+
308
+
309
+ def search_fts(self, query: str, *, limit: int = 20, offset: int = 0) -> List[SearchResult]:
310
+ with self._lock:
311
+ conn = self._get_connection()
312
+ try:
313
+ rows = conn.execute(
314
+ """
315
+ SELECT rowid, path, bm25(files_fts) AS rank,
316
+ snippet(files_fts, 2, '[bold red]', '[/bold red]', "...", 20) AS excerpt
317
+ FROM files_fts
318
+ WHERE files_fts MATCH ?
319
+ ORDER BY rank
320
+ LIMIT ? OFFSET ?
321
+ """,
322
+ (query, limit, offset),
323
+ ).fetchall()
324
+ except sqlite3.DatabaseError as exc:
325
+ raise StorageError(f"FTS search failed: {exc}") from exc
326
+
327
+ results: List[SearchResult] = []
328
+ for row in rows:
329
+ rank = float(row["rank"]) if row["rank"] is not None else 0.0
330
+ score = abs(rank) if rank < 0 else 0.0
331
+ results.append(
332
+ SearchResult(
333
+ path=row["path"],
334
+ score=score,
335
+ excerpt=row["excerpt"],
336
+ )
337
+ )
338
+ return results
339
+
340
+ def search_files_only(
341
+ self, query: str, *, limit: int = 20, offset: int = 0
342
+ ) -> List[str]:
343
+ """Search indexed file contents and return only file paths."""
344
+ with self._lock:
345
+ conn = self._get_connection()
346
+ try:
347
+ rows = conn.execute(
348
+ """
349
+ SELECT path
350
+ FROM files_fts
351
+ WHERE files_fts MATCH ?
352
+ ORDER BY bm25(files_fts)
353
+ LIMIT ? OFFSET ?
354
+ """,
355
+ (query, limit, offset),
356
+ ).fetchall()
357
+ except sqlite3.DatabaseError as exc:
358
+ raise StorageError(f"FTS search failed: {exc}") from exc
359
+
360
+ return [row["path"] for row in rows]
361
+
362
+ def search_symbols(
363
+ self, name: str, *, kind: Optional[str] = None, limit: int = 50
364
+ ) -> List[Symbol]:
365
+ pattern = f"%{name}%"
366
+ with self._lock:
367
+ conn = self._get_connection()
368
+ if kind:
369
+ rows = conn.execute(
370
+ """
371
+ SELECT name, kind, start_line, end_line
372
+ FROM symbols
373
+ WHERE name LIKE ? AND kind=?
374
+ ORDER BY name
375
+ LIMIT ?
376
+ """,
377
+ (pattern, kind, limit),
378
+ ).fetchall()
379
+ else:
380
+ rows = conn.execute(
381
+ """
382
+ SELECT name, kind, start_line, end_line
383
+ FROM symbols
384
+ WHERE name LIKE ?
385
+ ORDER BY name
386
+ LIMIT ?
387
+ """,
388
+ (pattern, limit),
389
+ ).fetchall()
390
+
391
+ return [
392
+ Symbol(name=row["name"], kind=row["kind"], range=(row["start_line"], row["end_line"]))
393
+ for row in rows
394
+ ]
395
+
396
+
397
+ def stats(self) -> Dict[str, Any]:
398
+ with self._lock:
399
+ conn = self._get_connection()
400
+ file_count = conn.execute("SELECT COUNT(*) AS c FROM files").fetchone()["c"]
401
+ symbol_count = conn.execute("SELECT COUNT(*) AS c FROM symbols").fetchone()["c"]
402
+ lang_rows = conn.execute(
403
+ "SELECT language, COUNT(*) AS c FROM files GROUP BY language ORDER BY c DESC"
404
+ ).fetchall()
405
+ languages = {row["language"]: row["c"] for row in lang_rows}
406
+ # Include relationship count if table exists
407
+ relationship_count = 0
408
+ try:
409
+ rel_row = conn.execute("SELECT COUNT(*) AS c FROM code_relationships").fetchone()
410
+ relationship_count = int(rel_row["c"]) if rel_row else 0
411
+ except sqlite3.DatabaseError:
412
+ pass
413
+
414
+ return {
415
+ "files": int(file_count),
416
+ "symbols": int(symbol_count),
417
+ "relationships": relationship_count,
418
+ "languages": languages,
419
+ "db_path": str(self.db_path),
420
+ }
421
+
422
+
423
+ def _connect(self) -> sqlite3.Connection:
424
+ """Legacy method for backward compatibility."""
425
+ return self._get_connection()
426
+
427
+ def _create_schema(self, conn: sqlite3.Connection) -> None:
428
+ try:
429
+ conn.execute(
430
+ """
431
+ CREATE TABLE IF NOT EXISTS files (
432
+ id INTEGER PRIMARY KEY,
433
+ path TEXT UNIQUE NOT NULL,
434
+ language TEXT NOT NULL,
435
+ content TEXT NOT NULL,
436
+ mtime REAL,
437
+ line_count INTEGER
438
+ )
439
+ """
440
+ )
441
+ conn.execute(
442
+ """
443
+ CREATE TABLE IF NOT EXISTS symbols (
444
+ id INTEGER PRIMARY KEY,
445
+ file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,
446
+ name TEXT NOT NULL,
447
+ kind TEXT NOT NULL,
448
+ start_line INTEGER NOT NULL,
449
+ end_line INTEGER NOT NULL
450
+ )
451
+ """
452
+ )
453
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name)")
454
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_symbols_kind ON symbols(kind)")
455
+ conn.execute(
456
+ """
457
+ CREATE TABLE IF NOT EXISTS code_relationships (
458
+ id INTEGER PRIMARY KEY,
459
+ source_symbol_id INTEGER NOT NULL REFERENCES symbols(id) ON DELETE CASCADE,
460
+ target_qualified_name TEXT NOT NULL,
461
+ relationship_type TEXT NOT NULL,
462
+ source_line INTEGER NOT NULL,
463
+ target_file TEXT
464
+ )
465
+ """
466
+ )
467
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_rel_target ON code_relationships(target_qualified_name)")
468
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_rel_source ON code_relationships(source_symbol_id)")
469
+ conn.commit()
470
+ except sqlite3.DatabaseError as exc:
471
+ raise StorageError(f"Failed to initialize database schema: {exc}") from exc
472
+
473
+ def _ensure_fts_external_content(self, conn: sqlite3.Connection) -> None:
474
+ """Ensure files_fts is an FTS5 external-content table (no content duplication)."""
475
+ try:
476
+ sql_row = conn.execute(
477
+ "SELECT sql FROM sqlite_master WHERE type='table' AND name='files_fts'"
478
+ ).fetchone()
479
+ sql = str(sql_row["sql"]) if sql_row and sql_row["sql"] else None
480
+
481
+ if sql is None:
482
+ self._create_external_fts(conn)
483
+ conn.commit()
484
+ return
485
+
486
+ if (
487
+ "content='files'" in sql
488
+ or 'content="files"' in sql
489
+ or "content=files" in sql
490
+ ):
491
+ self._create_fts_triggers(conn)
492
+ conn.commit()
493
+ return
494
+
495
+ self._migrate_fts_to_external(conn)
496
+ except sqlite3.DatabaseError as exc:
497
+ raise StorageError(f"Failed to ensure FTS schema: {exc}") from exc
498
+
499
+ def _create_external_fts(self, conn: sqlite3.Connection) -> None:
500
+ conn.execute(
501
+ """
502
+ CREATE VIRTUAL TABLE files_fts USING fts5(
503
+ path UNINDEXED,
504
+ language UNINDEXED,
505
+ content,
506
+ content='files',
507
+ content_rowid='id',
508
+ tokenize="unicode61 tokenchars '_'"
509
+ )
510
+ """
511
+ )
512
+ self._create_fts_triggers(conn)
513
+
514
+ def _create_fts_triggers(self, conn: sqlite3.Connection) -> None:
515
+ conn.execute(
516
+ """
517
+ CREATE TRIGGER IF NOT EXISTS files_ai AFTER INSERT ON files BEGIN
518
+ INSERT INTO files_fts(rowid, path, language, content)
519
+ VALUES(new.id, new.path, new.language, new.content);
520
+ END
521
+ """
522
+ )
523
+ conn.execute(
524
+ """
525
+ CREATE TRIGGER IF NOT EXISTS files_ad AFTER DELETE ON files BEGIN
526
+ INSERT INTO files_fts(files_fts, rowid, path, language, content)
527
+ VALUES('delete', old.id, old.path, old.language, old.content);
528
+ END
529
+ """
530
+ )
531
+ conn.execute(
532
+ """
533
+ CREATE TRIGGER IF NOT EXISTS files_au AFTER UPDATE ON files BEGIN
534
+ INSERT INTO files_fts(files_fts, rowid, path, language, content)
535
+ VALUES('delete', old.id, old.path, old.language, old.content);
536
+ INSERT INTO files_fts(rowid, path, language, content)
537
+ VALUES(new.id, new.path, new.language, new.content);
538
+ END
539
+ """
540
+ )
541
+
542
+ def _migrate_fts_to_external(self, conn: sqlite3.Connection) -> None:
543
+ """Migrate legacy files_fts (with duplicated content) to external content."""
544
+ try:
545
+ conn.execute("BEGIN")
546
+ conn.execute("DROP TRIGGER IF EXISTS files_ai")
547
+ conn.execute("DROP TRIGGER IF EXISTS files_ad")
548
+ conn.execute("DROP TRIGGER IF EXISTS files_au")
549
+
550
+ conn.execute("ALTER TABLE files_fts RENAME TO files_fts_legacy")
551
+ self._create_external_fts(conn)
552
+ conn.execute("INSERT INTO files_fts(files_fts) VALUES('rebuild')")
553
+ conn.execute("DROP TABLE files_fts_legacy")
554
+ conn.commit()
555
+ except sqlite3.DatabaseError:
556
+ try:
557
+ conn.rollback()
558
+ except Exception:
559
+ pass
560
+
561
+ try:
562
+ conn.execute("DROP TABLE IF EXISTS files_fts")
563
+ except Exception:
564
+ pass
565
+
566
+ try:
567
+ conn.execute("ALTER TABLE files_fts_legacy RENAME TO files_fts")
568
+ conn.commit()
569
+ except Exception:
570
+ pass
571
+ raise
572
+
573
+ try:
574
+ conn.execute("VACUUM")
575
+ except sqlite3.DatabaseError:
576
+ pass
@@ -0,0 +1,64 @@
1
+ """SQLite utility functions for CodexLens storage layer."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import sqlite3
7
+
8
+ log = logging.getLogger(__name__)
9
+
10
+
11
+ def check_trigram_support(conn: sqlite3.Connection) -> bool:
12
+ """Check if SQLite supports trigram tokenizer for FTS5.
13
+
14
+ Trigram tokenizer requires SQLite >= 3.34.0.
15
+
16
+ Args:
17
+ conn: Database connection to test
18
+
19
+ Returns:
20
+ True if trigram tokenizer is available, False otherwise
21
+ """
22
+ try:
23
+ # Test by creating a temporary virtual table with trigram tokenizer
24
+ conn.execute(
25
+ """
26
+ CREATE VIRTUAL TABLE IF NOT EXISTS test_trigram_check
27
+ USING fts5(test_content, tokenize='trigram')
28
+ """
29
+ )
30
+ # Clean up test table
31
+ conn.execute("DROP TABLE IF EXISTS test_trigram_check")
32
+ conn.commit()
33
+ return True
34
+ except sqlite3.OperationalError as e:
35
+ # Trigram tokenizer not available
36
+ if "unrecognized tokenizer" in str(e).lower():
37
+ log.debug("Trigram tokenizer not available in this SQLite version")
38
+ return False
39
+ # Other operational errors should be re-raised
40
+ raise
41
+ except Exception:
42
+ # Any other exception means trigram is not supported
43
+ return False
44
+
45
+
46
+ def get_sqlite_version(conn: sqlite3.Connection) -> tuple[int, int, int]:
47
+ """Get SQLite version as (major, minor, patch) tuple.
48
+
49
+ Args:
50
+ conn: Database connection
51
+
52
+ Returns:
53
+ Version tuple, e.g., (3, 34, 1)
54
+ """
55
+ row = conn.execute("SELECT sqlite_version()").fetchone()
56
+ version_str = row[0] if row else "0.0.0"
57
+ parts = version_str.split('.')
58
+ try:
59
+ major = int(parts[0]) if len(parts) > 0 else 0
60
+ minor = int(parts[1]) if len(parts) > 1 else 0
61
+ patch = int(parts[2]) if len(parts) > 2 else 0
62
+ return (major, minor, patch)
63
+ except (ValueError, IndexError):
64
+ return (0, 0, 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-workflow",
3
- "version": "6.1.4",
3
+ "version": "6.2.2",
4
4
  "description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
5
5
  "type": "module",
6
6
  "main": "ccw/src/index.js",
@@ -40,6 +40,7 @@
40
40
  },
41
41
  "files": [
42
42
  "ccw/bin/",
43
+ "ccw/dist/",
43
44
  "ccw/src/",
44
45
  "ccw/package.json",
45
46
  ".claude/agents/",
@@ -53,6 +54,8 @@
53
54
  ".codex/",
54
55
  ".gemini/",
55
56
  ".qwen/",
57
+ "codex-lens/src/codexlens/",
58
+ "codex-lens/pyproject.toml",
56
59
  "CLAUDE.md",
57
60
  "README.md"
58
61
  ],