claude-code-workflow 6.3.18 → 6.3.20

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 (832) hide show
  1. package/.claude/CLAUDE.md +8 -5
  2. package/.claude/agents/action-planning-agent.md +26 -2
  3. package/.claude/agents/code-developer.md +132 -43
  4. package/.claude/agents/debug-explore-agent.md +434 -0
  5. package/.claude/agents/issue-plan-agent.md +31 -2
  6. package/.claude/agents/test-fix-agent.md +14 -0
  7. package/.claude/commands/issue/discover.md +41 -0
  8. package/.claude/commands/issue/execute.md +200 -19
  9. package/.claude/commands/issue/new.md +93 -3
  10. package/.claude/commands/issue/plan.md +9 -3
  11. package/.claude/commands/issue/queue.md +94 -39
  12. package/.claude/commands/memory/swagger-docs.md +773 -0
  13. package/.claude/commands/workflow/brainstorm/auto-parallel.md +21 -21
  14. package/.claude/commands/workflow/execute.md +54 -34
  15. package/.claude/commands/workflow/lite-execute.md +48 -164
  16. package/.claude/commands/workflow/lite-fix.md +4 -4
  17. package/.claude/commands/workflow/lite-plan.md +5 -5
  18. package/.claude/commands/workflow/plan.md +27 -27
  19. package/.claude/commands/workflow/review.md +42 -17
  20. package/.claude/commands/workflow/tdd-plan.md +25 -25
  21. package/.claude/commands/workflow/test-fix-gen.md +10 -10
  22. package/.claude/commands/workflow/test-gen.md +14 -14
  23. package/.claude/commands/workflow/ui-design/explore-auto.md +21 -21
  24. package/.claude/commands/workflow/ui-design/imitate-auto.md +24 -24
  25. package/.claude/skills/_shared/SKILL-DESIGN-SPEC.md +693 -0
  26. package/.claude/skills/ccw/SKILL.md +462 -0
  27. package/.claude/skills/ccw/index/command-capabilities.json +127 -0
  28. package/.claude/skills/ccw/index/intent-rules.json +136 -0
  29. package/.claude/skills/ccw/index/workflow-chains.json +451 -0
  30. package/.claude/skills/ccw/phases/actions/bugfix.md +218 -0
  31. package/.claude/skills/ccw/phases/actions/coupled.md +194 -0
  32. package/.claude/skills/ccw/phases/actions/docs.md +93 -0
  33. package/.claude/skills/ccw/phases/actions/full.md +154 -0
  34. package/.claude/skills/ccw/phases/actions/issue.md +201 -0
  35. package/.claude/skills/ccw/phases/actions/rapid.md +104 -0
  36. package/.claude/skills/ccw/phases/actions/review-fix.md +84 -0
  37. package/.claude/skills/ccw/phases/actions/tdd.md +66 -0
  38. package/.claude/skills/ccw/phases/actions/ui.md +79 -0
  39. package/.claude/skills/ccw/phases/orchestrator.md +435 -0
  40. package/.claude/skills/ccw/specs/intent-classification.md +336 -0
  41. package/.claude/skills/ccw-help/SKILL.md +177 -0
  42. package/.claude/skills/ccw-help/index/all-agents.json +82 -0
  43. package/.claude/skills/{command-guide → ccw-help}/index/all-commands.json +183 -73
  44. package/.claude/skills/{command-guide → ccw-help}/index/by-category.json +187 -73
  45. package/.claude/skills/{command-guide → ccw-help}/index/by-use-case.json +295 -185
  46. package/.claude/skills/{command-guide → ccw-help}/index/command-relationships.json +19 -166
  47. package/.claude/skills/{command-guide → ccw-help}/index/essential-commands.json +10 -10
  48. package/.claude/skills/ccw-help/scripts/analyze_commands.py +337 -0
  49. package/.claude/skills/code-reviewer/README.md +340 -0
  50. package/.claude/skills/code-reviewer/SKILL.md +308 -0
  51. package/.claude/skills/code-reviewer/phases/01-code-discovery.md +246 -0
  52. package/.claude/skills/code-reviewer/phases/02-security-analysis.md +442 -0
  53. package/.claude/skills/code-reviewer/phases/03-best-practices-review.md +36 -0
  54. package/.claude/skills/code-reviewer/phases/04-report-generation.md +278 -0
  55. package/.claude/skills/code-reviewer/specs/best-practices-requirements.md +346 -0
  56. package/.claude/skills/code-reviewer/specs/quality-standards.md +252 -0
  57. package/.claude/skills/code-reviewer/specs/security-requirements.md +243 -0
  58. package/.claude/skills/code-reviewer/templates/best-practice-finding.md +234 -0
  59. package/.claude/skills/code-reviewer/templates/report-template.md +316 -0
  60. package/.claude/skills/code-reviewer/templates/security-finding.md +161 -0
  61. package/.claude/skills/skill-generator/SKILL.md +187 -0
  62. package/.claude/skills/skill-generator/phases/01-requirements-discovery.md +239 -0
  63. package/.claude/skills/skill-generator/phases/02-structure-generation.md +207 -0
  64. package/.claude/skills/skill-generator/phases/03-phase-generation.md +802 -0
  65. package/.claude/skills/skill-generator/phases/04-specs-templates.md +328 -0
  66. package/.claude/skills/skill-generator/phases/05-validation.md +334 -0
  67. package/.claude/skills/skill-generator/specs/cli-integration.md +448 -0
  68. package/.claude/skills/skill-generator/specs/execution-modes.md +396 -0
  69. package/.claude/skills/skill-generator/specs/scripting-integration.md +265 -0
  70. package/.claude/skills/skill-generator/specs/skill-requirements.md +466 -0
  71. package/.claude/skills/skill-generator/templates/autonomous-action.md +517 -0
  72. package/.claude/skills/skill-generator/templates/autonomous-orchestrator.md +276 -0
  73. package/.claude/skills/skill-generator/templates/code-analysis-action.md +503 -0
  74. package/.claude/skills/skill-generator/templates/llm-action.md +355 -0
  75. package/.claude/skills/skill-generator/templates/script-bash.md +277 -0
  76. package/.claude/skills/skill-generator/templates/script-python.md +198 -0
  77. package/.claude/skills/skill-generator/templates/sequential-phase.md +441 -0
  78. package/.claude/skills/skill-generator/templates/skill-md.md +156 -0
  79. package/.claude/workflows/chinese-response.md +15 -28
  80. package/.claude/workflows/cli-templates/prompts/documentation/swagger-api.txt +266 -0
  81. package/.claude/workflows/cli-tools-usage.md +221 -177
  82. package/.claude/workflows/windows-platform.md +13 -10
  83. package/.codex/prompts/issue-execute.md +310 -82
  84. package/.codex/prompts/issue-queue.md +22 -0
  85. package/.codex/prompts/lite-execute.md +36 -11
  86. package/README.md +309 -305
  87. package/ccw/README.md +10 -4
  88. package/ccw/dist/cli.d.ts.map +1 -1
  89. package/ccw/dist/cli.js +4 -1
  90. package/ccw/dist/cli.js.map +1 -1
  91. package/ccw/dist/commands/cli.d.ts.map +1 -1
  92. package/ccw/dist/commands/cli.js +131 -34
  93. package/ccw/dist/commands/cli.js.map +1 -1
  94. package/ccw/dist/commands/issue.d.ts +152 -0
  95. package/ccw/dist/commands/issue.d.ts.map +1 -1
  96. package/ccw/dist/commands/issue.js +550 -85
  97. package/ccw/dist/commands/issue.js.map +1 -1
  98. package/ccw/dist/commands/serve.d.ts +1 -0
  99. package/ccw/dist/commands/serve.d.ts.map +1 -1
  100. package/ccw/dist/commands/serve.js +12 -5
  101. package/ccw/dist/commands/serve.js.map +1 -1
  102. package/ccw/dist/commands/stop.d.ts.map +1 -1
  103. package/ccw/dist/commands/stop.js +29 -5
  104. package/ccw/dist/commands/stop.js.map +1 -1
  105. package/ccw/dist/commands/tool.d.ts.map +1 -1
  106. package/ccw/dist/commands/tool.js +19 -2
  107. package/ccw/dist/commands/tool.js.map +1 -1
  108. package/ccw/dist/commands/view.d.ts +1 -0
  109. package/ccw/dist/commands/view.d.ts.map +1 -1
  110. package/ccw/dist/commands/view.js +10 -3
  111. package/ccw/dist/commands/view.js.map +1 -1
  112. package/ccw/dist/config/cli-settings-manager.d.ts +86 -0
  113. package/ccw/dist/config/cli-settings-manager.d.ts.map +1 -0
  114. package/ccw/dist/config/cli-settings-manager.js +392 -0
  115. package/ccw/dist/config/cli-settings-manager.js.map +1 -0
  116. package/ccw/dist/config/litellm-api-config-manager.d.ts +71 -5
  117. package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -1
  118. package/ccw/dist/config/litellm-api-config-manager.js +290 -20
  119. package/ccw/dist/config/litellm-api-config-manager.js.map +1 -1
  120. package/ccw/dist/core/auth/csrf-manager.d.ts +18 -0
  121. package/ccw/dist/core/auth/csrf-manager.d.ts.map +1 -0
  122. package/ccw/dist/core/auth/csrf-manager.js +80 -0
  123. package/ccw/dist/core/auth/csrf-manager.js.map +1 -0
  124. package/ccw/dist/core/auth/csrf-middleware.d.ts +8 -0
  125. package/ccw/dist/core/auth/csrf-middleware.d.ts.map +1 -0
  126. package/ccw/dist/core/auth/csrf-middleware.js +141 -0
  127. package/ccw/dist/core/auth/csrf-middleware.js.map +1 -0
  128. package/ccw/dist/core/auth/middleware.d.ts +15 -0
  129. package/ccw/dist/core/auth/middleware.d.ts.map +1 -0
  130. package/ccw/dist/core/auth/middleware.js +76 -0
  131. package/ccw/dist/core/auth/middleware.js.map +1 -0
  132. package/ccw/dist/core/auth/token-manager.d.ts +41 -0
  133. package/ccw/dist/core/auth/token-manager.d.ts.map +1 -0
  134. package/ccw/dist/core/auth/token-manager.js +171 -0
  135. package/ccw/dist/core/auth/token-manager.js.map +1 -0
  136. package/ccw/dist/core/cache-manager.d.ts +6 -6
  137. package/ccw/dist/core/cache-manager.d.ts.map +1 -1
  138. package/ccw/dist/core/cache-manager.js +70 -48
  139. package/ccw/dist/core/cache-manager.js.map +1 -1
  140. package/ccw/dist/core/claude-freshness.d.ts.map +1 -1
  141. package/ccw/dist/core/claude-freshness.js +23 -3
  142. package/ccw/dist/core/claude-freshness.js.map +1 -1
  143. package/ccw/dist/core/core-memory-store.d.ts.map +1 -1
  144. package/ccw/dist/core/core-memory-store.js +2 -1
  145. package/ccw/dist/core/core-memory-store.js.map +1 -1
  146. package/ccw/dist/core/cors.d.ts +3 -0
  147. package/ccw/dist/core/cors.d.ts.map +1 -0
  148. package/ccw/dist/core/cors.js +10 -0
  149. package/ccw/dist/core/cors.js.map +1 -0
  150. package/ccw/dist/core/dashboard-generator-patch.js +0 -1
  151. package/ccw/dist/core/dashboard-generator-patch.js.map +1 -1
  152. package/ccw/dist/core/dashboard-generator.d.ts.map +1 -1
  153. package/ccw/dist/core/dashboard-generator.js +417 -416
  154. package/ccw/dist/core/dashboard-generator.js.map +1 -1
  155. package/ccw/dist/core/data-aggregator.js +2 -2
  156. package/ccw/dist/core/data-aggregator.js.map +1 -1
  157. package/ccw/dist/core/lite-scanner.d.ts +1 -1
  158. package/ccw/dist/core/lite-scanner.d.ts.map +1 -1
  159. package/ccw/dist/core/lite-scanner.js +130 -127
  160. package/ccw/dist/core/lite-scanner.js.map +1 -1
  161. package/ccw/dist/core/routes/auth-routes.d.ts +12 -0
  162. package/ccw/dist/core/routes/auth-routes.d.ts.map +1 -0
  163. package/ccw/dist/core/routes/auth-routes.js +80 -0
  164. package/ccw/dist/core/routes/auth-routes.js.map +1 -0
  165. package/ccw/dist/core/routes/ccw-routes.d.ts +1 -14
  166. package/ccw/dist/core/routes/ccw-routes.d.ts.map +1 -1
  167. package/ccw/dist/core/routes/ccw-routes.js +9 -4
  168. package/ccw/dist/core/routes/ccw-routes.js.map +1 -1
  169. package/ccw/dist/core/routes/claude-routes.d.ts +1 -14
  170. package/ccw/dist/core/routes/claude-routes.d.ts.map +1 -1
  171. package/ccw/dist/core/routes/claude-routes.js +98 -39
  172. package/ccw/dist/core/routes/claude-routes.js.map +1 -1
  173. package/ccw/dist/core/routes/cli-routes.d.ts +14 -12
  174. package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -1
  175. package/ccw/dist/core/routes/cli-routes.js +122 -43
  176. package/ccw/dist/core/routes/cli-routes.js.map +1 -1
  177. package/ccw/dist/core/routes/cli-settings-routes.d.ts +11 -0
  178. package/ccw/dist/core/routes/cli-settings-routes.d.ts.map +1 -0
  179. package/ccw/dist/core/routes/cli-settings-routes.js +204 -0
  180. package/ccw/dist/core/routes/cli-settings-routes.js.map +1 -0
  181. package/ccw/dist/core/routes/codexlens/config-handlers.d.ts +6 -0
  182. package/ccw/dist/core/routes/codexlens/config-handlers.d.ts.map +1 -0
  183. package/ccw/dist/core/routes/codexlens/config-handlers.js +1195 -0
  184. package/ccw/dist/core/routes/codexlens/config-handlers.js.map +1 -0
  185. package/ccw/dist/core/routes/codexlens/index-handlers.d.ts +10 -0
  186. package/ccw/dist/core/routes/codexlens/index-handlers.d.ts.map +1 -0
  187. package/ccw/dist/core/routes/codexlens/index-handlers.js +322 -0
  188. package/ccw/dist/core/routes/codexlens/index-handlers.js.map +1 -0
  189. package/ccw/dist/core/routes/codexlens/semantic-handlers.d.ts +6 -0
  190. package/ccw/dist/core/routes/codexlens/semantic-handlers.d.ts.map +1 -0
  191. package/ccw/dist/core/routes/codexlens/semantic-handlers.js +865 -0
  192. package/ccw/dist/core/routes/codexlens/semantic-handlers.js.map +1 -0
  193. package/ccw/dist/core/routes/codexlens/utils.d.ts +23 -0
  194. package/ccw/dist/core/routes/codexlens/utils.d.ts.map +1 -0
  195. package/ccw/dist/core/routes/codexlens/utils.js +85 -0
  196. package/ccw/dist/core/routes/codexlens/utils.js.map +1 -0
  197. package/ccw/dist/core/routes/codexlens/watcher-handlers.d.ts +13 -0
  198. package/ccw/dist/core/routes/codexlens/watcher-handlers.d.ts.map +1 -0
  199. package/ccw/dist/core/routes/codexlens/watcher-handlers.js +235 -0
  200. package/ccw/dist/core/routes/codexlens/watcher-handlers.js.map +1 -0
  201. package/ccw/dist/core/routes/codexlens-routes.d.ts +2 -11
  202. package/ccw/dist/core/routes/codexlens-routes.d.ts.map +1 -1
  203. package/ccw/dist/core/routes/codexlens-routes.js +10 -981
  204. package/ccw/dist/core/routes/codexlens-routes.js.map +1 -1
  205. package/ccw/dist/core/routes/discovery-routes.d.ts +1 -35
  206. package/ccw/dist/core/routes/discovery-routes.d.ts.map +1 -1
  207. package/ccw/dist/core/routes/discovery-routes.js +25 -0
  208. package/ccw/dist/core/routes/discovery-routes.js.map +1 -1
  209. package/ccw/dist/core/routes/files-routes.d.ts +1 -14
  210. package/ccw/dist/core/routes/files-routes.d.ts.map +1 -1
  211. package/ccw/dist/core/routes/files-routes.js +57 -14
  212. package/ccw/dist/core/routes/files-routes.js.map +1 -1
  213. package/ccw/dist/core/routes/graph-routes.d.ts +1 -14
  214. package/ccw/dist/core/routes/graph-routes.d.ts.map +1 -1
  215. package/ccw/dist/core/routes/graph-routes.js +36 -37
  216. package/ccw/dist/core/routes/graph-routes.js.map +1 -1
  217. package/ccw/dist/core/routes/help-routes.d.ts +1 -14
  218. package/ccw/dist/core/routes/help-routes.d.ts.map +1 -1
  219. package/ccw/dist/core/routes/help-routes.js +5 -0
  220. package/ccw/dist/core/routes/help-routes.js.map +1 -1
  221. package/ccw/dist/core/routes/hooks-routes.d.ts +4 -14
  222. package/ccw/dist/core/routes/hooks-routes.d.ts.map +1 -1
  223. package/ccw/dist/core/routes/hooks-routes.js +43 -21
  224. package/ccw/dist/core/routes/hooks-routes.js.map +1 -1
  225. package/ccw/dist/core/routes/issue-routes.d.ts +1 -34
  226. package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
  227. package/ccw/dist/core/routes/issue-routes.js +24 -0
  228. package/ccw/dist/core/routes/issue-routes.js.map +1 -1
  229. package/ccw/dist/core/routes/litellm-api-routes.d.ts +1 -14
  230. package/ccw/dist/core/routes/litellm-api-routes.d.ts.map +1 -1
  231. package/ccw/dist/core/routes/litellm-api-routes.js +513 -48
  232. package/ccw/dist/core/routes/litellm-api-routes.js.map +1 -1
  233. package/ccw/dist/core/routes/litellm-routes.d.ts +1 -14
  234. package/ccw/dist/core/routes/litellm-routes.d.ts.map +1 -1
  235. package/ccw/dist/core/routes/litellm-routes.js +28 -11
  236. package/ccw/dist/core/routes/litellm-routes.js.map +1 -1
  237. package/ccw/dist/core/routes/mcp-routes.d.ts +1 -14
  238. package/ccw/dist/core/routes/mcp-routes.d.ts.map +1 -1
  239. package/ccw/dist/core/routes/mcp-routes.js +99 -30
  240. package/ccw/dist/core/routes/mcp-routes.js.map +1 -1
  241. package/ccw/dist/core/routes/mcp-templates-db.d.ts.map +1 -1
  242. package/ccw/dist/core/routes/mcp-templates-db.js +30 -31
  243. package/ccw/dist/core/routes/mcp-templates-db.js.map +1 -1
  244. package/ccw/dist/core/routes/memory-routes.d.ts.map +1 -1
  245. package/ccw/dist/core/routes/memory-routes.js +74 -24
  246. package/ccw/dist/core/routes/memory-routes.js.map +1 -1
  247. package/ccw/dist/core/routes/nav-status-routes.d.ts +3 -0
  248. package/ccw/dist/core/routes/nav-status-routes.d.ts.map +1 -0
  249. package/ccw/dist/core/routes/nav-status-routes.js +217 -0
  250. package/ccw/dist/core/routes/nav-status-routes.js.map +1 -0
  251. package/ccw/dist/core/routes/rules-routes.d.ts +1 -14
  252. package/ccw/dist/core/routes/rules-routes.d.ts.map +1 -1
  253. package/ccw/dist/core/routes/rules-routes.js +481 -58
  254. package/ccw/dist/core/routes/rules-routes.js.map +1 -1
  255. package/ccw/dist/core/routes/session-routes.d.ts +1 -14
  256. package/ccw/dist/core/routes/session-routes.d.ts.map +1 -1
  257. package/ccw/dist/core/routes/session-routes.js +15 -3
  258. package/ccw/dist/core/routes/session-routes.js.map +1 -1
  259. package/ccw/dist/core/routes/skills-routes.d.ts +1 -14
  260. package/ccw/dist/core/routes/skills-routes.d.ts.map +1 -1
  261. package/ccw/dist/core/routes/skills-routes.js +394 -112
  262. package/ccw/dist/core/routes/skills-routes.js.map +1 -1
  263. package/ccw/dist/core/routes/status-routes.d.ts +1 -14
  264. package/ccw/dist/core/routes/status-routes.d.ts.map +1 -1
  265. package/ccw/dist/core/routes/status-routes.js +4 -0
  266. package/ccw/dist/core/routes/status-routes.js.map +1 -1
  267. package/ccw/dist/core/routes/system-routes.d.ts +4 -10
  268. package/ccw/dist/core/routes/system-routes.d.ts.map +1 -1
  269. package/ccw/dist/core/routes/system-routes.js +6 -4
  270. package/ccw/dist/core/routes/system-routes.js.map +1 -1
  271. package/ccw/dist/core/routes/types.d.ts +19 -0
  272. package/ccw/dist/core/routes/types.d.ts.map +1 -0
  273. package/ccw/dist/core/routes/types.js +2 -0
  274. package/ccw/dist/core/routes/types.js.map +1 -0
  275. package/ccw/dist/core/server.d.ts.map +1 -1
  276. package/ccw/dist/core/server.js +206 -29
  277. package/ccw/dist/core/server.js.map +1 -1
  278. package/ccw/dist/core/services/api-key-tester.d.ts +42 -0
  279. package/ccw/dist/core/services/api-key-tester.d.ts.map +1 -0
  280. package/ccw/dist/core/services/api-key-tester.js +126 -0
  281. package/ccw/dist/core/services/api-key-tester.js.map +1 -0
  282. package/ccw/dist/core/services/health-check-service.d.ts +88 -0
  283. package/ccw/dist/core/services/health-check-service.d.ts.map +1 -0
  284. package/ccw/dist/core/services/health-check-service.js +293 -0
  285. package/ccw/dist/core/services/health-check-service.js.map +1 -0
  286. package/ccw/dist/core/websocket.d.ts +9 -7
  287. package/ccw/dist/core/websocket.d.ts.map +1 -1
  288. package/ccw/dist/core/websocket.js +9 -4
  289. package/ccw/dist/core/websocket.js.map +1 -1
  290. package/ccw/dist/tools/claude-cli-tools.d.ts +152 -28
  291. package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
  292. package/ccw/dist/tools/claude-cli-tools.js +490 -100
  293. package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
  294. package/ccw/dist/tools/cli-config-manager.d.ts +24 -8
  295. package/ccw/dist/tools/cli-config-manager.d.ts.map +1 -1
  296. package/ccw/dist/tools/cli-config-manager.js +76 -156
  297. package/ccw/dist/tools/cli-config-manager.js.map +1 -1
  298. package/ccw/dist/tools/cli-executor-core.d.ts +85 -0
  299. package/ccw/dist/tools/cli-executor-core.d.ts.map +1 -0
  300. package/ccw/dist/tools/cli-executor-core.js +1310 -0
  301. package/ccw/dist/tools/cli-executor-core.js.map +1 -0
  302. package/ccw/dist/tools/cli-executor-state.d.ts +241 -0
  303. package/ccw/dist/tools/cli-executor-state.d.ts.map +1 -0
  304. package/ccw/dist/tools/cli-executor-state.js +392 -0
  305. package/ccw/dist/tools/cli-executor-state.js.map +1 -0
  306. package/ccw/dist/tools/cli-executor-utils.d.ts +36 -0
  307. package/ccw/dist/tools/cli-executor-utils.d.ts.map +1 -0
  308. package/ccw/dist/tools/cli-executor-utils.js +298 -0
  309. package/ccw/dist/tools/cli-executor-utils.js.map +1 -0
  310. package/ccw/dist/tools/cli-executor.d.ts +3 -377
  311. package/ccw/dist/tools/cli-executor.d.ts.map +1 -1
  312. package/ccw/dist/tools/cli-executor.js +3 -1884
  313. package/ccw/dist/tools/cli-executor.js.map +1 -1
  314. package/ccw/dist/tools/cli-history-store.d.ts +2 -0
  315. package/ccw/dist/tools/cli-history-store.d.ts.map +1 -1
  316. package/ccw/dist/tools/cli-history-store.js.map +1 -1
  317. package/ccw/dist/tools/cli-output-converter.d.ts +192 -0
  318. package/ccw/dist/tools/cli-output-converter.d.ts.map +1 -0
  319. package/ccw/dist/tools/cli-output-converter.js +1047 -0
  320. package/ccw/dist/tools/cli-output-converter.js.map +1 -0
  321. package/ccw/dist/tools/cli-prompt-builder.d.ts +113 -0
  322. package/ccw/dist/tools/cli-prompt-builder.d.ts.map +1 -0
  323. package/ccw/dist/tools/cli-prompt-builder.js +363 -0
  324. package/ccw/dist/tools/cli-prompt-builder.js.map +1 -0
  325. package/ccw/dist/tools/codex-lens.d.ts +15 -1
  326. package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
  327. package/ccw/dist/tools/codex-lens.js +289 -55
  328. package/ccw/dist/tools/codex-lens.js.map +1 -1
  329. package/ccw/dist/tools/detect-changed-modules.d.ts.map +1 -1
  330. package/ccw/dist/tools/detect-changed-modules.js +22 -4
  331. package/ccw/dist/tools/detect-changed-modules.js.map +1 -1
  332. package/ccw/dist/tools/index.d.ts.map +1 -1
  333. package/ccw/dist/tools/index.js +2 -0
  334. package/ccw/dist/tools/index.js.map +1 -1
  335. package/ccw/dist/tools/litellm-client.d.ts.map +1 -1
  336. package/ccw/dist/tools/litellm-client.js +10 -4
  337. package/ccw/dist/tools/litellm-client.js.map +1 -1
  338. package/ccw/dist/tools/litellm-executor.d.ts +2 -4
  339. package/ccw/dist/tools/litellm-executor.d.ts.map +1 -1
  340. package/ccw/dist/tools/litellm-executor.js +39 -8
  341. package/ccw/dist/tools/litellm-executor.js.map +1 -1
  342. package/ccw/dist/tools/native-session-discovery.d.ts +2 -0
  343. package/ccw/dist/tools/native-session-discovery.d.ts.map +1 -1
  344. package/ccw/dist/tools/native-session-discovery.js +197 -1
  345. package/ccw/dist/tools/native-session-discovery.js.map +1 -1
  346. package/ccw/dist/tools/session-manager.d.ts.map +1 -1
  347. package/ccw/dist/tools/session-manager.js +79 -0
  348. package/ccw/dist/tools/session-manager.js.map +1 -1
  349. package/ccw/dist/tools/skill-context-loader.d.ts +15 -0
  350. package/ccw/dist/tools/skill-context-loader.d.ts.map +1 -0
  351. package/ccw/dist/tools/skill-context-loader.js +198 -0
  352. package/ccw/dist/tools/skill-context-loader.js.map +1 -0
  353. package/ccw/dist/tools/smart-search.d.ts +8 -3
  354. package/ccw/dist/tools/smart-search.d.ts.map +1 -1
  355. package/ccw/dist/tools/smart-search.js +378 -75
  356. package/ccw/dist/tools/smart-search.js.map +1 -1
  357. package/ccw/dist/types/cli-settings.d.ts +86 -0
  358. package/ccw/dist/types/cli-settings.d.ts.map +1 -0
  359. package/ccw/dist/types/cli-settings.js +54 -0
  360. package/ccw/dist/types/cli-settings.js.map +1 -0
  361. package/ccw/dist/types/litellm-api-config.d.ts +40 -1
  362. package/ccw/dist/types/litellm-api-config.d.ts.map +1 -1
  363. package/ccw/dist/utils/exec-constants.d.ts +25 -0
  364. package/ccw/dist/utils/exec-constants.d.ts.map +1 -0
  365. package/ccw/dist/utils/exec-constants.js +25 -0
  366. package/ccw/dist/utils/exec-constants.js.map +1 -0
  367. package/ccw/dist/utils/path-resolver.d.ts +1 -0
  368. package/ccw/dist/utils/path-resolver.d.ts.map +1 -1
  369. package/ccw/dist/utils/path-resolver.js +48 -3
  370. package/ccw/dist/utils/path-resolver.js.map +1 -1
  371. package/ccw/dist/utils/path-validator.d.ts.map +1 -1
  372. package/ccw/dist/utils/path-validator.js +25 -6
  373. package/ccw/dist/utils/path-validator.js.map +1 -1
  374. package/ccw/dist/utils/python-utils.d.ts.map +1 -1
  375. package/ccw/dist/utils/python-utils.js +27 -7
  376. package/ccw/dist/utils/python-utils.js.map +1 -1
  377. package/ccw/dist/utils/shell-escape.d.ts +8 -0
  378. package/ccw/dist/utils/shell-escape.d.ts.map +1 -0
  379. package/ccw/dist/utils/shell-escape.js +24 -0
  380. package/ccw/dist/utils/shell-escape.js.map +1 -0
  381. package/ccw/dist/utils/uv-manager.d.ts +167 -0
  382. package/ccw/dist/utils/uv-manager.d.ts.map +1 -0
  383. package/ccw/dist/utils/uv-manager.js +644 -0
  384. package/ccw/dist/utils/uv-manager.js.map +1 -0
  385. package/ccw/src/cli.ts +4 -1
  386. package/ccw/src/commands/cli.ts +132 -34
  387. package/ccw/src/commands/issue.ts +605 -91
  388. package/ccw/src/commands/serve.ts +15 -5
  389. package/ccw/src/commands/stop.ts +32 -5
  390. package/ccw/src/commands/tool.ts +17 -2
  391. package/ccw/src/commands/view.ts +13 -3
  392. package/ccw/src/config/cli-settings-manager.ts +460 -0
  393. package/ccw/src/config/litellm-api-config-manager.ts +392 -57
  394. package/ccw/src/core/auth/csrf-manager.ts +104 -0
  395. package/ccw/src/core/auth/csrf-middleware.ts +159 -0
  396. package/ccw/src/core/auth/middleware.ts +94 -0
  397. package/ccw/src/core/auth/token-manager.ts +219 -0
  398. package/ccw/src/core/cache-manager.ts +64 -52
  399. package/ccw/src/core/claude-freshness.ts +26 -6
  400. package/ccw/src/core/core-memory-store.ts +2 -1
  401. package/ccw/src/core/cors.ts +10 -0
  402. package/ccw/src/core/dashboard-generator-patch.ts +47 -48
  403. package/ccw/src/core/dashboard-generator.ts +797 -744
  404. package/ccw/src/core/data-aggregator.ts +667 -667
  405. package/ccw/src/core/lite-scanner.ts +156 -140
  406. package/ccw/src/core/routes/auth-routes.ts +98 -0
  407. package/ccw/src/core/routes/ccw-routes.ts +10 -20
  408. package/ccw/src/core/routes/claude-routes.ts +101 -51
  409. package/ccw/src/core/routes/cli-routes.ts +152 -55
  410. package/ccw/src/core/routes/cli-settings-routes.ts +232 -0
  411. package/ccw/src/core/routes/codexlens/README.md +37 -0
  412. package/ccw/src/core/routes/codexlens/config-handlers.ts +1269 -0
  413. package/ccw/src/core/routes/codexlens/index-handlers.ts +354 -0
  414. package/ccw/src/core/routes/codexlens/semantic-handlers.ts +931 -0
  415. package/ccw/src/core/routes/codexlens/utils.ts +96 -0
  416. package/ccw/src/core/routes/codexlens/watcher-handlers.ts +265 -0
  417. package/ccw/src/core/routes/codexlens-routes.ts +11 -1044
  418. package/ccw/src/core/routes/discovery-routes.ts +1 -12
  419. package/ccw/src/core/routes/files-routes.ts +112 -40
  420. package/ccw/src/core/routes/graph-routes.ts +39 -46
  421. package/ccw/src/core/routes/help-routes.ts +2 -12
  422. package/ccw/src/core/routes/hooks-routes.ts +83 -44
  423. package/ccw/src/core/routes/issue-routes.ts +1 -12
  424. package/ccw/src/core/routes/litellm-api-routes.ts +574 -60
  425. package/ccw/src/core/routes/litellm-routes.ts +35 -27
  426. package/ccw/src/core/routes/mcp-routes.ts +157 -60
  427. package/ccw/src/core/routes/mcp-routes.ts.backup +549 -550
  428. package/ccw/src/core/routes/mcp-templates-db.ts +267 -268
  429. package/ccw/src/core/routes/memory-routes.ts +76 -22
  430. package/ccw/src/core/routes/nav-status-routes.ts +231 -0
  431. package/ccw/src/core/routes/rules-routes.ts +600 -81
  432. package/ccw/src/core/routes/session-routes.ts +28 -22
  433. package/ccw/src/core/routes/skills-routes.ts +452 -132
  434. package/ccw/src/core/routes/status-routes.ts +1 -12
  435. package/ccw/src/core/routes/system-routes.ts +15 -22
  436. package/ccw/src/core/routes/types.ts +25 -0
  437. package/ccw/src/core/server.ts +657 -468
  438. package/ccw/src/core/services/api-key-tester.ts +160 -0
  439. package/ccw/src/core/services/health-check-service.ts +366 -0
  440. package/ccw/src/core/websocket.ts +20 -12
  441. package/ccw/src/templates/dashboard-css/01-base.css +109 -0
  442. package/ccw/src/templates/dashboard-css/10-cli-status.css +202 -0
  443. package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +308 -0
  444. package/ccw/src/templates/dashboard-css/30-core-memory.css +20 -0
  445. package/ccw/src/templates/dashboard-css/31-api-settings.css +751 -14
  446. package/ccw/src/templates/dashboard-css/33-cli-stream-viewer.css +230 -2
  447. package/ccw/src/templates/dashboard-js/api.js +5 -0
  448. package/ccw/src/templates/dashboard-js/components/cli-status.js +279 -107
  449. package/ccw/src/templates/dashboard-js/components/cli-stream-viewer.js +262 -20
  450. package/ccw/src/templates/dashboard-js/components/hook-manager.js +105 -5
  451. package/ccw/src/templates/dashboard-js/components/mcp-manager.js +317 -0
  452. package/ccw/src/templates/dashboard-js/components/navigation.js +45 -0
  453. package/ccw/src/templates/dashboard-js/components/notifications.js +128 -0
  454. package/ccw/src/templates/dashboard-js/i18n.js +4448 -3983
  455. package/ccw/src/templates/dashboard-js/main.js +71 -0
  456. package/ccw/src/templates/dashboard-js/services.js +289 -0
  457. package/ccw/src/templates/dashboard-js/views/api-settings.js +5613 -3361
  458. package/ccw/src/templates/dashboard-js/views/claude-manager.js +1 -7
  459. package/ccw/src/templates/dashboard-js/views/cli-manager.js +581 -87
  460. package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +6101 -1965
  461. package/ccw/src/templates/dashboard-js/views/core-memory.js +129 -20
  462. package/ccw/src/templates/dashboard-js/views/hook-manager.js +17 -3
  463. package/ccw/src/templates/dashboard-js/views/mcp-manager.js +63 -0
  464. package/ccw/src/templates/dashboard-js/views/project-overview.js +182 -37
  465. package/ccw/src/templates/dashboard-js/views/rules-manager.js +26 -3
  466. package/ccw/src/templates/dashboard-js/views/skills-manager.js +2 -42
  467. package/ccw/src/templates/dashboard.html +6 -0
  468. package/ccw/src/tools/README.md +29 -0
  469. package/ccw/src/tools/claude-cli-tools.ts +640 -125
  470. package/ccw/src/tools/cli-config-manager.ts +102 -172
  471. package/ccw/src/tools/cli-executor-core.ts +1533 -0
  472. package/ccw/src/tools/cli-executor-state.ts +560 -0
  473. package/ccw/src/tools/cli-executor-utils.ts +349 -0
  474. package/ccw/src/tools/cli-executor.ts +3 -2309
  475. package/ccw/src/tools/cli-history-store.ts +2 -0
  476. package/ccw/src/tools/cli-output-converter.ts +1237 -0
  477. package/ccw/src/tools/cli-prompt-builder.ts +487 -0
  478. package/ccw/src/tools/codex-lens.ts +324 -59
  479. package/ccw/src/tools/detect-changed-modules.ts +24 -6
  480. package/ccw/src/tools/index.ts +2 -0
  481. package/ccw/src/tools/litellm-client.ts +10 -4
  482. package/ccw/src/tools/litellm-executor.ts +146 -114
  483. package/ccw/src/tools/native-session-discovery.ts +209 -1
  484. package/ccw/src/tools/session-manager.ts +88 -0
  485. package/ccw/src/tools/skill-context-loader.ts +213 -0
  486. package/ccw/src/tools/smart-search.ts +427 -76
  487. package/ccw/src/types/cli-settings.ts +137 -0
  488. package/ccw/src/types/litellm-api-config.ts +55 -1
  489. package/ccw/src/utils/exec-constants.ts +24 -0
  490. package/ccw/src/utils/path-resolver.ts +49 -3
  491. package/ccw/src/utils/path-validator.ts +28 -6
  492. package/ccw/src/utils/python-utils.ts +140 -121
  493. package/ccw/src/utils/shell-escape.ts +30 -0
  494. package/ccw/src/utils/uv-manager.ts +796 -0
  495. package/ccw-litellm/src/ccw_litellm/__pycache__/__init__.cpython-310.pyc +0 -0
  496. package/ccw-litellm/src/ccw_litellm/__pycache__/__init__.cpython-312.pyc +0 -0
  497. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/__init__.cpython-310.pyc +0 -0
  498. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/__init__.cpython-312.pyc +0 -0
  499. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_embedder.cpython-310.pyc +0 -0
  500. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_embedder.cpython-312.pyc +0 -0
  501. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
  502. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_llm.cpython-310.pyc +0 -0
  503. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_llm.cpython-312.pyc +0 -0
  504. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_llm.cpython-313.pyc +0 -0
  505. package/ccw-litellm/src/ccw_litellm/clients/litellm_embedder.py +270 -251
  506. package/ccw-litellm/src/ccw_litellm/clients/litellm_llm.py +33 -0
  507. package/ccw-litellm/src/ccw_litellm/config/__pycache__/__init__.cpython-310.pyc +0 -0
  508. package/ccw-litellm/src/ccw_litellm/config/__pycache__/__init__.cpython-312.pyc +0 -0
  509. package/ccw-litellm/src/ccw_litellm/config/__pycache__/loader.cpython-310.pyc +0 -0
  510. package/ccw-litellm/src/ccw_litellm/config/__pycache__/loader.cpython-312.pyc +0 -0
  511. package/ccw-litellm/src/ccw_litellm/config/__pycache__/loader.cpython-313.pyc +0 -0
  512. package/ccw-litellm/src/ccw_litellm/config/__pycache__/models.cpython-310.pyc +0 -0
  513. package/ccw-litellm/src/ccw_litellm/config/__pycache__/models.cpython-312.pyc +0 -0
  514. package/ccw-litellm/src/ccw_litellm/config/__pycache__/models.cpython-313.pyc +0 -0
  515. package/ccw-litellm/src/ccw_litellm/config/loader.py +343 -316
  516. package/ccw-litellm/src/ccw_litellm/config/models.py +162 -130
  517. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/__init__.cpython-310.pyc +0 -0
  518. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/__init__.cpython-312.pyc +0 -0
  519. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/embedder.cpython-310.pyc +0 -0
  520. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/embedder.cpython-312.pyc +0 -0
  521. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/llm.cpython-310.pyc +0 -0
  522. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/llm.cpython-312.pyc +0 -0
  523. package/codex-lens/pyproject.toml +43 -0
  524. package/codex-lens/src/codexlens/__pycache__/__init__.cpython-310.pyc +0 -0
  525. package/codex-lens/src/codexlens/__pycache__/__init__.cpython-312.pyc +0 -0
  526. package/codex-lens/src/codexlens/__pycache__/__main__.cpython-310.pyc +0 -0
  527. package/codex-lens/src/codexlens/__pycache__/__main__.cpython-312.pyc +0 -0
  528. package/codex-lens/src/codexlens/__pycache__/config.cpython-310.pyc +0 -0
  529. package/codex-lens/src/codexlens/__pycache__/config.cpython-312.pyc +0 -0
  530. package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
  531. package/codex-lens/src/codexlens/__pycache__/entities.cpython-310.pyc +0 -0
  532. package/codex-lens/src/codexlens/__pycache__/entities.cpython-312.pyc +0 -0
  533. package/codex-lens/src/codexlens/__pycache__/entities.cpython-313.pyc +0 -0
  534. package/codex-lens/src/codexlens/__pycache__/env_config.cpython-310.pyc +0 -0
  535. package/codex-lens/src/codexlens/__pycache__/env_config.cpython-312.pyc +0 -0
  536. package/codex-lens/src/codexlens/__pycache__/env_config.cpython-313.pyc +0 -0
  537. package/codex-lens/src/codexlens/__pycache__/errors.cpython-310.pyc +0 -0
  538. package/codex-lens/src/codexlens/__pycache__/errors.cpython-312.pyc +0 -0
  539. package/codex-lens/src/codexlens/cli/__pycache__/__init__.cpython-310.pyc +0 -0
  540. package/codex-lens/src/codexlens/cli/__pycache__/__init__.cpython-312.pyc +0 -0
  541. package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-310.pyc +0 -0
  542. package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-312.pyc +0 -0
  543. package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
  544. package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-310.pyc +0 -0
  545. package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-312.pyc +0 -0
  546. package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
  547. package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-310.pyc +0 -0
  548. package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-312.pyc +0 -0
  549. package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
  550. package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-310.pyc +0 -0
  551. package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-312.pyc +0 -0
  552. package/codex-lens/src/codexlens/cli/commands.py +4416 -2295
  553. package/codex-lens/src/codexlens/cli/embedding_manager.py +777 -15
  554. package/codex-lens/src/codexlens/cli/model_manager.py +676 -0
  555. package/codex-lens/src/codexlens/config.py +356 -12
  556. package/codex-lens/src/codexlens/entities.py +4 -1
  557. package/codex-lens/src/codexlens/env_config.py +304 -0
  558. package/codex-lens/src/codexlens/indexing/__init__.py +23 -1
  559. package/codex-lens/src/codexlens/indexing/__pycache__/__init__.cpython-313.pyc +0 -0
  560. package/codex-lens/src/codexlens/indexing/__pycache__/embedding.cpython-313.pyc +0 -0
  561. package/codex-lens/src/codexlens/indexing/__pycache__/symbol_extractor.cpython-313.pyc +0 -0
  562. package/codex-lens/src/codexlens/indexing/embedding.py +582 -0
  563. package/codex-lens/src/codexlens/indexing/symbol_extractor.py +62 -28
  564. package/codex-lens/src/codexlens/parsers/__pycache__/__init__.cpython-310.pyc +0 -0
  565. package/codex-lens/src/codexlens/parsers/__pycache__/__init__.cpython-312.pyc +0 -0
  566. package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-310.pyc +0 -0
  567. package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-312.pyc +0 -0
  568. package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-313.pyc +0 -0
  569. package/codex-lens/src/codexlens/parsers/__pycache__/tokenizer.cpython-310.pyc +0 -0
  570. package/codex-lens/src/codexlens/parsers/__pycache__/tokenizer.cpython-312.pyc +0 -0
  571. package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-310.pyc +0 -0
  572. package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-312.pyc +0 -0
  573. package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-313.pyc +0 -0
  574. package/codex-lens/src/codexlens/parsers/factory.py +139 -10
  575. package/codex-lens/src/codexlens/parsers/treesitter_parser.py +487 -13
  576. package/codex-lens/src/codexlens/search/__pycache__/__init__.cpython-310.pyc +0 -0
  577. package/codex-lens/src/codexlens/search/__pycache__/__init__.cpython-312.pyc +0 -0
  578. package/codex-lens/src/codexlens/search/__pycache__/binary_searcher.cpython-313.pyc +0 -0
  579. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-310.pyc +0 -0
  580. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-312.pyc +0 -0
  581. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
  582. package/codex-lens/src/codexlens/search/__pycache__/enrichment.cpython-313.pyc +0 -0
  583. package/codex-lens/src/codexlens/search/__pycache__/graph_expander.cpython-313.pyc +0 -0
  584. package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-310.pyc +0 -0
  585. package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-312.pyc +0 -0
  586. package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
  587. package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-310.pyc +0 -0
  588. package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-312.pyc +0 -0
  589. package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
  590. package/codex-lens/src/codexlens/search/binary_searcher.py +277 -0
  591. package/codex-lens/src/codexlens/search/chain_search.py +1652 -8
  592. package/codex-lens/src/codexlens/search/enrichment.py +21 -0
  593. package/codex-lens/src/codexlens/search/graph_expander.py +264 -0
  594. package/codex-lens/src/codexlens/search/hybrid_search.py +772 -37
  595. package/codex-lens/src/codexlens/search/ranking.py +397 -8
  596. package/codex-lens/src/codexlens/semantic/SPLADE_IMPLEMENTATION.md +225 -0
  597. package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-310.pyc +0 -0
  598. package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-312.pyc +0 -0
  599. package/codex-lens/src/codexlens/semantic/__pycache__/ann_index.cpython-310.pyc +0 -0
  600. package/codex-lens/src/codexlens/semantic/__pycache__/ann_index.cpython-312.pyc +0 -0
  601. package/codex-lens/src/codexlens/semantic/__pycache__/ann_index.cpython-313.pyc +0 -0
  602. package/codex-lens/src/codexlens/semantic/__pycache__/base.cpython-310.pyc +0 -0
  603. package/codex-lens/src/codexlens/semantic/__pycache__/base.cpython-312.pyc +0 -0
  604. package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-310.pyc +0 -0
  605. package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-312.pyc +0 -0
  606. package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
  607. package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-310.pyc +0 -0
  608. package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-312.pyc +0 -0
  609. package/codex-lens/src/codexlens/semantic/__pycache__/factory.cpython-310.pyc +0 -0
  610. package/codex-lens/src/codexlens/semantic/__pycache__/factory.cpython-312.pyc +0 -0
  611. package/codex-lens/src/codexlens/semantic/__pycache__/factory.cpython-313.pyc +0 -0
  612. package/codex-lens/src/codexlens/semantic/__pycache__/gpu_support.cpython-310.pyc +0 -0
  613. package/codex-lens/src/codexlens/semantic/__pycache__/gpu_support.cpython-312.pyc +0 -0
  614. package/codex-lens/src/codexlens/semantic/__pycache__/gpu_support.cpython-313.pyc +0 -0
  615. package/codex-lens/src/codexlens/semantic/__pycache__/litellm_embedder.cpython-310.pyc +0 -0
  616. package/codex-lens/src/codexlens/semantic/__pycache__/litellm_embedder.cpython-312.pyc +0 -0
  617. package/codex-lens/src/codexlens/semantic/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
  618. package/codex-lens/src/codexlens/semantic/__pycache__/reranker.cpython-313.pyc +0 -0
  619. package/codex-lens/src/codexlens/semantic/__pycache__/splade_encoder.cpython-310.pyc +0 -0
  620. package/codex-lens/src/codexlens/semantic/__pycache__/splade_encoder.cpython-312.pyc +0 -0
  621. package/codex-lens/src/codexlens/semantic/__pycache__/splade_encoder.cpython-313.pyc +0 -0
  622. package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-310.pyc +0 -0
  623. package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-312.pyc +0 -0
  624. package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
  625. package/codex-lens/src/codexlens/semantic/ann_index.py +654 -0
  626. package/codex-lens/src/codexlens/semantic/chunker.py +328 -23
  627. package/codex-lens/src/codexlens/semantic/factory.py +63 -3
  628. package/codex-lens/src/codexlens/semantic/gpu_support.py +19 -2
  629. package/codex-lens/src/codexlens/semantic/litellm_embedder.py +144 -144
  630. package/codex-lens/src/codexlens/semantic/reranker/__init__.py +25 -0
  631. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/__init__.cpython-310.pyc +0 -0
  632. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/__init__.cpython-312.pyc +0 -0
  633. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/__init__.cpython-313.pyc +0 -0
  634. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/api_reranker.cpython-310.pyc +0 -0
  635. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/api_reranker.cpython-312.pyc +0 -0
  636. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/api_reranker.cpython-313.pyc +0 -0
  637. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/base.cpython-310.pyc +0 -0
  638. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/base.cpython-312.pyc +0 -0
  639. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/base.cpython-313.pyc +0 -0
  640. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/factory.cpython-310.pyc +0 -0
  641. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/factory.cpython-312.pyc +0 -0
  642. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/factory.cpython-313.pyc +0 -0
  643. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/fastembed_reranker.cpython-310.pyc +0 -0
  644. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/fastembed_reranker.cpython-312.pyc +0 -0
  645. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/fastembed_reranker.cpython-313.pyc +0 -0
  646. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/legacy.cpython-310.pyc +0 -0
  647. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/legacy.cpython-312.pyc +0 -0
  648. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/legacy.cpython-313.pyc +0 -0
  649. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/litellm_reranker.cpython-313.pyc +0 -0
  650. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/onnx_reranker.cpython-310.pyc +0 -0
  651. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/onnx_reranker.cpython-312.pyc +0 -0
  652. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/onnx_reranker.cpython-313.pyc +0 -0
  653. package/codex-lens/src/codexlens/semantic/reranker/api_reranker.py +403 -0
  654. package/codex-lens/src/codexlens/semantic/reranker/base.py +46 -0
  655. package/codex-lens/src/codexlens/semantic/reranker/factory.py +159 -0
  656. package/codex-lens/src/codexlens/semantic/reranker/fastembed_reranker.py +257 -0
  657. package/codex-lens/src/codexlens/semantic/reranker/legacy.py +91 -0
  658. package/codex-lens/src/codexlens/semantic/reranker/litellm_reranker.py +214 -0
  659. package/codex-lens/src/codexlens/semantic/reranker/onnx_reranker.py +268 -0
  660. package/codex-lens/src/codexlens/semantic/splade_encoder.py +567 -0
  661. package/codex-lens/src/codexlens/semantic/vector_store.py +472 -352
  662. package/codex-lens/src/codexlens/storage/__init__.py +3 -0
  663. package/codex-lens/src/codexlens/storage/__pycache__/__init__.cpython-310.pyc +0 -0
  664. package/codex-lens/src/codexlens/storage/__pycache__/__init__.cpython-312.pyc +0 -0
  665. package/codex-lens/src/codexlens/storage/__pycache__/__init__.cpython-313.pyc +0 -0
  666. package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-310.pyc +0 -0
  667. package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-312.pyc +0 -0
  668. package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
  669. package/codex-lens/src/codexlens/storage/__pycache__/global_index.cpython-310.pyc +0 -0
  670. package/codex-lens/src/codexlens/storage/__pycache__/global_index.cpython-312.pyc +0 -0
  671. package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-310.pyc +0 -0
  672. package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-312.pyc +0 -0
  673. package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
  674. package/codex-lens/src/codexlens/storage/__pycache__/merkle_tree.cpython-313.pyc +0 -0
  675. package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-310.pyc +0 -0
  676. package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-312.pyc +0 -0
  677. package/codex-lens/src/codexlens/storage/__pycache__/registry.cpython-310.pyc +0 -0
  678. package/codex-lens/src/codexlens/storage/__pycache__/registry.cpython-312.pyc +0 -0
  679. package/codex-lens/src/codexlens/storage/__pycache__/splade_index.cpython-310.pyc +0 -0
  680. package/codex-lens/src/codexlens/storage/__pycache__/splade_index.cpython-312.pyc +0 -0
  681. package/codex-lens/src/codexlens/storage/__pycache__/splade_index.cpython-313.pyc +0 -0
  682. package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-310.pyc +0 -0
  683. package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-312.pyc +0 -0
  684. package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-313.pyc +0 -0
  685. package/codex-lens/src/codexlens/storage/__pycache__/sqlite_utils.cpython-310.pyc +0 -0
  686. package/codex-lens/src/codexlens/storage/__pycache__/sqlite_utils.cpython-312.pyc +0 -0
  687. package/codex-lens/src/codexlens/storage/__pycache__/vector_meta_store.cpython-310.pyc +0 -0
  688. package/codex-lens/src/codexlens/storage/__pycache__/vector_meta_store.cpython-312.pyc +0 -0
  689. package/codex-lens/src/codexlens/storage/__pycache__/vector_meta_store.cpython-313.pyc +0 -0
  690. package/codex-lens/src/codexlens/storage/dir_index.py +310 -12
  691. package/codex-lens/src/codexlens/storage/index_tree.py +240 -25
  692. package/codex-lens/src/codexlens/storage/merkle_tree.py +136 -0
  693. package/codex-lens/src/codexlens/storage/migrations/__pycache__/__init__.cpython-310.pyc +0 -0
  694. package/codex-lens/src/codexlens/storage/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
  695. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_006_enhance_relationships.cpython-313.pyc +0 -0
  696. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_007_add_graph_neighbors.cpython-310.pyc +0 -0
  697. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_007_add_graph_neighbors.cpython-312.pyc +0 -0
  698. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_007_add_graph_neighbors.cpython-313.pyc +0 -0
  699. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_008_add_merkle_hashes.cpython-313.pyc +0 -0
  700. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_009_add_splade.cpython-313.pyc +0 -0
  701. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_010_add_multi_vector_chunks.cpython-313.pyc +0 -0
  702. package/codex-lens/src/codexlens/storage/migrations/migration_006_enhance_relationships.py +37 -0
  703. package/codex-lens/src/codexlens/storage/migrations/migration_007_add_graph_neighbors.py +47 -0
  704. package/codex-lens/src/codexlens/storage/migrations/migration_008_add_merkle_hashes.py +81 -0
  705. package/codex-lens/src/codexlens/storage/migrations/migration_009_add_splade.py +103 -0
  706. package/codex-lens/src/codexlens/storage/migrations/migration_010_add_multi_vector_chunks.py +162 -0
  707. package/codex-lens/src/codexlens/storage/splade_index.py +578 -0
  708. package/codex-lens/src/codexlens/storage/sqlite_store.py +508 -184
  709. package/codex-lens/src/codexlens/storage/vector_meta_store.py +415 -0
  710. package/codex-lens/src/codexlens/watcher/__init__.py +17 -0
  711. package/codex-lens/src/codexlens/watcher/__pycache__/__init__.cpython-310.pyc +0 -0
  712. package/codex-lens/src/codexlens/watcher/__pycache__/__init__.cpython-312.pyc +0 -0
  713. package/codex-lens/src/codexlens/watcher/__pycache__/__init__.cpython-313.pyc +0 -0
  714. package/codex-lens/src/codexlens/watcher/__pycache__/events.cpython-310.pyc +0 -0
  715. package/codex-lens/src/codexlens/watcher/__pycache__/events.cpython-312.pyc +0 -0
  716. package/codex-lens/src/codexlens/watcher/__pycache__/events.cpython-313.pyc +0 -0
  717. package/codex-lens/src/codexlens/watcher/__pycache__/file_watcher.cpython-310.pyc +0 -0
  718. package/codex-lens/src/codexlens/watcher/__pycache__/file_watcher.cpython-312.pyc +0 -0
  719. package/codex-lens/src/codexlens/watcher/__pycache__/file_watcher.cpython-313.pyc +0 -0
  720. package/codex-lens/src/codexlens/watcher/__pycache__/incremental_indexer.cpython-310.pyc +0 -0
  721. package/codex-lens/src/codexlens/watcher/__pycache__/incremental_indexer.cpython-312.pyc +0 -0
  722. package/codex-lens/src/codexlens/watcher/__pycache__/incremental_indexer.cpython-313.pyc +0 -0
  723. package/codex-lens/src/codexlens/watcher/__pycache__/manager.cpython-310.pyc +0 -0
  724. package/codex-lens/src/codexlens/watcher/__pycache__/manager.cpython-312.pyc +0 -0
  725. package/codex-lens/src/codexlens/watcher/__pycache__/manager.cpython-313.pyc +0 -0
  726. package/codex-lens/src/codexlens/watcher/events.py +82 -0
  727. package/codex-lens/src/codexlens/watcher/file_watcher.py +347 -0
  728. package/codex-lens/src/codexlens/watcher/incremental_indexer.py +369 -0
  729. package/codex-lens/src/codexlens/watcher/manager.py +255 -0
  730. package/package.json +4 -1
  731. package/.claude/commands/workflow/docs/analyze.md +0 -1467
  732. package/.claude/commands/workflow/docs/copyright.md +0 -1265
  733. package/.claude/skills/command-guide/SKILL.md +0 -388
  734. package/.claude/skills/command-guide/UPDATE-GUIDELINE.md +0 -592
  735. package/.claude/skills/command-guide/guides/cli-tools-guide.md +0 -410
  736. package/.claude/skills/command-guide/guides/examples.md +0 -537
  737. package/.claude/skills/command-guide/guides/getting-started.md +0 -242
  738. package/.claude/skills/command-guide/guides/implementation-details.md +0 -1010
  739. package/.claude/skills/command-guide/guides/index-structure.md +0 -326
  740. package/.claude/skills/command-guide/guides/troubleshooting.md +0 -92
  741. package/.claude/skills/command-guide/guides/ui-design-workflow-guide.md +0 -316
  742. package/.claude/skills/command-guide/guides/workflow-patterns.md +0 -662
  743. package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +0 -855
  744. package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +0 -267
  745. package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +0 -182
  746. package/.claude/skills/command-guide/reference/agents/cli-lite-planning-agent.md +0 -446
  747. package/.claude/skills/command-guide/reference/agents/cli-planning-agent.md +0 -558
  748. package/.claude/skills/command-guide/reference/agents/code-developer.md +0 -311
  749. package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +0 -308
  750. package/.claude/skills/command-guide/reference/agents/context-search-agent.md +0 -581
  751. package/.claude/skills/command-guide/reference/agents/doc-generator.md +0 -330
  752. package/.claude/skills/command-guide/reference/agents/memory-bridge.md +0 -94
  753. package/.claude/skills/command-guide/reference/agents/test-context-search-agent.md +0 -400
  754. package/.claude/skills/command-guide/reference/agents/test-fix-agent.md +0 -344
  755. package/.claude/skills/command-guide/reference/agents/ui-design-agent.md +0 -593
  756. package/.claude/skills/command-guide/reference/agents/universal-executor.md +0 -131
  757. package/.claude/skills/command-guide/reference/commands/cli/cli-init.md +0 -440
  758. package/.claude/skills/command-guide/reference/commands/enhance-prompt.md +0 -93
  759. package/.claude/skills/command-guide/reference/commands/memory/code-map-memory.md +0 -687
  760. package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +0 -471
  761. package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +0 -386
  762. package/.claude/skills/command-guide/reference/commands/memory/docs.md +0 -616
  763. package/.claude/skills/command-guide/reference/commands/memory/load-skill-memory.md +0 -182
  764. package/.claude/skills/command-guide/reference/commands/memory/load.md +0 -240
  765. package/.claude/skills/command-guide/reference/commands/memory/skill-memory.md +0 -525
  766. package/.claude/skills/command-guide/reference/commands/memory/style-skill-memory.md +0 -396
  767. package/.claude/skills/command-guide/reference/commands/memory/tech-research.md +0 -314
  768. package/.claude/skills/command-guide/reference/commands/memory/update-full.md +0 -332
  769. package/.claude/skills/command-guide/reference/commands/memory/update-related.md +0 -332
  770. package/.claude/skills/command-guide/reference/commands/memory/workflow-skill-memory.md +0 -517
  771. package/.claude/skills/command-guide/reference/commands/task/breakdown.md +0 -204
  772. package/.claude/skills/command-guide/reference/commands/task/create.md +0 -152
  773. package/.claude/skills/command-guide/reference/commands/task/execute.md +0 -270
  774. package/.claude/skills/command-guide/reference/commands/task/replan.md +0 -437
  775. package/.claude/skills/command-guide/reference/commands/version.md +0 -254
  776. package/.claude/skills/command-guide/reference/commands/workflow/action-plan-verify.md +0 -447
  777. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/api-designer.md +0 -585
  778. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/artifacts.md +0 -452
  779. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +0 -443
  780. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/data-architect.md +0 -220
  781. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-manager.md +0 -200
  782. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-owner.md +0 -200
  783. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/scrum-master.md +0 -200
  784. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/subject-matter-expert.md +0 -200
  785. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/synthesis.md +0 -398
  786. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/system-architect.md +0 -387
  787. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ui-designer.md +0 -221
  788. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ux-expert.md +0 -221
  789. package/.claude/skills/command-guide/reference/commands/workflow/execute.md +0 -465
  790. package/.claude/skills/command-guide/reference/commands/workflow/init.md +0 -164
  791. package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +0 -748
  792. package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +0 -664
  793. package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +0 -645
  794. package/.claude/skills/command-guide/reference/commands/workflow/plan.md +0 -551
  795. package/.claude/skills/command-guide/reference/commands/workflow/replan.md +0 -515
  796. package/.claude/skills/command-guide/reference/commands/workflow/review-fix.md +0 -606
  797. package/.claude/skills/command-guide/reference/commands/workflow/review-module-cycle.md +0 -765
  798. package/.claude/skills/command-guide/reference/commands/workflow/review-session-cycle.md +0 -776
  799. package/.claude/skills/command-guide/reference/commands/workflow/review.md +0 -298
  800. package/.claude/skills/command-guide/reference/commands/workflow/session/complete.md +0 -547
  801. package/.claude/skills/command-guide/reference/commands/workflow/session/list.md +0 -114
  802. package/.claude/skills/command-guide/reference/commands/workflow/session/resume.md +0 -77
  803. package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +0 -257
  804. package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +0 -460
  805. package/.claude/skills/command-guide/reference/commands/workflow/tdd-verify.md +0 -400
  806. package/.claude/skills/command-guide/reference/commands/workflow/test-cycle-execute.md +0 -498
  807. package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +0 -699
  808. package/.claude/skills/command-guide/reference/commands/workflow/test-gen.md +0 -529
  809. package/.claude/skills/command-guide/reference/commands/workflow/tools/conflict-resolution.md +0 -766
  810. package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +0 -433
  811. package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +0 -487
  812. package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +0 -518
  813. package/.claude/skills/command-guide/reference/commands/workflow/tools/tdd-coverage-analysis.md +0 -309
  814. package/.claude/skills/command-guide/reference/commands/workflow/tools/test-concept-enhanced.md +0 -163
  815. package/.claude/skills/command-guide/reference/commands/workflow/tools/test-context-gather.md +0 -232
  816. package/.claude/skills/command-guide/reference/commands/workflow/tools/test-task-generate.md +0 -254
  817. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/animation-extract.md +0 -1150
  818. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/codify-style.md +0 -652
  819. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/design-sync.md +0 -454
  820. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/explore-auto.md +0 -678
  821. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/generate.md +0 -504
  822. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/imitate-auto.md +0 -745
  823. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +0 -537
  824. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/layout-extract.md +0 -788
  825. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/reference-page-generator.md +0 -356
  826. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/style-extract.md +0 -773
  827. package/.claude/skills/command-guide/scripts/analyze_commands.py +0 -502
  828. package/.claude/skills/command-guide/scripts/update-index.sh +0 -130
  829. package/.claude/skills/command-guide/templates/issue-bug.md +0 -104
  830. package/.claude/skills/command-guide/templates/issue-diagnosis.md +0 -275
  831. package/.claude/skills/command-guide/templates/issue-feature.md +0 -97
  832. package/.claude/skills/command-guide/templates/issue-question.md +0 -141
@@ -8,7 +8,7 @@ from __future__ import annotations
8
8
 
9
9
  import logging
10
10
  import time
11
- from concurrent.futures import ThreadPoolExecutor, as_completed
11
+ from concurrent.futures import ThreadPoolExecutor, TimeoutError as FuturesTimeoutError, as_completed
12
12
  from contextlib import contextmanager
13
13
  from pathlib import Path
14
14
  from typing import Any, Dict, List, Optional
@@ -31,17 +31,33 @@ def timer(name: str, logger: logging.Logger, level: int = logging.DEBUG):
31
31
  logger.log(level, "[TIMING] %s: %.2fms", name, elapsed_ms)
32
32
 
33
33
  from codexlens.config import Config
34
+ from codexlens.config import VECTORS_HNSW_NAME
34
35
  from codexlens.entities import SearchResult
35
36
  from codexlens.search.ranking import (
37
+ DEFAULT_WEIGHTS,
38
+ FTS_FALLBACK_WEIGHTS,
39
+ QueryIntent,
36
40
  apply_symbol_boost,
41
+ cross_encoder_rerank,
42
+ detect_query_intent,
43
+ filter_results_by_category,
37
44
  get_rrf_weights,
38
45
  reciprocal_rank_fusion,
39
46
  rerank_results,
47
+ simple_weighted_fusion,
40
48
  tag_search_source,
41
49
  )
42
50
  from codexlens.storage.dir_index import DirIndexStore
43
51
 
44
52
 
53
+ # Three-way fusion weights (FTS + Vector + SPLADE)
54
+ THREE_WAY_WEIGHTS = {
55
+ "exact": 0.2,
56
+ "splade": 0.3,
57
+ "vector": 0.5,
58
+ }
59
+
60
+
45
61
  class HybridSearchEngine:
46
62
  """Hybrid search engine with parallel execution and RRF fusion.
47
63
 
@@ -53,12 +69,9 @@ class HybridSearchEngine:
53
69
  default_weights: Default RRF weights for each source
54
70
  """
55
71
 
56
- # Default RRF weights (vector: 60%, exact: 30%, fuzzy: 10%)
57
- DEFAULT_WEIGHTS = {
58
- "exact": 0.3,
59
- "fuzzy": 0.1,
60
- "vector": 0.6,
61
- }
72
+ # NOTE: DEFAULT_WEIGHTS imported from ranking.py - single source of truth
73
+ # Default RRF weights: SPLADE-based hybrid (splade: 0.4, vector: 0.6)
74
+ # FTS fallback mode uses FTS_FALLBACK_WEIGHTS (exact: 0.3, fuzzy: 0.1, vector: 0.6)
62
75
 
63
76
  def __init__(
64
77
  self,
@@ -72,11 +85,24 @@ class HybridSearchEngine:
72
85
  weights: Optional custom RRF weights (default: DEFAULT_WEIGHTS)
73
86
  config: Optional runtime config (enables optional reranking features)
74
87
  embedder: Optional embedder instance for embedding-based reranking
88
+
89
+ Raises:
90
+ TypeError: If weights is not a dict (e.g., if a Path is passed)
75
91
  """
76
92
  self.logger = logging.getLogger(__name__)
77
- self.weights = weights or self.DEFAULT_WEIGHTS.copy()
93
+
94
+ # Validate weights type to catch common usage errors
95
+ if weights is not None and not isinstance(weights, dict):
96
+ raise TypeError(
97
+ f"weights must be a dict, got {type(weights).__name__}. "
98
+ f"Did you mean to pass index_path to search() instead of __init__()?"
99
+ )
100
+
101
+ self.weights = weights or DEFAULT_WEIGHTS.copy()
78
102
  self._config = config
79
103
  self.embedder = embedder
104
+ self.reranker: Any = None
105
+ self._use_gpu = config.embedding_use_gpu if config else True
80
106
 
81
107
  def search(
82
108
  self,
@@ -86,6 +112,7 @@ class HybridSearchEngine:
86
112
  enable_fuzzy: bool = True,
87
113
  enable_vector: bool = False,
88
114
  pure_vector: bool = False,
115
+ enable_splade: bool = False,
89
116
  ) -> List[SearchResult]:
90
117
  """Execute hybrid search with parallel retrieval and RRF fusion.
91
118
 
@@ -96,6 +123,7 @@ class HybridSearchEngine:
96
123
  enable_fuzzy: Enable fuzzy FTS search (default True)
97
124
  enable_vector: Enable vector search (default False)
98
125
  pure_vector: If True, only use vector search without FTS fallback (default False)
126
+ enable_splade: If True, force SPLADE sparse neural search (default False)
99
127
 
100
128
  Returns:
101
129
  List of SearchResult objects sorted by fusion score
@@ -109,12 +137,53 @@ class HybridSearchEngine:
109
137
  >>> results = engine.search(Path("project/_index.db"),
110
138
  ... "how to authenticate users",
111
139
  ... enable_vector=True, pure_vector=True)
140
+ >>> # SPLADE sparse neural search
141
+ >>> results = engine.search(Path("project/_index.db"), "auth flow",
142
+ ... enable_splade=True, enable_vector=True)
112
143
  >>> for r in results[:5]:
113
144
  ... print(f"{r.path}: {r.score:.3f}")
114
145
  """
146
+ # Defensive: avoid creating/locking an index database when callers pass
147
+ # an empty placeholder file (common in tests and misconfigured callers).
148
+ try:
149
+ if index_path.exists() and index_path.stat().st_size == 0:
150
+ return []
151
+ except OSError:
152
+ return []
153
+
154
+ # Detect query intent early for category filtering at index level
155
+ query_intent = detect_query_intent(query)
156
+ # Map intent to category for vector search:
157
+ # - KEYWORD (code intent) -> filter to 'code' only
158
+ # - SEMANTIC (doc intent) -> no filter (allow docs to surface)
159
+ # - MIXED -> no filter (allow all)
160
+ vector_category: Optional[str] = None
161
+ if query_intent == QueryIntent.KEYWORD:
162
+ vector_category = "code"
163
+
115
164
  # Determine which backends to use
116
165
  backends = {}
117
166
 
167
+ # Check if SPLADE is available
168
+ splade_available = False
169
+ # Respect config.enable_splade flag and use_fts_fallback flag
170
+ if self._config and getattr(self._config, 'use_fts_fallback', False):
171
+ # Config explicitly requests FTS fallback - disable SPLADE
172
+ splade_available = False
173
+ elif self._config and not getattr(self._config, 'enable_splade', True):
174
+ # Config explicitly disabled SPLADE
175
+ splade_available = False
176
+ else:
177
+ # Check if SPLADE dependencies are available
178
+ try:
179
+ from codexlens.semantic.splade_encoder import check_splade_available
180
+ ok, _ = check_splade_available()
181
+ if ok:
182
+ # SPLADE tables are in main index database, will check table existence in _search_splade
183
+ splade_available = True
184
+ except Exception:
185
+ pass
186
+
118
187
  if pure_vector:
119
188
  # Pure vector mode: only use vector search, no FTS fallback
120
189
  if enable_vector:
@@ -127,17 +196,41 @@ class HybridSearchEngine:
127
196
  "To use pure vector search, enable vector search mode."
128
197
  )
129
198
  backends["exact"] = True
199
+ elif enable_splade:
200
+ # Explicit SPLADE mode requested via CLI --method splade
201
+ if splade_available:
202
+ backends["splade"] = True
203
+ if enable_vector:
204
+ backends["vector"] = True
205
+ else:
206
+ # SPLADE requested but not available - warn and fallback
207
+ self.logger.warning(
208
+ "SPLADE search requested but not available. "
209
+ "Falling back to FTS. Run 'codexlens index splade' to enable."
210
+ )
211
+ backends["exact"] = True
212
+ if enable_fuzzy:
213
+ backends["fuzzy"] = True
214
+ if enable_vector:
215
+ backends["vector"] = True
130
216
  else:
131
- # Hybrid mode: always include exact search as baseline
132
- backends["exact"] = True
133
- if enable_fuzzy:
134
- backends["fuzzy"] = True
135
- if enable_vector:
136
- backends["vector"] = True
217
+ # Hybrid mode: default to SPLADE if available, otherwise use FTS
218
+ if splade_available:
219
+ # Default: enable SPLADE, disable exact and fuzzy
220
+ backends["splade"] = True
221
+ if enable_vector:
222
+ backends["vector"] = True
223
+ else:
224
+ # Fallback mode: enable exact+fuzzy when SPLADE unavailable
225
+ backends["exact"] = True
226
+ if enable_fuzzy:
227
+ backends["fuzzy"] = True
228
+ if enable_vector:
229
+ backends["vector"] = True
137
230
 
138
231
  # Execute parallel searches
139
232
  with timer("parallel_search_total", self.logger):
140
- results_map = self._search_parallel(index_path, query, backends, limit)
233
+ results_map = self._search_parallel(index_path, query, backends, limit, vector_category)
141
234
 
142
235
  # Provide helpful message if pure-vector mode returns no results
143
236
  if pure_vector and enable_vector and len(results_map.get("vector", [])) == 0:
@@ -156,9 +249,22 @@ class HybridSearchEngine:
156
249
  if source in results_map
157
250
  }
158
251
 
159
- with timer("rrf_fusion", self.logger):
252
+ # Determine fusion method from config (default: rrf)
253
+ fusion_method = "rrf"
254
+ rrf_k = 60
255
+ if self._config is not None:
256
+ fusion_method = getattr(self._config, "fusion_method", "rrf") or "rrf"
257
+ rrf_k = getattr(self._config, "rrf_k", 60) or 60
258
+
259
+ with timer("fusion", self.logger):
160
260
  adaptive_weights = get_rrf_weights(query, active_weights)
161
- fused_results = reciprocal_rank_fusion(results_map, adaptive_weights)
261
+ if fusion_method == "simple":
262
+ fused_results = simple_weighted_fusion(results_map, adaptive_weights)
263
+ else:
264
+ # Default to RRF
265
+ fused_results = reciprocal_rank_fusion(
266
+ results_map, adaptive_weights, k=rrf_k
267
+ )
162
268
 
163
269
  # Optional: boost results that include explicit symbol matches
164
270
  boost_factor = (
@@ -180,7 +286,41 @@ class HybridSearchEngine:
180
286
  query,
181
287
  fused_results[:100],
182
288
  self.embedder,
183
- top_k=self._config.reranking_top_k,
289
+ top_k=(
290
+ 100
291
+ if self._config.enable_cross_encoder_rerank
292
+ else self._config.reranking_top_k
293
+ ),
294
+ )
295
+
296
+ # Optional: cross-encoder reranking as a second stage
297
+ if (
298
+ self._config is not None
299
+ and self._config.enable_reranking
300
+ and self._config.enable_cross_encoder_rerank
301
+ ):
302
+ with timer("cross_encoder_rerank", self.logger):
303
+ if self.reranker is None:
304
+ self.reranker = self._get_cross_encoder_reranker()
305
+ if self.reranker is not None:
306
+ fused_results = cross_encoder_rerank(
307
+ query,
308
+ fused_results,
309
+ self.reranker,
310
+ top_k=self._config.reranker_top_k,
311
+ )
312
+
313
+ # Apply category filtering to avoid code/doc pollution
314
+ # This ensures KEYWORD queries return code files, SEMANTIC queries prefer docs
315
+ enable_category_filter = (
316
+ self._config is None
317
+ or getattr(self._config, 'enable_category_filter', True)
318
+ )
319
+ if enable_category_filter and not pure_vector:
320
+ with timer("category_filter", self.logger):
321
+ query_intent = detect_query_intent(query)
322
+ fused_results = filter_results_by_category(
323
+ fused_results, query_intent, allow_mixed=True
184
324
  )
185
325
 
186
326
  # Apply final limit
@@ -222,12 +362,71 @@ class HybridSearchEngine:
222
362
  )
223
363
  return None
224
364
 
365
+ def _get_cross_encoder_reranker(self) -> Any:
366
+ if self._config is None:
367
+ return None
368
+
369
+ try:
370
+ from codexlens.semantic.reranker import (
371
+ check_reranker_available,
372
+ get_reranker,
373
+ )
374
+ except Exception as exc:
375
+ self.logger.debug("Reranker factory unavailable: %s", exc)
376
+ return None
377
+
378
+ backend = (getattr(self._config, "reranker_backend", "") or "").strip().lower() or "onnx"
379
+
380
+ ok, err = check_reranker_available(backend)
381
+ if not ok:
382
+ self.logger.debug(
383
+ "Reranker backend unavailable (backend=%s): %s",
384
+ backend,
385
+ err,
386
+ )
387
+ return None
388
+
389
+ try:
390
+ model_name = (getattr(self._config, "reranker_model", "") or "").strip() or None
391
+
392
+ if backend != "legacy" and model_name == "cross-encoder/ms-marco-MiniLM-L-6-v2":
393
+ model_name = None
394
+
395
+ device: str | None = None
396
+ kwargs: dict[str, Any] = {}
397
+
398
+ if backend == "onnx":
399
+ kwargs["use_gpu"] = bool(getattr(self._config, "embedding_use_gpu", True))
400
+ elif backend == "legacy":
401
+ if not bool(getattr(self._config, "embedding_use_gpu", True)):
402
+ device = "cpu"
403
+ elif backend == "api":
404
+ # Pass max_input_tokens for adaptive batching
405
+ max_tokens = getattr(self._config, "reranker_max_input_tokens", None)
406
+ if max_tokens:
407
+ kwargs["max_input_tokens"] = max_tokens
408
+
409
+ return get_reranker(
410
+ backend=backend,
411
+ model_name=model_name,
412
+ device=device,
413
+ **kwargs,
414
+ )
415
+ except Exception as exc:
416
+ self.logger.debug(
417
+ "Failed to initialize reranker (backend=%s): %s",
418
+ backend,
419
+ exc,
420
+ )
421
+ return None
422
+
225
423
  def _search_parallel(
226
424
  self,
227
425
  index_path: Path,
228
426
  query: str,
229
427
  backends: Dict[str, bool],
230
428
  limit: int,
429
+ category: Optional[str] = None,
231
430
  ) -> Dict[str, List[SearchResult]]:
232
431
  """Execute parallel searches across enabled backends.
233
432
 
@@ -236,6 +435,7 @@ class HybridSearchEngine:
236
435
  query: FTS5 query string
237
436
  backends: Dictionary of backend name to enabled flag
238
437
  limit: Results limit per backend
438
+ category: Optional category filter for vector search ('code' or 'doc')
239
439
 
240
440
  Returns:
241
441
  Dictionary mapping source name to results list
@@ -266,27 +466,44 @@ class HybridSearchEngine:
266
466
  if backends.get("vector"):
267
467
  submit_times["vector"] = time.perf_counter()
268
468
  future = executor.submit(
269
- self._search_vector, index_path, query, limit
469
+ self._search_vector, index_path, query, limit, category
270
470
  )
271
471
  future_to_source[future] = "vector"
272
472
 
273
- # Collect results as they complete
274
- for future in as_completed(future_to_source):
275
- source = future_to_source[future]
276
- elapsed_ms = (time.perf_counter() - submit_times[source]) * 1000
277
- timing_data[source] = elapsed_ms
278
- try:
279
- results = future.result()
280
- # Tag results with source for debugging
281
- tagged_results = tag_search_source(results, source)
282
- results_map[source] = tagged_results
283
- self.logger.debug(
284
- "[TIMING] %s_search: %.2fms (%d results)",
285
- source, elapsed_ms, len(results)
286
- )
287
- except Exception as exc:
288
- self.logger.error("Search failed for %s: %s", source, exc)
289
- results_map[source] = []
473
+ if backends.get("splade"):
474
+ submit_times["splade"] = time.perf_counter()
475
+ future = executor.submit(
476
+ self._search_splade, index_path, query, limit
477
+ )
478
+ future_to_source[future] = "splade"
479
+
480
+ # Collect results as they complete with timeout protection
481
+ try:
482
+ for future in as_completed(future_to_source, timeout=30.0):
483
+ source = future_to_source[future]
484
+ elapsed_ms = (time.perf_counter() - submit_times[source]) * 1000
485
+ timing_data[source] = elapsed_ms
486
+ try:
487
+ results = future.result(timeout=10.0)
488
+ # Tag results with source for debugging
489
+ tagged_results = tag_search_source(results, source)
490
+ results_map[source] = tagged_results
491
+ self.logger.debug(
492
+ "[TIMING] %s_search: %.2fms (%d results)",
493
+ source, elapsed_ms, len(results)
494
+ )
495
+ except (Exception, FuturesTimeoutError) as exc:
496
+ self.logger.error("Search failed for %s: %s", source, exc)
497
+ results_map[source] = []
498
+ except FuturesTimeoutError:
499
+ self.logger.warning("Search timeout: some backends did not respond in time")
500
+ # Cancel remaining futures
501
+ for future in future_to_source:
502
+ future.cancel()
503
+ # Set empty results for sources that didn't complete
504
+ for source in backends:
505
+ if source not in results_map:
506
+ results_map[source] = []
290
507
 
291
508
  # Log timing summary
292
509
  if timing_data:
@@ -339,20 +556,419 @@ class HybridSearchEngine:
339
556
  self.logger.debug("Fuzzy search error: %s", exc)
340
557
  return []
341
558
 
559
+ def _find_vectors_hnsw(self, index_path: Path) -> Optional[Path]:
560
+ """Find the centralized _vectors.hnsw file by traversing up from index_path.
561
+
562
+ Similar to _search_splade's approach, this method searches for the
563
+ centralized dense vector index file in parent directories.
564
+
565
+ Args:
566
+ index_path: Path to the current _index.db file
567
+
568
+ Returns:
569
+ Path to _vectors.hnsw if found, None otherwise
570
+ """
571
+ current_dir = index_path.parent
572
+ for _ in range(10): # Limit search depth
573
+ candidate = current_dir / VECTORS_HNSW_NAME
574
+ if candidate.exists():
575
+ return candidate
576
+ parent = current_dir.parent
577
+ if parent == current_dir: # Reached root
578
+ break
579
+ current_dir = parent
580
+ return None
581
+
582
+ def _search_vector_centralized(
583
+ self,
584
+ index_path: Path,
585
+ hnsw_path: Path,
586
+ query: str,
587
+ limit: int,
588
+ category: Optional[str] = None,
589
+ ) -> List[SearchResult]:
590
+ """Search using centralized vector index.
591
+
592
+ Args:
593
+ index_path: Path to _index.db file (for metadata lookup)
594
+ hnsw_path: Path to centralized _vectors.hnsw file
595
+ query: Natural language query string
596
+ limit: Maximum results
597
+ category: Optional category filter ('code' or 'doc')
598
+
599
+ Returns:
600
+ List of SearchResult objects ordered by semantic similarity
601
+ """
602
+ try:
603
+ import sqlite3
604
+ import json
605
+ from codexlens.semantic.factory import get_embedder
606
+ from codexlens.semantic.ann_index import ANNIndex
607
+
608
+ # Get model config from the first index database we can find
609
+ # (all indexes should use the same embedding model)
610
+ index_root = hnsw_path.parent
611
+ model_config = None
612
+
613
+ # Try to get model config from the centralized index root first
614
+ # (not the sub-directory index_path, which may have outdated config)
615
+ try:
616
+ from codexlens.semantic.vector_store import VectorStore
617
+ central_index_path = index_root / "_index.db"
618
+ if central_index_path.exists():
619
+ with VectorStore(central_index_path) as vs:
620
+ model_config = vs.get_model_config()
621
+ self.logger.debug(
622
+ "Loaded model config from centralized index: %s",
623
+ model_config
624
+ )
625
+ except Exception as e:
626
+ self.logger.debug("Failed to load model config from centralized index: %s", e)
627
+
628
+ # Detect dimension from HNSW file if model config not found
629
+ if model_config is None:
630
+ self.logger.debug("Model config not found, will detect from HNSW index")
631
+ # Create a temporary ANNIndex to load and detect dimension
632
+ # We need to know the dimension to properly load the index
633
+
634
+ # Get embedder based on model config or default
635
+ if model_config:
636
+ backend = model_config.get("backend", "fastembed")
637
+ model_name = model_config["model_name"]
638
+ model_profile = model_config["model_profile"]
639
+ embedding_dim = model_config["embedding_dim"]
640
+
641
+ if backend == "litellm":
642
+ embedder = get_embedder(backend="litellm", model=model_name)
643
+ else:
644
+ embedder = get_embedder(backend="fastembed", profile=model_profile)
645
+ else:
646
+ # Default to code profile
647
+ embedder = get_embedder(backend="fastembed", profile="code")
648
+ embedding_dim = embedder.embedding_dim
649
+
650
+ # Load centralized ANN index
651
+ start_load = time.perf_counter()
652
+ ann_index = ANNIndex.create_central(
653
+ index_root=index_root,
654
+ dim=embedding_dim,
655
+ )
656
+ if not ann_index.load():
657
+ self.logger.warning("Failed to load centralized vector index from %s", hnsw_path)
658
+ return []
659
+ self.logger.debug(
660
+ "[TIMING] central_ann_load: %.2fms (%d vectors)",
661
+ (time.perf_counter() - start_load) * 1000,
662
+ ann_index.count()
663
+ )
664
+
665
+ # Generate query embedding
666
+ start_embed = time.perf_counter()
667
+ query_embedding = embedder.embed_single(query)
668
+ self.logger.debug(
669
+ "[TIMING] query_embedding: %.2fms",
670
+ (time.perf_counter() - start_embed) * 1000
671
+ )
672
+
673
+ # Search ANN index
674
+ start_search = time.perf_counter()
675
+ import numpy as np
676
+ query_vec = np.array(query_embedding, dtype=np.float32)
677
+ ids, distances = ann_index.search(query_vec, top_k=limit * 2) # Fetch extra for filtering
678
+ self.logger.debug(
679
+ "[TIMING] central_ann_search: %.2fms (%d results)",
680
+ (time.perf_counter() - start_search) * 1000,
681
+ len(ids) if ids else 0
682
+ )
683
+
684
+ if not ids:
685
+ return []
686
+
687
+ # Convert distances to similarity scores (for cosine: score = 1 - distance)
688
+ scores = [1.0 - d for d in distances]
689
+
690
+ # Fetch chunk metadata from semantic_chunks tables
691
+ # We need to search across all _index.db files in the project
692
+ results = self._fetch_chunks_by_ids_centralized(
693
+ index_root, ids, scores, category
694
+ )
695
+
696
+ return results[:limit]
697
+
698
+ except ImportError as exc:
699
+ self.logger.debug("Semantic dependencies not available: %s", exc)
700
+ return []
701
+ except Exception as exc:
702
+ self.logger.error("Centralized vector search error: %s", exc)
703
+ return []
704
+
705
+ def _fetch_chunks_by_ids_centralized(
706
+ self,
707
+ index_root: Path,
708
+ chunk_ids: List[int],
709
+ scores: List[float],
710
+ category: Optional[str] = None,
711
+ ) -> List[SearchResult]:
712
+ """Fetch chunk metadata from centralized _vectors_meta.db for fast lookup.
713
+
714
+ This method uses the centralized VectorMetadataStore for O(1) lookup
715
+ instead of traversing all _index.db files (O(n) where n = number of indexes).
716
+
717
+ Falls back to the legacy per-index lookup if centralized metadata is unavailable.
718
+
719
+ Args:
720
+ index_root: Root directory containing _vectors_meta.db
721
+ chunk_ids: List of chunk IDs from ANN search
722
+ scores: Corresponding similarity scores
723
+ category: Optional category filter
724
+
725
+ Returns:
726
+ List of SearchResult objects
727
+ """
728
+ from codexlens.config import VECTORS_META_DB_NAME
729
+
730
+ # Build score map
731
+ score_map = {cid: score for cid, score in zip(chunk_ids, scores)}
732
+
733
+ # Try centralized metadata store first (fast path)
734
+ vectors_meta_path = index_root / VECTORS_META_DB_NAME
735
+ if vectors_meta_path.exists():
736
+ try:
737
+ return self._fetch_from_vector_meta_store(
738
+ vectors_meta_path, chunk_ids, score_map, category
739
+ )
740
+ except Exception as e:
741
+ self.logger.warning(
742
+ "Centralized metadata lookup failed, falling back to legacy traversal: %s. "
743
+ "Consider regenerating embeddings with: codexlens embeddings-generate --centralized",
744
+ e
745
+ )
746
+
747
+ # Fallback: traverse _index.db files (legacy path)
748
+ return self._fetch_chunks_by_ids_legacy(
749
+ index_root, chunk_ids, score_map, category
750
+ )
751
+
752
+ def _fetch_from_vector_meta_store(
753
+ self,
754
+ meta_db_path: Path,
755
+ chunk_ids: List[int],
756
+ score_map: Dict[int, float],
757
+ category: Optional[str] = None,
758
+ ) -> List[SearchResult]:
759
+ """Fetch chunks from centralized VectorMetadataStore.
760
+
761
+ Args:
762
+ meta_db_path: Path to _vectors_meta.db
763
+ chunk_ids: List of chunk IDs to fetch
764
+ score_map: Mapping of chunk_id to score
765
+ category: Optional category filter
766
+
767
+ Returns:
768
+ List of SearchResult objects
769
+ """
770
+ from codexlens.storage.vector_meta_store import VectorMetadataStore
771
+
772
+ results = []
773
+
774
+ with VectorMetadataStore(meta_db_path) as meta_store:
775
+ rows = meta_store.get_chunks_by_ids(chunk_ids, category=category)
776
+
777
+ for row in rows:
778
+ chunk_id = row["chunk_id"]
779
+ file_path = row["file_path"]
780
+ content = row["content"] or ""
781
+ metadata = row.get("metadata") or {}
782
+ start_line = row.get("start_line")
783
+ end_line = row.get("end_line")
784
+
785
+ score = score_map.get(chunk_id, 0.0)
786
+
787
+ # Build excerpt
788
+ excerpt = content[:200] + "..." if len(content) > 200 else content
789
+
790
+ # Extract symbol information
791
+ symbol_name = metadata.get("symbol_name")
792
+ symbol_kind = metadata.get("symbol_kind")
793
+
794
+ # Build Symbol object if available
795
+ symbol = None
796
+ if symbol_name and symbol_kind and start_line and end_line:
797
+ try:
798
+ from codexlens.entities import Symbol
799
+ symbol = Symbol(
800
+ name=symbol_name,
801
+ kind=symbol_kind,
802
+ range=(start_line, end_line)
803
+ )
804
+ except Exception:
805
+ pass
806
+
807
+ results.append(SearchResult(
808
+ path=file_path,
809
+ score=score,
810
+ excerpt=excerpt,
811
+ content=content,
812
+ symbol=symbol,
813
+ metadata=metadata,
814
+ start_line=start_line,
815
+ end_line=end_line,
816
+ symbol_name=symbol_name,
817
+ symbol_kind=symbol_kind,
818
+ ))
819
+
820
+ # Sort by score descending
821
+ results.sort(key=lambda r: r.score, reverse=True)
822
+ return results
823
+
824
+ def _fetch_chunks_by_ids_legacy(
825
+ self,
826
+ index_root: Path,
827
+ chunk_ids: List[int],
828
+ score_map: Dict[int, float],
829
+ category: Optional[str] = None,
830
+ ) -> List[SearchResult]:
831
+ """Legacy fallback: fetch chunk metadata by traversing all _index.db files.
832
+
833
+ This is the O(n) fallback path used when centralized metadata is unavailable.
834
+
835
+ Args:
836
+ index_root: Root directory containing _index.db files
837
+ chunk_ids: List of chunk IDs from ANN search
838
+ score_map: Mapping of chunk_id to score
839
+ category: Optional category filter
840
+
841
+ Returns:
842
+ List of SearchResult objects
843
+ """
844
+ import sqlite3
845
+ import json
846
+
847
+ # Find all _index.db files
848
+ index_files = list(index_root.rglob("_index.db"))
849
+
850
+ results = []
851
+ found_ids = set()
852
+
853
+ for index_path in index_files:
854
+ try:
855
+ with sqlite3.connect(index_path) as conn:
856
+ conn.row_factory = sqlite3.Row
857
+
858
+ # Check if semantic_chunks table exists
859
+ cursor = conn.execute(
860
+ "SELECT name FROM sqlite_master WHERE type='table' AND name='semantic_chunks'"
861
+ )
862
+ if cursor.fetchone() is None:
863
+ continue
864
+
865
+ # Build query for chunk IDs we haven't found yet
866
+ remaining_ids = [cid for cid in chunk_ids if cid not in found_ids]
867
+ if not remaining_ids:
868
+ break
869
+
870
+ placeholders = ",".join("?" * len(remaining_ids))
871
+
872
+ if category:
873
+ query = f"""
874
+ SELECT id, file_path, content, metadata
875
+ FROM semantic_chunks
876
+ WHERE id IN ({placeholders}) AND category = ?
877
+ """
878
+ params = remaining_ids + [category]
879
+ else:
880
+ query = f"""
881
+ SELECT id, file_path, content, metadata
882
+ FROM semantic_chunks
883
+ WHERE id IN ({placeholders})
884
+ """
885
+ params = remaining_ids
886
+
887
+ rows = conn.execute(query, params).fetchall()
888
+
889
+ for row in rows:
890
+ chunk_id = row["id"]
891
+ if chunk_id in found_ids:
892
+ continue
893
+ found_ids.add(chunk_id)
894
+
895
+ file_path = row["file_path"]
896
+ content = row["content"]
897
+ metadata_json = row["metadata"]
898
+ metadata = json.loads(metadata_json) if metadata_json else {}
899
+
900
+ score = score_map.get(chunk_id, 0.0)
901
+
902
+ # Build excerpt
903
+ excerpt = content[:200] + "..." if len(content) > 200 else content
904
+
905
+ # Extract symbol information
906
+ symbol_name = metadata.get("symbol_name")
907
+ symbol_kind = metadata.get("symbol_kind")
908
+ start_line = metadata.get("start_line")
909
+ end_line = metadata.get("end_line")
910
+
911
+ # Build Symbol object if available
912
+ symbol = None
913
+ if symbol_name and symbol_kind and start_line and end_line:
914
+ try:
915
+ from codexlens.entities import Symbol
916
+ symbol = Symbol(
917
+ name=symbol_name,
918
+ kind=symbol_kind,
919
+ range=(start_line, end_line)
920
+ )
921
+ except Exception:
922
+ pass
923
+
924
+ results.append(SearchResult(
925
+ path=file_path,
926
+ score=score,
927
+ excerpt=excerpt,
928
+ content=content,
929
+ symbol=symbol,
930
+ metadata=metadata,
931
+ start_line=start_line,
932
+ end_line=end_line,
933
+ symbol_name=symbol_name,
934
+ symbol_kind=symbol_kind,
935
+ ))
936
+
937
+ except Exception as e:
938
+ self.logger.debug("Failed to fetch chunks from %s: %s", index_path, e)
939
+ continue
940
+
941
+ # Sort by score descending
942
+ results.sort(key=lambda r: r.score, reverse=True)
943
+ return results
944
+
342
945
  def _search_vector(
343
- self, index_path: Path, query: str, limit: int
946
+ self, index_path: Path, query: str, limit: int, category: Optional[str] = None
344
947
  ) -> List[SearchResult]:
345
948
  """Execute vector similarity search using semantic embeddings.
346
949
 
950
+ Supports both centralized vector storage (single _vectors.hnsw at project root)
951
+ and distributed storage (per-directory .hnsw files).
952
+
347
953
  Args:
348
954
  index_path: Path to _index.db file
349
955
  query: Natural language query string
350
956
  limit: Maximum results
957
+ category: Optional category filter ('code' or 'doc')
351
958
 
352
959
  Returns:
353
960
  List of SearchResult objects ordered by semantic similarity
354
961
  """
355
962
  try:
963
+ # First, check for centralized vector index
964
+ central_hnsw_path = self._find_vectors_hnsw(index_path)
965
+ if central_hnsw_path is not None:
966
+ self.logger.debug("Found centralized vector index at %s", central_hnsw_path)
967
+ return self._search_vector_centralized(
968
+ index_path, central_hnsw_path, query, limit, category
969
+ )
970
+
971
+ # Fallback to distributed (per-index) vector storage
356
972
  # Check if semantic chunks table exists
357
973
  import sqlite3
358
974
 
@@ -466,6 +1082,7 @@ class HybridSearchEngine:
466
1082
  top_k=limit,
467
1083
  min_score=0.0, # Return all results, let RRF handle filtering
468
1084
  return_full_content=True,
1085
+ category=category,
469
1086
  )
470
1087
  self.logger.debug(
471
1088
  "[TIMING] vector_similarity_search: %.2fms (%d results)",
@@ -480,3 +1097,121 @@ class HybridSearchEngine:
480
1097
  except Exception as exc:
481
1098
  self.logger.error("Vector search error: %s", exc)
482
1099
  return []
1100
+
1101
+ def _search_splade(
1102
+ self, index_path: Path, query: str, limit: int
1103
+ ) -> List[SearchResult]:
1104
+ """SPLADE sparse retrieval via inverted index.
1105
+
1106
+ Args:
1107
+ index_path: Path to _index.db file
1108
+ query: Natural language query string
1109
+ limit: Maximum results
1110
+
1111
+ Returns:
1112
+ List of SearchResult ordered by SPLADE score
1113
+ """
1114
+ try:
1115
+ from codexlens.semantic.splade_encoder import get_splade_encoder, check_splade_available
1116
+ from codexlens.storage.splade_index import SpladeIndex
1117
+ from codexlens.config import SPLADE_DB_NAME
1118
+ import sqlite3
1119
+ import json
1120
+
1121
+ # Check dependencies
1122
+ ok, err = check_splade_available()
1123
+ if not ok:
1124
+ self.logger.debug("SPLADE not available: %s", err)
1125
+ return []
1126
+
1127
+ # SPLADE index is stored in _splade.db at the project index root
1128
+ # Traverse up from the current index to find the root _splade.db
1129
+ current_dir = index_path.parent
1130
+ splade_db_path = None
1131
+ for _ in range(10): # Limit search depth
1132
+ candidate = current_dir / SPLADE_DB_NAME
1133
+ if candidate.exists():
1134
+ splade_db_path = candidate
1135
+ break
1136
+ parent = current_dir.parent
1137
+ if parent == current_dir: # Reached root
1138
+ break
1139
+ current_dir = parent
1140
+
1141
+ if not splade_db_path:
1142
+ self.logger.debug("SPLADE index not found in ancestor directories of %s", index_path)
1143
+ return []
1144
+
1145
+ splade_index = SpladeIndex(splade_db_path)
1146
+ if not splade_index.has_index():
1147
+ self.logger.debug("SPLADE index not initialized")
1148
+ return []
1149
+
1150
+ # Encode query to sparse vector
1151
+ encoder = get_splade_encoder(use_gpu=self._use_gpu)
1152
+ query_sparse = encoder.encode_text(query)
1153
+
1154
+ # Search inverted index for top matches
1155
+ raw_results = splade_index.search(query_sparse, limit=limit, min_score=0.0)
1156
+
1157
+ if not raw_results:
1158
+ return []
1159
+
1160
+ # Fetch chunk details from splade_chunks table (self-contained)
1161
+ chunk_ids = [chunk_id for chunk_id, _ in raw_results]
1162
+ score_map = {chunk_id: score for chunk_id, score in raw_results}
1163
+
1164
+ # Get chunk metadata from SPLADE database
1165
+ rows = splade_index.get_chunks_by_ids(chunk_ids)
1166
+
1167
+ # Build SearchResult objects
1168
+ results = []
1169
+ for row in rows:
1170
+ chunk_id = row["id"]
1171
+ file_path = row["file_path"]
1172
+ content = row["content"]
1173
+ metadata_json = row["metadata"]
1174
+ metadata = json.loads(metadata_json) if metadata_json else {}
1175
+
1176
+ score = score_map.get(chunk_id, 0.0)
1177
+
1178
+ # Build excerpt (short preview)
1179
+ excerpt = content[:200] + "..." if len(content) > 200 else content
1180
+
1181
+ # Extract symbol information from metadata
1182
+ symbol_name = metadata.get("symbol_name")
1183
+ symbol_kind = metadata.get("symbol_kind")
1184
+ start_line = metadata.get("start_line")
1185
+ end_line = metadata.get("end_line")
1186
+
1187
+ # Build Symbol object if we have symbol info
1188
+ symbol = None
1189
+ if symbol_name and symbol_kind and start_line and end_line:
1190
+ try:
1191
+ from codexlens.entities import Symbol
1192
+ symbol = Symbol(
1193
+ name=symbol_name,
1194
+ kind=symbol_kind,
1195
+ range=(start_line, end_line)
1196
+ )
1197
+ except Exception:
1198
+ pass
1199
+
1200
+ results.append(SearchResult(
1201
+ path=file_path,
1202
+ score=score,
1203
+ excerpt=excerpt,
1204
+ content=content,
1205
+ symbol=symbol,
1206
+ metadata=metadata,
1207
+ start_line=start_line,
1208
+ end_line=end_line,
1209
+ symbol_name=symbol_name,
1210
+ symbol_kind=symbol_kind,
1211
+ ))
1212
+
1213
+ return results
1214
+
1215
+ except Exception as exc:
1216
+ self.logger.debug("SPLADE search error: %s", exc)
1217
+ return []