claude-code-workflow 6.1.4 → 6.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +10 -0
- package/.claude/agents/action-planning-agent.md +857 -778
- package/.claude/agents/cli-execution-agent.md +266 -269
- package/.claude/agents/cli-explore-agent.md +2 -2
- package/.claude/agents/cli-lite-planning-agent.md +142 -92
- package/.claude/agents/cli-planning-agent.md +4 -4
- package/.claude/agents/code-developer.md +7 -6
- package/.claude/agents/conceptual-planning-agent.md +2 -2
- package/.claude/agents/context-search-agent.md +31 -32
- package/.claude/agents/doc-generator.md +4 -4
- package/.claude/agents/memory-bridge.md +93 -93
- package/.claude/agents/test-context-search-agent.md +8 -7
- package/.claude/agents/test-fix-agent.md +7 -6
- package/.claude/commands/clean.md +516 -0
- package/.claude/commands/memory/compact.md +383 -0
- package/.claude/commands/memory/docs-full-cli.md +471 -471
- package/.claude/commands/memory/docs-related-cli.md +386 -386
- package/.claude/commands/memory/docs.md +615 -615
- package/.claude/commands/memory/load.md +5 -5
- package/.claude/commands/memory/tech-research-rules.md +310 -0
- package/.claude/commands/memory/update-full.md +332 -332
- package/.claude/commands/memory/workflow-skill-memory.md +4 -4
- package/.claude/commands/task/create.md +151 -151
- package/.claude/commands/version.md +254 -254
- package/.claude/commands/workflow/brainstorm/api-designer.md +587 -585
- package/.claude/commands/workflow/brainstorm/artifacts.md +1 -0
- package/.claude/commands/workflow/brainstorm/auto-parallel.md +443 -443
- package/.claude/commands/workflow/brainstorm/data-architect.md +220 -220
- package/.claude/commands/workflow/brainstorm/product-manager.md +200 -200
- package/.claude/commands/workflow/brainstorm/product-owner.md +200 -200
- package/.claude/commands/workflow/brainstorm/scrum-master.md +200 -200
- package/.claude/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
- package/.claude/commands/workflow/brainstorm/system-architect.md +389 -387
- package/.claude/commands/workflow/brainstorm/ui-designer.md +221 -221
- package/.claude/commands/workflow/brainstorm/ux-expert.md +221 -221
- package/.claude/commands/workflow/debug.md +321 -0
- package/.claude/commands/workflow/execute.md +13 -0
- package/.claude/commands/workflow/init.md +165 -164
- package/.claude/commands/workflow/lite-execute.md +119 -13
- package/.claude/commands/workflow/lite-fix.md +623 -621
- package/.claude/commands/workflow/lite-plan.md +610 -592
- package/.claude/commands/workflow/plan.md +5 -5
- package/.claude/commands/workflow/review-module-cycle.md +2 -0
- package/.claude/commands/workflow/review-session-cycle.md +2 -0
- package/.claude/commands/workflow/review.md +297 -291
- package/.claude/commands/workflow/session/complete.md +153 -500
- package/.claude/commands/workflow/session/list.md +95 -95
- package/.claude/commands/workflow/session/resume.md +60 -60
- package/.claude/commands/workflow/session/start.md +199 -199
- package/.claude/commands/workflow/tdd-plan.md +3 -3
- package/.claude/commands/workflow/tdd-verify.md +23 -9
- package/.claude/commands/workflow/test-cycle-execute.md +2 -0
- package/.claude/commands/workflow/test-fix-gen.md +699 -699
- package/.claude/commands/workflow/tools/conflict-resolution.md +104 -18
- package/.claude/commands/workflow/tools/context-gather.md +436 -434
- package/.claude/commands/workflow/tools/task-generate-agent.md +490 -291
- package/.claude/commands/workflow/tools/task-generate-tdd.md +18 -10
- package/.claude/commands/workflow/tools/test-concept-enhanced.md +2 -1
- package/.claude/commands/workflow/tools/test-context-gather.md +1 -0
- package/.claude/commands/workflow/tools/test-task-generate.md +1 -0
- package/.claude/commands/workflow/ui-design/import-from-code.md +9 -6
- package/.claude/skills/command-guide/SKILL.md +5 -5
- package/.claude/skills/command-guide/index/all-commands.json +1 -1
- package/.claude/skills/command-guide/index/by-category.json +1 -1
- package/.claude/skills/command-guide/index/by-use-case.json +1 -1
- package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +857 -778
- package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +266 -269
- package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +2 -2
- package/.claude/skills/command-guide/reference/agents/cli-lite-planning-agent.md +142 -92
- package/.claude/skills/command-guide/reference/agents/cli-planning-agent.md +4 -4
- package/.claude/skills/command-guide/reference/agents/code-developer.md +7 -6
- package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +2 -2
- package/.claude/skills/command-guide/reference/agents/context-search-agent.md +31 -32
- package/.claude/skills/command-guide/reference/agents/doc-generator.md +4 -4
- package/.claude/skills/command-guide/reference/agents/memory-bridge.md +93 -93
- package/.claude/skills/command-guide/reference/agents/test-context-search-agent.md +8 -7
- package/.claude/skills/command-guide/reference/agents/test-fix-agent.md +7 -6
- package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +471 -471
- package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +386 -386
- package/.claude/skills/command-guide/reference/commands/memory/docs.md +17 -16
- package/.claude/skills/command-guide/reference/commands/memory/load.md +5 -5
- package/.claude/skills/command-guide/reference/commands/memory/tech-research.md +194 -357
- package/.claude/skills/command-guide/reference/commands/memory/update-full.md +332 -332
- package/.claude/skills/command-guide/reference/commands/memory/workflow-skill-memory.md +4 -4
- package/.claude/skills/command-guide/reference/commands/task/create.md +151 -151
- package/.claude/skills/command-guide/reference/commands/version.md +254 -254
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/api-designer.md +585 -585
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +443 -443
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/data-architect.md +220 -220
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-manager.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-owner.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/scrum-master.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/system-architect.md +387 -387
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ui-designer.md +221 -221
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ux-expert.md +221 -221
- package/.claude/skills/command-guide/reference/commands/workflow/execute.md +25 -20
- package/.claude/skills/command-guide/reference/commands/workflow/init.md +164 -164
- package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +748 -686
- package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +664 -621
- package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +645 -592
- package/.claude/skills/command-guide/reference/commands/workflow/plan.md +5 -5
- package/.claude/skills/command-guide/reference/commands/workflow/review.md +25 -18
- package/.claude/skills/command-guide/reference/commands/workflow/session/complete.md +547 -500
- package/.claude/skills/command-guide/reference/commands/workflow/session/list.md +45 -27
- package/.claude/skills/command-guide/reference/commands/workflow/session/resume.md +35 -19
- package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +90 -33
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +3 -3
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-verify.md +23 -9
- package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +699 -699
- package/.claude/skills/command-guide/reference/commands/workflow/tools/conflict-resolution.md +103 -17
- package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +434 -434
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +487 -291
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +17 -10
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-concept-enhanced.md +1 -1
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +6 -6
- package/.claude/workflows/chinese-response.md +38 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-api.txt +122 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-components.txt +122 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-config.txt +89 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-core.txt +60 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-patterns.txt +70 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-testing.txt +81 -0
- package/.claude/workflows/cli-templates/prompts/rules/tech-rules-agent-prompt.txt +89 -0
- package/.claude/workflows/cli-templates/prompts/workflow/gemini-solution-design.txt +131 -131
- package/.claude/workflows/cli-templates/prompts/workflow/skill-conflict-patterns.txt +5 -9
- package/.claude/workflows/cli-templates/prompts/workflow/skill-lessons-learned.txt +5 -9
- package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +112 -0
- package/.claude/workflows/cli-templates/protocols/write-protocol.md +201 -0
- package/.claude/workflows/cli-templates/schemas/conflict-resolution-schema.json +137 -0
- package/.claude/workflows/cli-templates/schemas/debug-log-json-schema.json +127 -0
- package/.claude/workflows/cli-templates/schemas/fix-plan-json-schema.json +25 -0
- package/.claude/workflows/cli-templates/schemas/plan-json-schema.json +25 -0
- package/.claude/workflows/cli-tools-usage.md +526 -0
- package/{CLAUDE.md → .claude/workflows/coding-philosophy.md} +24 -45
- package/.claude/workflows/context-tools.md +84 -0
- package/.claude/workflows/file-modification.md +64 -0
- package/.claude/workflows/tool-strategy.md +216 -79
- package/.claude/workflows/windows-platform.md +16 -0
- package/.claude/workflows/workflow-architecture.md +942 -942
- package/.codex/AGENTS.md +63 -330
- package/.codex/prompts/debug.md +318 -0
- package/.codex/prompts/execute.md +273 -0
- package/.codex/prompts/lite-execute.md +164 -0
- package/.codex/prompts/lite-plan.md +469 -0
- package/.codex/prompts.zip +0 -0
- package/.gemini/GEMINI.md +25 -164
- package/.qwen/QWEN.md +0 -139
- package/README.md +29 -9
- package/ccw/README.md +30 -6
- package/ccw/bin/ccw-mcp.js +7 -0
- package/ccw/bin/ccw.js +9 -9
- package/ccw/package.json +65 -47
- package/ccw/src/.workflow/.cli-history/history.db +0 -0
- package/ccw/src/.workflow/.cli-history/history.db-shm +0 -0
- package/ccw/src/.workflow/.cli-history/history.db-wal +0 -0
- package/ccw/src/cli.ts +244 -0
- package/ccw/src/commands/cli.ts +740 -0
- package/ccw/src/commands/core-memory.ts +770 -0
- package/ccw/src/commands/hook.ts +315 -0
- package/ccw/src/commands/install.ts +519 -0
- package/ccw/src/commands/{list.js → list.ts} +1 -1
- package/ccw/src/commands/memory.ts +1090 -0
- package/ccw/src/commands/{serve.js → serve.ts} +14 -5
- package/ccw/src/commands/session-path-resolver.ts +372 -0
- package/ccw/src/commands/session.ts +1141 -0
- package/ccw/src/commands/{stop.js → stop.ts} +16 -6
- package/ccw/src/commands/tool.ts +201 -0
- package/ccw/src/commands/{uninstall.js → uninstall.ts} +89 -40
- package/ccw/src/commands/{upgrade.js → upgrade.ts} +68 -23
- package/ccw/src/commands/{view.js → view.ts} +22 -8
- package/ccw/src/config/storage-paths.ts +670 -0
- package/ccw/src/core/cache-manager.ts +294 -0
- package/ccw/src/core/claude-freshness.ts +319 -0
- package/ccw/src/core/core-memory-store.ts +1528 -0
- package/ccw/src/core/{dashboard-generator-patch.js → dashboard-generator-patch.ts} +18 -0
- package/ccw/src/core/{dashboard-generator.js → dashboard-generator.ts} +69 -12
- package/ccw/src/core/data-aggregator.ts +584 -0
- package/ccw/src/core/history-importer.ts +625 -0
- package/ccw/src/core/{lite-scanner.js → lite-scanner-complete.ts} +162 -66
- package/ccw/src/core/lite-scanner.ts +469 -0
- package/ccw/src/core/{manifest.js → manifest.ts} +104 -34
- package/ccw/src/core/memory-embedder-bridge.ts +262 -0
- package/ccw/src/core/memory-store.ts +978 -0
- package/ccw/src/core/routes/ccw-routes.ts +96 -0
- package/ccw/src/core/routes/claude-routes.ts +1183 -0
- package/ccw/src/core/routes/cli-routes.ts +561 -0
- package/ccw/src/core/routes/codexlens-routes.ts +806 -0
- package/ccw/src/core/routes/core-memory-routes.ts +605 -0
- package/ccw/src/core/routes/files-routes.ts +428 -0
- package/ccw/src/core/routes/graph-routes.md +164 -0
- package/ccw/src/core/routes/graph-routes.ts +626 -0
- package/ccw/src/core/routes/help-routes.ts +308 -0
- package/ccw/src/core/routes/hooks-routes.ts +405 -0
- package/ccw/src/core/routes/mcp-routes.ts +1271 -0
- package/ccw/src/core/routes/mcp-routes.ts.backup +550 -0
- package/ccw/src/core/routes/mcp-templates-db.ts +268 -0
- package/ccw/src/core/routes/memory-routes.ts +1206 -0
- package/ccw/src/core/routes/rules-routes.ts +526 -0
- package/ccw/src/core/routes/session-routes.ts +467 -0
- package/ccw/src/core/routes/skills-routes.ts +599 -0
- package/ccw/src/core/routes/status-routes.ts +57 -0
- package/ccw/src/core/routes/system-routes.ts +427 -0
- package/ccw/src/core/server.ts +431 -0
- package/ccw/src/core/session-clustering-service.ts +1258 -0
- package/ccw/src/core/session-scanner.ts +283 -0
- package/ccw/src/core/websocket.ts +190 -0
- package/ccw/src/{index.js → index.ts} +1 -0
- package/ccw/src/mcp-server/index.ts +186 -0
- package/ccw/src/templates/assets/css/github-dark.min.css +10 -0
- package/ccw/src/templates/assets/css/github.min.css +10 -0
- package/ccw/src/templates/assets/js/cytoscape.min.js +32 -0
- package/ccw/src/templates/assets/js/d3.min.js +2 -0
- package/ccw/src/templates/assets/js/highlight.min.js +1244 -0
- package/ccw/src/templates/assets/js/lucide.min.js +12 -0
- package/ccw/src/templates/assets/js/marked.min.js +69 -0
- package/ccw/src/templates/assets/js/tailwind.js +83 -0
- package/ccw/src/templates/dashboard-css/01-base.css +11 -0
- package/ccw/src/templates/dashboard-css/02-session.css +22 -0
- package/ccw/src/templates/dashboard-css/04-lite-tasks.css +10 -0
- package/ccw/src/templates/dashboard-css/06-cards.css +10 -4
- package/ccw/src/templates/dashboard-css/07-managers.css +1178 -7
- package/ccw/src/templates/dashboard-css/09-explorer.css +23 -12
- package/ccw/src/templates/dashboard-css/10-cli-status.css +337 -0
- package/ccw/src/templates/dashboard-css/11-cli-history.css +271 -0
- package/ccw/src/templates/dashboard-css/12-cli-legacy.css +796 -0
- package/ccw/src/templates/dashboard-css/13-cli-ccw.css +199 -0
- package/ccw/src/templates/dashboard-css/14-cli-modals.css +258 -0
- package/ccw/src/templates/dashboard-css/15-cli-endpoints.css +305 -0
- package/ccw/src/templates/dashboard-css/16-cli-session.css +241 -0
- package/ccw/src/templates/dashboard-css/17-cli-conversation.css +283 -0
- package/ccw/src/templates/dashboard-css/18-cli-settings.css +160 -0
- package/ccw/src/templates/dashboard-css/19-cli-native-session.css +496 -0
- package/ccw/src/templates/dashboard-css/20-cli-taskqueue.css +188 -0
- package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +310 -0
- package/ccw/src/templates/dashboard-css/22-cli-semantic.css +240 -0
- package/ccw/src/templates/dashboard-css/23-memory.css +2390 -0
- package/ccw/src/templates/dashboard-css/24-prompt-history.css +1089 -0
- package/ccw/src/templates/dashboard-css/25-skills-rules.css +326 -0
- package/ccw/src/templates/dashboard-css/26-claude-manager.css +908 -0
- package/ccw/src/templates/dashboard-css/27-graph-explorer.css +1678 -0
- package/ccw/src/templates/dashboard-css/28-mcp-manager.css +748 -0
- package/ccw/src/templates/dashboard-css/29-help.css +264 -0
- package/ccw/src/templates/dashboard-css/30-core-memory.css +1700 -0
- package/ccw/src/templates/dashboard-js/api.js +162 -142
- package/ccw/src/templates/dashboard-js/components/carousel.js +4 -4
- package/ccw/src/templates/dashboard-js/components/cli-history.js +876 -0
- package/ccw/src/templates/dashboard-js/components/cli-status.js +978 -0
- package/ccw/src/templates/dashboard-js/components/global-notifications.js +508 -219
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +1277 -282
- package/ccw/src/templates/dashboard-js/components/index-manager.js +302 -0
- package/ccw/src/templates/dashboard-js/components/mcp-manager.js +718 -27
- package/ccw/src/templates/dashboard-js/components/modals.js +66 -0
- package/ccw/src/templates/dashboard-js/components/navigation.js +80 -12
- package/ccw/src/templates/dashboard-js/components/notifications.js +758 -194
- package/ccw/src/templates/dashboard-js/components/storage-manager.js +478 -0
- package/ccw/src/templates/dashboard-js/components/tabs-other.js +157 -6
- package/ccw/src/templates/dashboard-js/components/task-queue-sidebar.js +716 -0
- package/ccw/src/templates/dashboard-js/help-i18n.js +272 -0
- package/ccw/src/templates/dashboard-js/i18n.js +2807 -0
- package/ccw/src/templates/dashboard-js/main.js +15 -0
- package/ccw/src/templates/dashboard-js/state.js +243 -42
- package/ccw/src/templates/dashboard-js/utils.js +47 -1
- package/ccw/src/templates/dashboard-js/views/claude-manager.js +912 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +2272 -0
- package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +964 -0
- package/ccw/src/templates/dashboard-js/views/core-memory-clusters.js +503 -0
- package/ccw/src/templates/dashboard-js/views/core-memory.js +782 -0
- package/ccw/src/templates/dashboard-js/views/explorer.js +888 -852
- package/ccw/src/templates/dashboard-js/views/graph-explorer.js +1157 -0
- package/ccw/src/templates/dashboard-js/views/help.js +856 -0
- package/ccw/src/templates/dashboard-js/views/history.js +337 -0
- package/ccw/src/templates/dashboard-js/views/home.js +61 -15
- package/ccw/src/templates/dashboard-js/views/hook-manager.js +311 -43
- package/ccw/src/templates/dashboard-js/views/lite-tasks.js +204 -28
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js +2187 -411
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js.backup +1729 -0
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js.new +928 -0
- package/ccw/src/templates/dashboard-js/views/memory.js +1221 -0
- package/ccw/src/templates/dashboard-js/views/prompt-history.js +713 -0
- package/ccw/src/templates/dashboard-js/views/rules-manager.js +828 -0
- package/ccw/src/templates/dashboard-js/views/session-detail.js +54 -53
- package/ccw/src/templates/dashboard-js/views/skills-manager.js +819 -0
- package/ccw/src/templates/dashboard.html +185 -85
- package/ccw/src/templates/hooks-config-example.json +60 -0
- package/ccw/src/tools/classify-folders.ts +245 -0
- package/ccw/src/tools/cli-config-manager.ts +268 -0
- package/ccw/src/tools/cli-executor.ts +2014 -0
- package/ccw/src/tools/cli-history-store.ts +1195 -0
- package/ccw/src/tools/codex-lens.ts +1141 -0
- package/ccw/src/tools/{convert-tokens-to-css.js → convert-tokens-to-css.ts} +73 -23
- package/ccw/src/tools/core-memory.ts +444 -0
- package/ccw/src/tools/detect-changed-modules.ts +325 -0
- package/ccw/src/tools/{discover-design-files.js → discover-design-files.ts} +74 -24
- package/ccw/src/tools/edit-file.ts +568 -0
- package/ccw/src/tools/{generate-module-docs.js → generate-module-docs.ts} +207 -185
- package/ccw/src/tools/{get-modules-by-depth.js → get-modules-by-depth.ts} +120 -79
- package/ccw/src/tools/index.ts +370 -0
- package/ccw/src/tools/native-session-discovery.ts +795 -0
- package/ccw/src/tools/notifier.ts +129 -0
- package/ccw/src/tools/read-file.ts +410 -0
- package/ccw/src/tools/resume-strategy.ts +345 -0
- package/ccw/src/tools/session-content-parser.ts +619 -0
- package/ccw/src/tools/session-manager.ts +1026 -0
- package/ccw/src/tools/smart-context.ts +228 -0
- package/ccw/src/tools/smart-search.ts +2065 -0
- package/ccw/src/tools/smart-search.ts.backup +1233 -0
- package/ccw/src/tools/storage-manager.ts +455 -0
- package/ccw/src/tools/write-file.ts +222 -0
- package/ccw/src/types/config.ts +11 -0
- package/ccw/src/types/index.ts +3 -0
- package/ccw/src/types/session.ts +25 -0
- package/ccw/src/types/tool.ts +41 -0
- package/ccw/src/utils/{browser-launcher.js → browser-launcher.ts} +10 -8
- package/ccw/src/utils/file-utils.ts +48 -0
- package/ccw/src/utils/{path-resolver.js → path-resolver.ts} +114 -78
- package/ccw/src/utils/path-validator.ts +153 -0
- package/ccw/src/utils/{ui.js → ui.ts} +32 -25
- package/codex-lens/pyproject.toml +48 -0
- package/codex-lens/src/codexlens/.workflow/.cli-history/history.db +0 -0
- package/codex-lens/src/codexlens/__init__.py +28 -0
- package/codex-lens/src/codexlens/__main__.py +14 -0
- package/codex-lens/src/codexlens/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/__main__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/entities.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/errors.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__init__.py +27 -0
- package/codex-lens/src/codexlens/cli/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/commands.py +1931 -0
- package/codex-lens/src/codexlens/cli/embedding_manager.py +620 -0
- package/codex-lens/src/codexlens/cli/model_manager.py +289 -0
- package/codex-lens/src/codexlens/cli/output.py +124 -0
- package/codex-lens/src/codexlens/config.py +201 -0
- package/codex-lens/src/codexlens/entities.py +121 -0
- package/codex-lens/src/codexlens/errors.py +55 -0
- package/codex-lens/src/codexlens/indexing/README.md +77 -0
- package/codex-lens/src/codexlens/indexing/__init__.py +4 -0
- package/codex-lens/src/codexlens/indexing/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/indexing/__pycache__/symbol_extractor.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/indexing/symbol_extractor.py +243 -0
- package/codex-lens/src/codexlens/parsers/__init__.py +8 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/encoding.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/tokenizer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/encoding.py +202 -0
- package/codex-lens/src/codexlens/parsers/factory.py +256 -0
- package/codex-lens/src/codexlens/parsers/tokenizer.py +98 -0
- package/codex-lens/src/codexlens/parsers/treesitter_parser.py +335 -0
- package/codex-lens/src/codexlens/search/__init__.py +15 -0
- package/codex-lens/src/codexlens/search/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/enrichment.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/query_parser.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/chain_search.py +647 -0
- package/codex-lens/src/codexlens/search/enrichment.py +150 -0
- package/codex-lens/src/codexlens/search/hybrid_search.py +313 -0
- package/codex-lens/src/codexlens/search/query_parser.py +242 -0
- package/codex-lens/src/codexlens/search/ranking.py +274 -0
- package/codex-lens/src/codexlens/semantic/__init__.py +39 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/ann_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/code_extractor.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/graph_analyzer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/llm_enhancer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/ann_index.py +414 -0
- package/codex-lens/src/codexlens/semantic/chunker.py +448 -0
- package/codex-lens/src/codexlens/semantic/code_extractor.py +274 -0
- package/codex-lens/src/codexlens/semantic/embedder.py +185 -0
- package/codex-lens/src/codexlens/semantic/vector_store.py +955 -0
- package/codex-lens/src/codexlens/storage/__init__.py +29 -0
- package/codex-lens/src/codexlens/storage/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/file_cache.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/migration_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/registry.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/sqlite_utils.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/dir_index.py +1850 -0
- package/codex-lens/src/codexlens/storage/file_cache.py +32 -0
- package/codex-lens/src/codexlens/storage/index_tree.py +776 -0
- package/codex-lens/src/codexlens/storage/migration_manager.py +154 -0
- package/codex-lens/src/codexlens/storage/migrations/__init__.py +1 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_001_normalize_keywords.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_002_add_token_metadata.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_003_code_relationships.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_005_cleanup_unused_fields.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_001_normalize_keywords.py +123 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_002_add_token_metadata.py +48 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_004_dual_fts.py +232 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_005_cleanup_unused_fields.py +196 -0
- package/codex-lens/src/codexlens/storage/path_mapper.py +274 -0
- package/codex-lens/src/codexlens/storage/registry.py +670 -0
- package/codex-lens/src/codexlens/storage/sqlite_store.py +576 -0
- package/codex-lens/src/codexlens/storage/sqlite_utils.py +64 -0
- package/package.json +4 -1
- package/.claude/commands/memory/tech-research.md +0 -477
- package/.claude/scripts/classify-folders.sh +0 -39
- package/.claude/scripts/convert_tokens_to_css.sh +0 -229
- package/.claude/scripts/detect_changed_modules.sh +0 -161
- package/.claude/scripts/discover-design-files.sh +0 -87
- package/.claude/scripts/extract-animations.js +0 -243
- package/.claude/scripts/extract-computed-styles.js +0 -118
- package/.claude/scripts/extract-layout-structure.js +0 -411
- package/.claude/scripts/generate_module_docs.sh +0 -717
- package/.claude/scripts/get_modules_by_depth.sh +0 -170
- package/.claude/scripts/ui-generate-preview.sh +0 -395
- package/.claude/scripts/ui-instantiate-prototypes.sh +0 -815
- package/.claude/scripts/update_module_claude.sh +0 -337
- package/.claude/workflows/context-search-strategy.md +0 -77
- package/.claude/workflows/intelligent-tools-strategy.md +0 -662
- package/ccw/src/cli.js +0 -119
- package/ccw/src/commands/install.js +0 -324
- package/ccw/src/commands/tool.js +0 -138
- package/ccw/src/core/data-aggregator.js +0 -409
- package/ccw/src/core/server.js +0 -2063
- package/ccw/src/core/session-scanner.js +0 -235
- package/ccw/src/tools/classify-folders.js +0 -204
- package/ccw/src/tools/detect-changed-modules.js +0 -288
- package/ccw/src/tools/edit-file.js +0 -266
- package/ccw/src/tools/index.js +0 -176
- package/ccw/src/utils/file-utils.js +0 -48
|
@@ -0,0 +1,776 @@
|
|
|
1
|
+
"""Hierarchical index tree builder for CodexLens.
|
|
2
|
+
|
|
3
|
+
Constructs a bottom-up directory index tree with parallel processing support.
|
|
4
|
+
Each directory maintains its own _index.db with files and subdirectory links.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import os
|
|
11
|
+
import time
|
|
12
|
+
from concurrent.futures import ProcessPoolExecutor, as_completed
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Dict, List, Optional, Set
|
|
16
|
+
|
|
17
|
+
from codexlens.config import Config
|
|
18
|
+
from codexlens.parsers.factory import ParserFactory
|
|
19
|
+
from codexlens.storage.dir_index import DirIndexStore
|
|
20
|
+
from codexlens.storage.path_mapper import PathMapper
|
|
21
|
+
from codexlens.storage.registry import ProjectInfo, RegistryStore
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class BuildResult:
|
|
26
|
+
"""Complete build operation result."""
|
|
27
|
+
|
|
28
|
+
project_id: int
|
|
29
|
+
source_root: Path
|
|
30
|
+
index_root: Path
|
|
31
|
+
total_files: int
|
|
32
|
+
total_dirs: int
|
|
33
|
+
errors: List[str]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class DirBuildResult:
|
|
38
|
+
"""Single directory build result."""
|
|
39
|
+
|
|
40
|
+
source_path: Path
|
|
41
|
+
index_path: Path
|
|
42
|
+
files_count: int
|
|
43
|
+
symbols_count: int
|
|
44
|
+
subdirs: List[str] # Subdirectory names
|
|
45
|
+
error: Optional[str] = None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class IndexTreeBuilder:
|
|
49
|
+
"""Hierarchical index tree builder with parallel processing.
|
|
50
|
+
|
|
51
|
+
Builds directory indexes bottom-up to enable proper subdirectory linking.
|
|
52
|
+
Each directory gets its own _index.db containing:
|
|
53
|
+
- Files in that directory
|
|
54
|
+
- Links to child directory indexes
|
|
55
|
+
- Symbols and FTS5 search
|
|
56
|
+
|
|
57
|
+
Attributes:
|
|
58
|
+
registry: Global project registry
|
|
59
|
+
mapper: Path mapping between source and index
|
|
60
|
+
config: CodexLens configuration
|
|
61
|
+
parser_factory: Parser factory for symbol extraction
|
|
62
|
+
logger: Logger instance
|
|
63
|
+
IGNORE_DIRS: Set of directory names to skip during indexing
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
# Directories to skip during indexing
|
|
67
|
+
IGNORE_DIRS: Set[str] = {
|
|
68
|
+
".git",
|
|
69
|
+
".venv",
|
|
70
|
+
"venv",
|
|
71
|
+
"node_modules",
|
|
72
|
+
"__pycache__",
|
|
73
|
+
".codexlens",
|
|
74
|
+
".idea",
|
|
75
|
+
".vscode",
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
def __init__(
|
|
79
|
+
self, registry: RegistryStore, mapper: PathMapper, config: Config = None, incremental: bool = True
|
|
80
|
+
):
|
|
81
|
+
"""Initialize the index tree builder.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
registry: Global registry store for project tracking
|
|
85
|
+
mapper: Path mapper for source to index conversions
|
|
86
|
+
config: CodexLens configuration (uses defaults if None)
|
|
87
|
+
incremental: Enable incremental indexing (default True)
|
|
88
|
+
"""
|
|
89
|
+
self.registry = registry
|
|
90
|
+
self.mapper = mapper
|
|
91
|
+
self.config = config or Config()
|
|
92
|
+
self.parser_factory = ParserFactory(self.config)
|
|
93
|
+
self.logger = logging.getLogger(__name__)
|
|
94
|
+
self.incremental = incremental
|
|
95
|
+
|
|
96
|
+
def build(
|
|
97
|
+
self,
|
|
98
|
+
source_root: Path,
|
|
99
|
+
languages: List[str] = None,
|
|
100
|
+
workers: int = None,
|
|
101
|
+
force_full: bool = False,
|
|
102
|
+
) -> BuildResult:
|
|
103
|
+
"""Build complete index tree for a project.
|
|
104
|
+
|
|
105
|
+
Process:
|
|
106
|
+
1. Register project in registry
|
|
107
|
+
2. Collect all directories grouped by depth
|
|
108
|
+
3. Build indexes bottom-up (deepest first)
|
|
109
|
+
4. Link subdirectories to parents
|
|
110
|
+
5. Update project statistics
|
|
111
|
+
6. Cleanup deleted files (if incremental mode)
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
source_root: Project root directory to index
|
|
115
|
+
languages: Optional list of language IDs to limit indexing
|
|
116
|
+
workers: Number of parallel worker processes
|
|
117
|
+
force_full: Force full reindex (override incremental mode)
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
BuildResult with statistics and errors
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
ValueError: If source_root doesn't exist
|
|
124
|
+
"""
|
|
125
|
+
source_root = source_root.resolve()
|
|
126
|
+
if not source_root.exists():
|
|
127
|
+
raise ValueError(f"Source root does not exist: {source_root}")
|
|
128
|
+
|
|
129
|
+
# Auto-detect optimal worker count if not specified
|
|
130
|
+
if workers is None:
|
|
131
|
+
workers = min(os.cpu_count() or 4, 16) # Cap at 16 workers
|
|
132
|
+
self.logger.debug("Auto-detected %d workers for parallel indexing", workers)
|
|
133
|
+
|
|
134
|
+
# Override incremental mode if force_full is True
|
|
135
|
+
use_incremental = self.incremental and not force_full
|
|
136
|
+
if force_full:
|
|
137
|
+
self.logger.info("Building index tree for %s (FULL reindex)", source_root)
|
|
138
|
+
else:
|
|
139
|
+
self.logger.info("Building index tree for %s (incremental=%s)", source_root, use_incremental)
|
|
140
|
+
|
|
141
|
+
# Register project
|
|
142
|
+
index_root = self.mapper.source_to_index_dir(source_root)
|
|
143
|
+
project_info = self.registry.register_project(source_root, index_root)
|
|
144
|
+
|
|
145
|
+
# Report progress: discovering files (5%)
|
|
146
|
+
print("Discovering files...", flush=True)
|
|
147
|
+
|
|
148
|
+
# Collect directories by depth
|
|
149
|
+
dirs_by_depth = self._collect_dirs_by_depth(source_root, languages)
|
|
150
|
+
|
|
151
|
+
if not dirs_by_depth:
|
|
152
|
+
self.logger.warning("No indexable directories found in %s", source_root)
|
|
153
|
+
return BuildResult(
|
|
154
|
+
project_id=project_info.id,
|
|
155
|
+
source_root=source_root,
|
|
156
|
+
index_root=index_root,
|
|
157
|
+
total_files=0,
|
|
158
|
+
total_dirs=0,
|
|
159
|
+
errors=["No indexable directories found"],
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# Calculate total directories for progress tracking
|
|
163
|
+
total_dirs_to_process = sum(len(dirs) for dirs in dirs_by_depth.values())
|
|
164
|
+
processed_dirs = 0
|
|
165
|
+
|
|
166
|
+
# Report progress: building index (10%)
|
|
167
|
+
print("Building index...", flush=True)
|
|
168
|
+
|
|
169
|
+
total_files = 0
|
|
170
|
+
total_dirs = 0
|
|
171
|
+
all_errors: List[str] = []
|
|
172
|
+
all_results: List[DirBuildResult] = [] # Store all results for subdir linking
|
|
173
|
+
|
|
174
|
+
# Build bottom-up (highest depth first)
|
|
175
|
+
max_depth = max(dirs_by_depth.keys())
|
|
176
|
+
for depth in range(max_depth, -1, -1):
|
|
177
|
+
if depth not in dirs_by_depth:
|
|
178
|
+
continue
|
|
179
|
+
|
|
180
|
+
dirs = dirs_by_depth[depth]
|
|
181
|
+
self.logger.info("Building %d directories at depth %d", len(dirs), depth)
|
|
182
|
+
|
|
183
|
+
# Build directories at this level in parallel
|
|
184
|
+
results = self._build_level_parallel(dirs, languages, workers)
|
|
185
|
+
all_results.extend(results)
|
|
186
|
+
|
|
187
|
+
# Process results
|
|
188
|
+
for result in results:
|
|
189
|
+
if result.error:
|
|
190
|
+
all_errors.append(f"{result.source_path}: {result.error}")
|
|
191
|
+
processed_dirs += 1
|
|
192
|
+
continue
|
|
193
|
+
|
|
194
|
+
total_files += result.files_count
|
|
195
|
+
total_dirs += 1
|
|
196
|
+
processed_dirs += 1
|
|
197
|
+
|
|
198
|
+
# Report progress for each processed directory (10-80%)
|
|
199
|
+
# Use "Processing file" format for frontend parser compatibility
|
|
200
|
+
progress_percent = 10 + int((processed_dirs / total_dirs_to_process) * 70)
|
|
201
|
+
print(f"Processing file {processed_dirs}/{total_dirs_to_process}: {result.source_path.name}", flush=True)
|
|
202
|
+
|
|
203
|
+
# Register directory in registry
|
|
204
|
+
self.registry.register_dir(
|
|
205
|
+
project_id=project_info.id,
|
|
206
|
+
source_path=result.source_path,
|
|
207
|
+
index_path=result.index_path,
|
|
208
|
+
depth=self.mapper.get_relative_depth(result.source_path, source_root),
|
|
209
|
+
files_count=result.files_count,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# Report progress: linking subdirectories (80%)
|
|
213
|
+
print("Linking subdirectories...", flush=True)
|
|
214
|
+
|
|
215
|
+
# After building all directories, link subdirectories to parents
|
|
216
|
+
# This needs to happen after all indexes exist
|
|
217
|
+
for result in all_results:
|
|
218
|
+
if result.error:
|
|
219
|
+
continue
|
|
220
|
+
# Link children to this directory
|
|
221
|
+
self._link_children_to_parent(result.source_path, all_results)
|
|
222
|
+
|
|
223
|
+
# Cleanup deleted files if in incremental mode
|
|
224
|
+
if use_incremental:
|
|
225
|
+
# Report progress: cleaning up (90%)
|
|
226
|
+
print("Cleaning up deleted files...", flush=True)
|
|
227
|
+
self.logger.info("Cleaning up deleted files...")
|
|
228
|
+
total_deleted = 0
|
|
229
|
+
for result in all_results:
|
|
230
|
+
if result.error:
|
|
231
|
+
continue
|
|
232
|
+
try:
|
|
233
|
+
with DirIndexStore(result.index_path) as store:
|
|
234
|
+
deleted_count = store.cleanup_deleted_files(result.source_path)
|
|
235
|
+
total_deleted += deleted_count
|
|
236
|
+
if deleted_count > 0:
|
|
237
|
+
self.logger.debug("Removed %d deleted files from %s", deleted_count, result.source_path)
|
|
238
|
+
except Exception as exc:
|
|
239
|
+
self.logger.warning("Cleanup failed for %s: %s", result.source_path, exc)
|
|
240
|
+
|
|
241
|
+
if total_deleted > 0:
|
|
242
|
+
self.logger.info("Removed %d deleted files from index", total_deleted)
|
|
243
|
+
|
|
244
|
+
# Report progress: finalizing (95%)
|
|
245
|
+
print("Finalizing...", flush=True)
|
|
246
|
+
|
|
247
|
+
# Update project statistics
|
|
248
|
+
self.registry.update_project_stats(source_root, total_files, total_dirs)
|
|
249
|
+
|
|
250
|
+
# Report completion (100%)
|
|
251
|
+
print(f"Indexed {total_files} files", flush=True)
|
|
252
|
+
|
|
253
|
+
self.logger.info(
|
|
254
|
+
"Index build complete: %d files, %d directories, %d errors",
|
|
255
|
+
total_files,
|
|
256
|
+
total_dirs,
|
|
257
|
+
len(all_errors),
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
return BuildResult(
|
|
261
|
+
project_id=project_info.id,
|
|
262
|
+
source_root=source_root,
|
|
263
|
+
index_root=index_root,
|
|
264
|
+
total_files=total_files,
|
|
265
|
+
total_dirs=total_dirs,
|
|
266
|
+
errors=all_errors,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
def update_subtree(
|
|
270
|
+
self,
|
|
271
|
+
source_path: Path,
|
|
272
|
+
languages: List[str] = None,
|
|
273
|
+
workers: int = None,
|
|
274
|
+
) -> BuildResult:
|
|
275
|
+
"""Incrementally update a subtree.
|
|
276
|
+
|
|
277
|
+
Rebuilds indexes for the specified directory and all subdirectories.
|
|
278
|
+
Useful for incremental updates when only part of the tree changed.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
source_path: Root of subtree to update
|
|
282
|
+
languages: Optional list of language IDs to limit indexing
|
|
283
|
+
workers: Number of parallel worker processes
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
BuildResult for the subtree
|
|
287
|
+
|
|
288
|
+
Raises:
|
|
289
|
+
ValueError: If source_path is not indexed
|
|
290
|
+
"""
|
|
291
|
+
source_path = source_path.resolve()
|
|
292
|
+
project_root = self.mapper.get_project_root(source_path)
|
|
293
|
+
|
|
294
|
+
# Get project info
|
|
295
|
+
project_info = self.registry.get_project(project_root)
|
|
296
|
+
if not project_info:
|
|
297
|
+
raise ValueError(f"Directory not indexed: {source_path}")
|
|
298
|
+
|
|
299
|
+
self.logger.info("Updating subtree at %s", source_path)
|
|
300
|
+
|
|
301
|
+
# Use build logic but start from source_path
|
|
302
|
+
return self.build(source_path, languages, workers)
|
|
303
|
+
|
|
304
|
+
def rebuild_dir(self, source_path: Path) -> DirBuildResult:
|
|
305
|
+
"""Rebuild index for a single directory.
|
|
306
|
+
|
|
307
|
+
Only rebuilds the specified directory, does not touch subdirectories.
|
|
308
|
+
Useful for updating a single directory after file changes.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
source_path: Directory to rebuild
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
DirBuildResult for the directory
|
|
315
|
+
"""
|
|
316
|
+
source_path = source_path.resolve()
|
|
317
|
+
self.logger.info("Rebuilding directory %s", source_path)
|
|
318
|
+
return self._build_single_dir(source_path)
|
|
319
|
+
|
|
320
|
+
# === Internal Methods ===
|
|
321
|
+
|
|
322
|
+
def _collect_dirs_by_depth(
|
|
323
|
+
self, source_root: Path, languages: List[str] = None
|
|
324
|
+
) -> Dict[int, List[Path]]:
|
|
325
|
+
"""Collect all indexable directories grouped by depth.
|
|
326
|
+
|
|
327
|
+
Walks the directory tree and groups directories by their depth
|
|
328
|
+
relative to source_root. Depth 0 is the root itself.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
source_root: Root directory to start from
|
|
332
|
+
languages: Optional language filter
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
Dictionary mapping depth to list of directory paths
|
|
336
|
+
Example: {0: [root], 1: [src, tests], 2: [src/api, src/utils]}
|
|
337
|
+
"""
|
|
338
|
+
source_root = source_root.resolve()
|
|
339
|
+
dirs_by_depth: Dict[int, List[Path]] = {}
|
|
340
|
+
|
|
341
|
+
# Always include the root directory at depth 0 for chain search entry point
|
|
342
|
+
dirs_by_depth[0] = [source_root]
|
|
343
|
+
|
|
344
|
+
for root, dirnames, _ in os.walk(source_root):
|
|
345
|
+
# Filter out ignored directories
|
|
346
|
+
dirnames[:] = [
|
|
347
|
+
d
|
|
348
|
+
for d in dirnames
|
|
349
|
+
if d not in self.IGNORE_DIRS and not d.startswith(".")
|
|
350
|
+
]
|
|
351
|
+
|
|
352
|
+
root_path = Path(root)
|
|
353
|
+
|
|
354
|
+
# Skip root (already added)
|
|
355
|
+
if root_path == source_root:
|
|
356
|
+
continue
|
|
357
|
+
|
|
358
|
+
# Check if this directory should be indexed
|
|
359
|
+
if not self._should_index_dir(root_path, languages):
|
|
360
|
+
continue
|
|
361
|
+
|
|
362
|
+
# Calculate depth relative to source_root
|
|
363
|
+
try:
|
|
364
|
+
depth = len(root_path.relative_to(source_root).parts)
|
|
365
|
+
except ValueError:
|
|
366
|
+
continue
|
|
367
|
+
|
|
368
|
+
if depth not in dirs_by_depth:
|
|
369
|
+
dirs_by_depth[depth] = []
|
|
370
|
+
|
|
371
|
+
dirs_by_depth[depth].append(root_path)
|
|
372
|
+
|
|
373
|
+
return dirs_by_depth
|
|
374
|
+
|
|
375
|
+
def _should_index_dir(self, dir_path: Path, languages: List[str] = None) -> bool:
|
|
376
|
+
"""Check if directory should be indexed.
|
|
377
|
+
|
|
378
|
+
A directory is indexed if:
|
|
379
|
+
1. It's not in IGNORE_DIRS
|
|
380
|
+
2. It doesn't start with '.'
|
|
381
|
+
3. It contains at least one supported language file
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
dir_path: Directory to check
|
|
385
|
+
languages: Optional language filter
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
True if directory should be indexed
|
|
389
|
+
"""
|
|
390
|
+
# Check directory name
|
|
391
|
+
if dir_path.name in self.IGNORE_DIRS or dir_path.name.startswith("."):
|
|
392
|
+
return False
|
|
393
|
+
|
|
394
|
+
# Check for supported files in this directory
|
|
395
|
+
source_files = self._iter_source_files(dir_path, languages)
|
|
396
|
+
return len(source_files) > 0
|
|
397
|
+
|
|
398
|
+
def _build_level_parallel(
|
|
399
|
+
self, dirs: List[Path], languages: List[str], workers: int
|
|
400
|
+
) -> List[DirBuildResult]:
|
|
401
|
+
"""Build multiple directories in parallel.
|
|
402
|
+
|
|
403
|
+
Uses ProcessPoolExecutor to build directories concurrently.
|
|
404
|
+
All directories at the same level are independent and can be
|
|
405
|
+
processed in parallel.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
dirs: List of directories to build
|
|
409
|
+
languages: Language filter
|
|
410
|
+
workers: Number of worker processes
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
List of DirBuildResult objects
|
|
414
|
+
"""
|
|
415
|
+
results: List[DirBuildResult] = []
|
|
416
|
+
|
|
417
|
+
if not dirs:
|
|
418
|
+
return results
|
|
419
|
+
|
|
420
|
+
# For single directory, avoid overhead of process pool
|
|
421
|
+
if len(dirs) == 1:
|
|
422
|
+
result = self._build_single_dir(dirs[0], languages)
|
|
423
|
+
return [result]
|
|
424
|
+
|
|
425
|
+
# Prepare arguments for worker processes
|
|
426
|
+
config_dict = {
|
|
427
|
+
"data_dir": str(self.config.data_dir),
|
|
428
|
+
"supported_languages": self.config.supported_languages,
|
|
429
|
+
"parsing_rules": self.config.parsing_rules,
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
worker_args = [
|
|
433
|
+
(
|
|
434
|
+
dir_path,
|
|
435
|
+
self.mapper.source_to_index_db(dir_path),
|
|
436
|
+
languages,
|
|
437
|
+
config_dict,
|
|
438
|
+
)
|
|
439
|
+
for dir_path in dirs
|
|
440
|
+
]
|
|
441
|
+
|
|
442
|
+
# Execute in parallel
|
|
443
|
+
with ProcessPoolExecutor(max_workers=workers) as executor:
|
|
444
|
+
futures = {
|
|
445
|
+
executor.submit(_build_dir_worker, args): args[0]
|
|
446
|
+
for args in worker_args
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
for future in as_completed(futures):
|
|
450
|
+
try:
|
|
451
|
+
result = future.result()
|
|
452
|
+
results.append(result)
|
|
453
|
+
except Exception as exc:
|
|
454
|
+
dir_path = futures[future]
|
|
455
|
+
self.logger.error("Failed to build %s: %s", dir_path, exc)
|
|
456
|
+
results.append(
|
|
457
|
+
DirBuildResult(
|
|
458
|
+
source_path=dir_path,
|
|
459
|
+
index_path=self.mapper.source_to_index_db(dir_path),
|
|
460
|
+
files_count=0,
|
|
461
|
+
symbols_count=0,
|
|
462
|
+
subdirs=[],
|
|
463
|
+
error=str(exc),
|
|
464
|
+
)
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
return results
|
|
468
|
+
|
|
469
|
+
def _build_single_dir(
|
|
470
|
+
self, dir_path: Path, languages: List[str] = None
|
|
471
|
+
) -> DirBuildResult:
|
|
472
|
+
"""Build index for a single directory.
|
|
473
|
+
|
|
474
|
+
Creates _index.db and indexes all files in the directory.
|
|
475
|
+
Does not recurse into subdirectories.
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
dir_path: Directory to index
|
|
479
|
+
languages: Optional language filter
|
|
480
|
+
|
|
481
|
+
Returns:
|
|
482
|
+
DirBuildResult with statistics and subdirectory list
|
|
483
|
+
"""
|
|
484
|
+
dir_path = dir_path.resolve()
|
|
485
|
+
index_db_path = self.mapper.source_to_index_db(dir_path)
|
|
486
|
+
|
|
487
|
+
try:
|
|
488
|
+
# Ensure index directory exists
|
|
489
|
+
index_db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
490
|
+
|
|
491
|
+
# Create directory index
|
|
492
|
+
store = DirIndexStore(index_db_path)
|
|
493
|
+
store.initialize()
|
|
494
|
+
|
|
495
|
+
# Get source files in this directory only
|
|
496
|
+
source_files = self._iter_source_files(dir_path, languages)
|
|
497
|
+
|
|
498
|
+
files_count = 0
|
|
499
|
+
symbols_count = 0
|
|
500
|
+
skipped_count = 0
|
|
501
|
+
|
|
502
|
+
for file_path in source_files:
|
|
503
|
+
try:
|
|
504
|
+
# Check if file needs reindexing (incremental mode)
|
|
505
|
+
if self.incremental and not store.needs_reindex(file_path):
|
|
506
|
+
skipped_count += 1
|
|
507
|
+
continue
|
|
508
|
+
|
|
509
|
+
# Read and parse file
|
|
510
|
+
text = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
511
|
+
language_id = self.config.language_for_path(file_path)
|
|
512
|
+
if not language_id:
|
|
513
|
+
continue
|
|
514
|
+
|
|
515
|
+
parser = self.parser_factory.get_parser(language_id)
|
|
516
|
+
indexed_file = parser.parse(text, file_path)
|
|
517
|
+
|
|
518
|
+
# Add to directory index
|
|
519
|
+
store.add_file(
|
|
520
|
+
name=file_path.name,
|
|
521
|
+
full_path=file_path,
|
|
522
|
+
content=text,
|
|
523
|
+
language=language_id,
|
|
524
|
+
symbols=indexed_file.symbols,
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
files_count += 1
|
|
528
|
+
symbols_count += len(indexed_file.symbols)
|
|
529
|
+
|
|
530
|
+
except Exception as exc:
|
|
531
|
+
self.logger.debug("Failed to index %s: %s", file_path, exc)
|
|
532
|
+
continue
|
|
533
|
+
|
|
534
|
+
# Get list of subdirectories
|
|
535
|
+
subdirs = [
|
|
536
|
+
d.name
|
|
537
|
+
for d in dir_path.iterdir()
|
|
538
|
+
if d.is_dir()
|
|
539
|
+
and d.name not in self.IGNORE_DIRS
|
|
540
|
+
and not d.name.startswith(".")
|
|
541
|
+
]
|
|
542
|
+
|
|
543
|
+
store.close()
|
|
544
|
+
|
|
545
|
+
if skipped_count > 0:
|
|
546
|
+
self.logger.debug(
|
|
547
|
+
"Built %s: %d files indexed, %d skipped (unchanged), %d symbols, %d subdirs",
|
|
548
|
+
dir_path,
|
|
549
|
+
files_count,
|
|
550
|
+
skipped_count,
|
|
551
|
+
symbols_count,
|
|
552
|
+
len(subdirs),
|
|
553
|
+
)
|
|
554
|
+
else:
|
|
555
|
+
self.logger.debug(
|
|
556
|
+
"Built %s: %d files, %d symbols, %d subdirs",
|
|
557
|
+
dir_path,
|
|
558
|
+
files_count,
|
|
559
|
+
symbols_count,
|
|
560
|
+
len(subdirs),
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
return DirBuildResult(
|
|
564
|
+
source_path=dir_path,
|
|
565
|
+
index_path=index_db_path,
|
|
566
|
+
files_count=files_count,
|
|
567
|
+
symbols_count=symbols_count,
|
|
568
|
+
subdirs=subdirs,
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
except Exception as exc:
|
|
572
|
+
self.logger.error("Failed to build directory %s: %s", dir_path, exc)
|
|
573
|
+
return DirBuildResult(
|
|
574
|
+
source_path=dir_path,
|
|
575
|
+
index_path=index_db_path,
|
|
576
|
+
files_count=0,
|
|
577
|
+
symbols_count=0,
|
|
578
|
+
subdirs=[],
|
|
579
|
+
error=str(exc),
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
def _link_children_to_parent(
|
|
583
|
+
self, parent_path: Path, all_results: List[DirBuildResult]
|
|
584
|
+
) -> None:
|
|
585
|
+
"""Link child directory indexes to parent's subdirs table.
|
|
586
|
+
|
|
587
|
+
Finds all direct children of parent_path in all_results and
|
|
588
|
+
registers them as subdirectories in the parent's index.
|
|
589
|
+
|
|
590
|
+
Args:
|
|
591
|
+
parent_path: Parent directory path
|
|
592
|
+
all_results: List of all build results
|
|
593
|
+
"""
|
|
594
|
+
parent_index_db = self.mapper.source_to_index_db(parent_path)
|
|
595
|
+
|
|
596
|
+
try:
|
|
597
|
+
store = DirIndexStore(parent_index_db)
|
|
598
|
+
store.initialize()
|
|
599
|
+
|
|
600
|
+
for result in all_results:
|
|
601
|
+
# Only register direct children (parent is one level up)
|
|
602
|
+
if result.source_path.parent != parent_path:
|
|
603
|
+
continue
|
|
604
|
+
|
|
605
|
+
if result.error:
|
|
606
|
+
continue
|
|
607
|
+
|
|
608
|
+
# Register subdirectory link
|
|
609
|
+
store.register_subdir(
|
|
610
|
+
name=result.source_path.name,
|
|
611
|
+
index_path=result.index_path,
|
|
612
|
+
files_count=result.files_count,
|
|
613
|
+
direct_files=result.files_count,
|
|
614
|
+
)
|
|
615
|
+
self.logger.debug(
|
|
616
|
+
"Linked %s to parent %s",
|
|
617
|
+
result.source_path.name,
|
|
618
|
+
parent_path,
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
store.close()
|
|
622
|
+
|
|
623
|
+
except Exception as exc:
|
|
624
|
+
self.logger.error(
|
|
625
|
+
"Failed to link children to %s: %s", parent_path, exc
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
def _iter_source_files(
|
|
629
|
+
self, dir_path: Path, languages: List[str] = None
|
|
630
|
+
) -> List[Path]:
|
|
631
|
+
"""Iterate source files in directory (non-recursive).
|
|
632
|
+
|
|
633
|
+
Returns files in the specified directory that match language filters.
|
|
634
|
+
Does not recurse into subdirectories.
|
|
635
|
+
|
|
636
|
+
Args:
|
|
637
|
+
dir_path: Directory to scan
|
|
638
|
+
languages: Optional language filter
|
|
639
|
+
|
|
640
|
+
Returns:
|
|
641
|
+
List of source file paths
|
|
642
|
+
"""
|
|
643
|
+
files: List[Path] = []
|
|
644
|
+
|
|
645
|
+
if not dir_path.is_dir():
|
|
646
|
+
return files
|
|
647
|
+
|
|
648
|
+
for item in dir_path.iterdir():
|
|
649
|
+
if not item.is_file():
|
|
650
|
+
continue
|
|
651
|
+
|
|
652
|
+
if item.name.startswith("."):
|
|
653
|
+
continue
|
|
654
|
+
|
|
655
|
+
# Check language support
|
|
656
|
+
language_id = self.config.language_for_path(item)
|
|
657
|
+
if not language_id:
|
|
658
|
+
continue
|
|
659
|
+
|
|
660
|
+
# Apply language filter
|
|
661
|
+
if languages and language_id not in languages:
|
|
662
|
+
continue
|
|
663
|
+
|
|
664
|
+
files.append(item)
|
|
665
|
+
|
|
666
|
+
return files
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
# === Worker Function for ProcessPoolExecutor ===
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
def _build_dir_worker(args: tuple) -> DirBuildResult:
|
|
673
|
+
"""Worker function for parallel directory building.
|
|
674
|
+
|
|
675
|
+
Must be at module level for ProcessPoolExecutor pickling.
|
|
676
|
+
Reconstructs necessary objects from serializable arguments.
|
|
677
|
+
|
|
678
|
+
Args:
|
|
679
|
+
args: Tuple of (dir_path, index_db_path, languages, config_dict)
|
|
680
|
+
|
|
681
|
+
Returns:
|
|
682
|
+
DirBuildResult for the directory
|
|
683
|
+
"""
|
|
684
|
+
dir_path, index_db_path, languages, config_dict = args
|
|
685
|
+
|
|
686
|
+
# Reconstruct config
|
|
687
|
+
config = Config(
|
|
688
|
+
data_dir=Path(config_dict["data_dir"]),
|
|
689
|
+
supported_languages=config_dict["supported_languages"],
|
|
690
|
+
parsing_rules=config_dict["parsing_rules"],
|
|
691
|
+
)
|
|
692
|
+
|
|
693
|
+
parser_factory = ParserFactory(config)
|
|
694
|
+
|
|
695
|
+
try:
|
|
696
|
+
# Ensure index directory exists
|
|
697
|
+
index_db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
698
|
+
|
|
699
|
+
# Create directory index
|
|
700
|
+
store = DirIndexStore(index_db_path)
|
|
701
|
+
store.initialize()
|
|
702
|
+
|
|
703
|
+
files_count = 0
|
|
704
|
+
symbols_count = 0
|
|
705
|
+
|
|
706
|
+
# Index files in this directory
|
|
707
|
+
for item in dir_path.iterdir():
|
|
708
|
+
if not item.is_file():
|
|
709
|
+
continue
|
|
710
|
+
|
|
711
|
+
if item.name.startswith("."):
|
|
712
|
+
continue
|
|
713
|
+
|
|
714
|
+
language_id = config.language_for_path(item)
|
|
715
|
+
if not language_id:
|
|
716
|
+
continue
|
|
717
|
+
|
|
718
|
+
if languages and language_id not in languages:
|
|
719
|
+
continue
|
|
720
|
+
|
|
721
|
+
try:
|
|
722
|
+
text = item.read_text(encoding="utf-8", errors="ignore")
|
|
723
|
+
parser = parser_factory.get_parser(language_id)
|
|
724
|
+
indexed_file = parser.parse(text, item)
|
|
725
|
+
|
|
726
|
+
store.add_file(
|
|
727
|
+
name=item.name,
|
|
728
|
+
full_path=item,
|
|
729
|
+
content=text,
|
|
730
|
+
language=language_id,
|
|
731
|
+
symbols=indexed_file.symbols,
|
|
732
|
+
)
|
|
733
|
+
|
|
734
|
+
files_count += 1
|
|
735
|
+
symbols_count += len(indexed_file.symbols)
|
|
736
|
+
|
|
737
|
+
except Exception:
|
|
738
|
+
continue
|
|
739
|
+
|
|
740
|
+
# Get subdirectories
|
|
741
|
+
ignore_dirs = {
|
|
742
|
+
".git",
|
|
743
|
+
".venv",
|
|
744
|
+
"venv",
|
|
745
|
+
"node_modules",
|
|
746
|
+
"__pycache__",
|
|
747
|
+
".codexlens",
|
|
748
|
+
".idea",
|
|
749
|
+
".vscode",
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
subdirs = [
|
|
753
|
+
d.name
|
|
754
|
+
for d in dir_path.iterdir()
|
|
755
|
+
if d.is_dir() and d.name not in ignore_dirs and not d.name.startswith(".")
|
|
756
|
+
]
|
|
757
|
+
|
|
758
|
+
store.close()
|
|
759
|
+
|
|
760
|
+
return DirBuildResult(
|
|
761
|
+
source_path=dir_path,
|
|
762
|
+
index_path=index_db_path,
|
|
763
|
+
files_count=files_count,
|
|
764
|
+
symbols_count=symbols_count,
|
|
765
|
+
subdirs=subdirs,
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
except Exception as exc:
|
|
769
|
+
return DirBuildResult(
|
|
770
|
+
source_path=dir_path,
|
|
771
|
+
index_path=index_db_path,
|
|
772
|
+
files_count=0,
|
|
773
|
+
symbols_count=0,
|
|
774
|
+
subdirs=[],
|
|
775
|
+
error=str(exc),
|
|
776
|
+
)
|