claude-code-workflow 6.2.1 → 6.2.3
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 -0
- package/.claude/agents/cli-execution-agent.md +267 -0
- package/.claude/agents/cli-explore-agent.md +182 -0
- package/.claude/agents/cli-lite-planning-agent.md +446 -0
- package/.claude/agents/cli-planning-agent.md +558 -0
- package/.claude/agents/code-developer.md +311 -0
- package/.claude/agents/conceptual-planning-agent.md +308 -0
- package/.claude/agents/context-search-agent.md +581 -0
- package/.claude/agents/doc-generator.md +330 -0
- package/.claude/agents/memory-bridge.md +94 -0
- package/.claude/agents/test-context-search-agent.md +400 -0
- package/.claude/agents/test-fix-agent.md +344 -0
- package/.claude/agents/ui-design-agent.md +593 -0
- package/.claude/agents/universal-executor.md +131 -0
- package/.claude/commands/clean.md +516 -0
- package/.claude/commands/cli/cli-init.md +440 -0
- package/.claude/commands/enhance-prompt.md +93 -0
- package/.claude/commands/memory/code-map-memory.md +687 -0
- package/.claude/commands/memory/compact.md +383 -0
- package/.claude/commands/memory/docs-full-cli.md +471 -0
- package/.claude/commands/memory/docs-related-cli.md +386 -0
- package/.claude/commands/memory/docs.md +615 -0
- package/.claude/commands/memory/load-skill-memory.md +182 -0
- package/.claude/commands/memory/load.md +240 -0
- package/.claude/commands/memory/skill-memory.md +525 -0
- package/.claude/commands/memory/style-skill-memory.md +396 -0
- package/.claude/commands/memory/tech-research-rules.md +310 -0
- package/.claude/commands/memory/update-full.md +332 -0
- package/.claude/commands/memory/update-related.md +332 -0
- package/.claude/commands/memory/workflow-skill-memory.md +517 -0
- package/.claude/commands/task/breakdown.md +204 -0
- package/.claude/commands/task/create.md +152 -0
- package/.claude/commands/task/execute.md +270 -0
- package/.claude/commands/task/replan.md +437 -0
- package/.claude/commands/version.md +254 -0
- package/.claude/commands/workflow/action-plan-verify.md +447 -0
- package/.claude/commands/workflow/brainstorm/api-designer.md +587 -0
- package/.claude/commands/workflow/brainstorm/artifacts.md +453 -0
- package/.claude/commands/workflow/brainstorm/auto-parallel.md +443 -0
- package/.claude/commands/workflow/brainstorm/data-architect.md +220 -0
- package/.claude/commands/workflow/brainstorm/product-manager.md +200 -0
- package/.claude/commands/workflow/brainstorm/product-owner.md +200 -0
- package/.claude/commands/workflow/brainstorm/scrum-master.md +200 -0
- package/.claude/commands/workflow/brainstorm/subject-matter-expert.md +200 -0
- package/.claude/commands/workflow/brainstorm/synthesis.md +398 -0
- package/.claude/commands/workflow/brainstorm/system-architect.md +389 -0
- package/.claude/commands/workflow/brainstorm/ui-designer.md +221 -0
- package/.claude/commands/workflow/brainstorm/ux-expert.md +221 -0
- package/.claude/commands/workflow/debug.md +321 -0
- package/.claude/commands/workflow/execute.md +475 -0
- package/.claude/commands/workflow/init.md +165 -0
- package/.claude/commands/workflow/lite-execute.md +792 -0
- package/.claude/commands/workflow/lite-fix.md +623 -0
- package/.claude/commands/workflow/lite-plan.md +610 -0
- package/.claude/commands/workflow/plan.md +551 -0
- package/.claude/commands/workflow/replan.md +515 -0
- package/.claude/commands/workflow/review-fix.md +606 -0
- package/.claude/commands/workflow/review-module-cycle.md +767 -0
- package/.claude/commands/workflow/review-session-cycle.md +778 -0
- package/.claude/commands/workflow/review.md +297 -0
- package/.claude/commands/workflow/session/complete.md +153 -0
- package/.claude/commands/workflow/session/list.md +96 -0
- package/.claude/commands/workflow/session/resume.md +61 -0
- package/.claude/commands/workflow/session/start.md +200 -0
- package/.claude/commands/workflow/tdd-plan.md +460 -0
- package/.claude/commands/workflow/tdd-verify.md +400 -0
- package/.claude/commands/workflow/test-cycle-execute.md +500 -0
- package/.claude/commands/workflow/test-fix-gen.md +699 -0
- package/.claude/commands/workflow/test-gen.md +529 -0
- package/.claude/commands/workflow/tools/conflict-resolution.md +766 -0
- package/.claude/commands/workflow/tools/context-gather.md +436 -0
- package/.claude/commands/workflow/tools/task-generate-agent.md +490 -0
- package/.claude/commands/workflow/tools/task-generate-tdd.md +526 -0
- package/.claude/commands/workflow/tools/tdd-coverage-analysis.md +309 -0
- package/.claude/commands/workflow/tools/test-concept-enhanced.md +164 -0
- package/.claude/commands/workflow/tools/test-context-gather.md +236 -0
- package/.claude/commands/workflow/tools/test-task-generate.md +257 -0
- package/.claude/commands/workflow/ui-design/animation-extract.md +1150 -0
- package/.claude/commands/workflow/ui-design/codify-style.md +652 -0
- package/.claude/commands/workflow/ui-design/design-sync.md +454 -0
- package/.claude/commands/workflow/ui-design/explore-auto.md +678 -0
- package/.claude/commands/workflow/ui-design/generate.md +504 -0
- package/.claude/commands/workflow/ui-design/imitate-auto.md +745 -0
- package/.claude/commands/workflow/ui-design/import-from-code.md +540 -0
- package/.claude/commands/workflow/ui-design/layout-extract.md +788 -0
- package/.claude/commands/workflow/ui-design/reference-page-generator.md +356 -0
- package/.claude/commands/workflow/ui-design/style-extract.md +773 -0
- package/.claude/skills/command-guide/SKILL.md +388 -0
- package/.claude/skills/command-guide/UPDATE-GUIDELINE.md +592 -0
- package/.claude/skills/command-guide/guides/cli-tools-guide.md +410 -0
- package/.claude/skills/command-guide/guides/examples.md +537 -0
- package/.claude/skills/command-guide/guides/getting-started.md +242 -0
- package/.claude/skills/command-guide/guides/implementation-details.md +1010 -0
- package/.claude/skills/command-guide/guides/index-structure.md +326 -0
- package/.claude/skills/command-guide/guides/troubleshooting.md +92 -0
- package/.claude/skills/command-guide/guides/ui-design-workflow-guide.md +316 -0
- package/.claude/skills/command-guide/guides/workflow-patterns.md +662 -0
- package/.claude/skills/command-guide/index/all-commands.json +772 -0
- package/.claude/skills/command-guide/index/by-category.json +800 -0
- package/.claude/skills/command-guide/index/by-use-case.json +786 -0
- package/.claude/skills/command-guide/index/command-relationships.json +307 -0
- package/.claude/skills/command-guide/index/essential-commands.json +112 -0
- package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +857 -0
- package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +267 -0
- package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +182 -0
- package/.claude/skills/command-guide/reference/agents/cli-lite-planning-agent.md +446 -0
- package/.claude/skills/command-guide/reference/agents/cli-planning-agent.md +558 -0
- package/.claude/skills/command-guide/reference/agents/code-developer.md +311 -0
- package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +308 -0
- package/.claude/skills/command-guide/reference/agents/context-search-agent.md +581 -0
- package/.claude/skills/command-guide/reference/agents/doc-generator.md +330 -0
- package/.claude/skills/command-guide/reference/agents/memory-bridge.md +94 -0
- package/.claude/skills/command-guide/reference/agents/test-context-search-agent.md +400 -0
- package/.claude/skills/command-guide/reference/agents/test-fix-agent.md +344 -0
- package/.claude/skills/command-guide/reference/agents/ui-design-agent.md +593 -0
- package/.claude/skills/command-guide/reference/agents/universal-executor.md +131 -0
- package/.claude/skills/command-guide/reference/commands/cli/cli-init.md +440 -0
- package/.claude/skills/command-guide/reference/commands/enhance-prompt.md +93 -0
- package/.claude/skills/command-guide/reference/commands/memory/code-map-memory.md +687 -0
- package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +471 -0
- package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +386 -0
- package/.claude/skills/command-guide/reference/commands/memory/docs.md +616 -0
- package/.claude/skills/command-guide/reference/commands/memory/load-skill-memory.md +182 -0
- package/.claude/skills/command-guide/reference/commands/memory/load.md +240 -0
- package/.claude/skills/command-guide/reference/commands/memory/skill-memory.md +525 -0
- package/.claude/skills/command-guide/reference/commands/memory/style-skill-memory.md +396 -0
- package/.claude/skills/command-guide/reference/commands/memory/tech-research.md +314 -0
- package/.claude/skills/command-guide/reference/commands/memory/update-full.md +332 -0
- package/.claude/skills/command-guide/reference/commands/memory/update-related.md +332 -0
- package/.claude/skills/command-guide/reference/commands/memory/workflow-skill-memory.md +517 -0
- package/.claude/skills/command-guide/reference/commands/task/breakdown.md +204 -0
- package/.claude/skills/command-guide/reference/commands/task/create.md +152 -0
- package/.claude/skills/command-guide/reference/commands/task/execute.md +270 -0
- package/.claude/skills/command-guide/reference/commands/task/replan.md +437 -0
- package/.claude/skills/command-guide/reference/commands/version.md +254 -0
- package/.claude/skills/command-guide/reference/commands/workflow/action-plan-verify.md +447 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/api-designer.md +585 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/artifacts.md +452 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +443 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/data-architect.md +220 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-manager.md +200 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-owner.md +200 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/scrum-master.md +200 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/subject-matter-expert.md +200 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/synthesis.md +398 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/system-architect.md +387 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ui-designer.md +221 -0
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ux-expert.md +221 -0
- package/.claude/skills/command-guide/reference/commands/workflow/execute.md +465 -0
- package/.claude/skills/command-guide/reference/commands/workflow/init.md +164 -0
- package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +748 -0
- package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +664 -0
- package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +645 -0
- package/.claude/skills/command-guide/reference/commands/workflow/plan.md +551 -0
- package/.claude/skills/command-guide/reference/commands/workflow/replan.md +515 -0
- package/.claude/skills/command-guide/reference/commands/workflow/review-fix.md +606 -0
- package/.claude/skills/command-guide/reference/commands/workflow/review-module-cycle.md +765 -0
- package/.claude/skills/command-guide/reference/commands/workflow/review-session-cycle.md +776 -0
- package/.claude/skills/command-guide/reference/commands/workflow/review.md +298 -0
- package/.claude/skills/command-guide/reference/commands/workflow/session/complete.md +547 -0
- package/.claude/skills/command-guide/reference/commands/workflow/session/list.md +114 -0
- package/.claude/skills/command-guide/reference/commands/workflow/session/resume.md +77 -0
- package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +257 -0
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +460 -0
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-verify.md +400 -0
- package/.claude/skills/command-guide/reference/commands/workflow/test-cycle-execute.md +498 -0
- package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +699 -0
- package/.claude/skills/command-guide/reference/commands/workflow/test-gen.md +529 -0
- package/.claude/skills/command-guide/reference/commands/workflow/tools/conflict-resolution.md +766 -0
- package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +434 -0
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +487 -0
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +525 -0
- package/.claude/skills/command-guide/reference/commands/workflow/tools/tdd-coverage-analysis.md +309 -0
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-concept-enhanced.md +163 -0
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-context-gather.md +235 -0
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-task-generate.md +256 -0
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/animation-extract.md +1150 -0
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/codify-style.md +652 -0
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/design-sync.md +454 -0
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/explore-auto.md +678 -0
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/generate.md +504 -0
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/imitate-auto.md +745 -0
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +537 -0
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/layout-extract.md +788 -0
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/reference-page-generator.md +356 -0
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/style-extract.md +773 -0
- package/.claude/skills/command-guide/scripts/analyze_commands.py +502 -0
- package/.claude/skills/command-guide/scripts/update-index.sh +130 -0
- package/.claude/skills/command-guide/templates/issue-bug.md +104 -0
- package/.claude/skills/command-guide/templates/issue-diagnosis.md +275 -0
- package/.claude/skills/command-guide/templates/issue-feature.md +97 -0
- package/.claude/skills/command-guide/templates/issue-question.md +141 -0
- package/.claude/skills/prompt-enhancer/SKILL.md +124 -0
- package/.claude/workflows/_template-compare-matrix.html +692 -0
- package/.claude/workflows/chinese-response.md +38 -0
- package/.claude/workflows/cli-templates/fix-plan-template.json +75 -0
- package/.claude/workflows/cli-templates/fix-progress-template.json +48 -0
- package/.claude/workflows/cli-templates/memory/style-skill-memory/skill-md-template.md +299 -0
- package/.claude/workflows/cli-templates/planning-roles/data-architect.md +120 -0
- package/.claude/workflows/cli-templates/planning-roles/product-manager.md +119 -0
- package/.claude/workflows/cli-templates/planning-roles/product-owner.md +261 -0
- package/.claude/workflows/cli-templates/planning-roles/scrum-master.md +186 -0
- package/.claude/workflows/cli-templates/planning-roles/subject-matter-expert.md +281 -0
- package/.claude/workflows/cli-templates/planning-roles/synthesis-role.md +414 -0
- package/.claude/workflows/cli-templates/planning-roles/system-architect.md +106 -0
- package/.claude/workflows/cli-templates/planning-roles/test-strategist.md +124 -0
- package/.claude/workflows/cli-templates/planning-roles/ui-designer.md +379 -0
- package/.claude/workflows/cli-templates/planning-roles/ux-expert.md +240 -0
- package/.claude/workflows/cli-templates/prompts/analysis/01-diagnose-bug-root-cause.txt +127 -0
- package/.claude/workflows/cli-templates/prompts/analysis/01-trace-code-execution.txt +115 -0
- package/.claude/workflows/cli-templates/prompts/analysis/02-analyze-code-patterns.txt +37 -0
- package/.claude/workflows/cli-templates/prompts/analysis/02-analyze-technical-document.txt +33 -0
- package/.claude/workflows/cli-templates/prompts/analysis/02-review-architecture.txt +29 -0
- package/.claude/workflows/cli-templates/prompts/analysis/02-review-code-quality.txt +28 -0
- package/.claude/workflows/cli-templates/prompts/analysis/03-analyze-performance.txt +29 -0
- package/.claude/workflows/cli-templates/prompts/analysis/03-assess-security-risks.txt +29 -0
- package/.claude/workflows/cli-templates/prompts/analysis/03-review-quality-standards.txt +29 -0
- package/.claude/workflows/cli-templates/prompts/development/02-generate-tests.txt +70 -0
- package/.claude/workflows/cli-templates/prompts/development/02-implement-component-ui.txt +55 -0
- package/.claude/workflows/cli-templates/prompts/development/02-implement-feature.txt +58 -0
- package/.claude/workflows/cli-templates/prompts/development/02-refactor-codebase.txt +55 -0
- package/.claude/workflows/cli-templates/prompts/development/03-debug-runtime-issues.txt +55 -0
- package/.claude/workflows/cli-templates/prompts/documentation/api.txt +15 -0
- package/.claude/workflows/cli-templates/prompts/documentation/folder-navigation.txt +27 -0
- package/.claude/workflows/cli-templates/prompts/documentation/module-readme.txt +49 -0
- package/.claude/workflows/cli-templates/prompts/documentation/project-architecture.txt +41 -0
- package/.claude/workflows/cli-templates/prompts/documentation/project-examples.txt +35 -0
- package/.claude/workflows/cli-templates/prompts/documentation/project-readme.txt +35 -0
- package/.claude/workflows/cli-templates/prompts/memory/02-document-module-structure.txt +165 -0
- package/.claude/workflows/cli-templates/prompts/planning/01-plan-architecture-design.txt +109 -0
- package/.claude/workflows/cli-templates/prompts/planning/02-breakdown-task-steps.txt +30 -0
- package/.claude/workflows/cli-templates/prompts/planning/02-design-component-spec.txt +28 -0
- package/.claude/workflows/cli-templates/prompts/planning/03-evaluate-concept-feasibility.txt +127 -0
- package/.claude/workflows/cli-templates/prompts/planning/03-plan-migration-strategy.txt +30 -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/tech/tech-module-format.txt +359 -0
- package/.claude/workflows/cli-templates/prompts/tech/tech-skill-index.txt +185 -0
- package/.claude/workflows/cli-templates/prompts/test/test-concept-analysis.txt +179 -0
- package/.claude/workflows/cli-templates/prompts/universal/00-universal-creative-style.txt +95 -0
- package/.claude/workflows/cli-templates/prompts/universal/00-universal-rigorous-style.txt +92 -0
- package/.claude/workflows/cli-templates/prompts/verification/codex-technical.txt +28 -0
- package/.claude/workflows/cli-templates/prompts/verification/cross-validation.txt +28 -0
- package/.claude/workflows/cli-templates/prompts/verification/gemini-strategic.txt +27 -0
- package/.claude/workflows/cli-templates/prompts/workflow/analysis-results-structure.txt +224 -0
- package/.claude/workflows/cli-templates/prompts/workflow/codex-feasibility-validation.txt +176 -0
- package/.claude/workflows/cli-templates/prompts/workflow/gemini-solution-design.txt +131 -0
- package/.claude/workflows/cli-templates/prompts/workflow/impl-plan-template.txt +286 -0
- package/.claude/workflows/cli-templates/prompts/workflow/skill-aggregation.txt +172 -0
- package/.claude/workflows/cli-templates/prompts/workflow/skill-conflict-patterns.txt +94 -0
- package/.claude/workflows/cli-templates/prompts/workflow/skill-index.txt +224 -0
- package/.claude/workflows/cli-templates/prompts/workflow/skill-lessons-learned.txt +94 -0
- package/.claude/workflows/cli-templates/prompts/workflow/skill-sessions-timeline.txt +53 -0
- package/.claude/workflows/cli-templates/prompts/workflow/task-json-agent-mode.txt +123 -0
- package/.claude/workflows/cli-templates/prompts/workflow/task-json-cli-mode.txt +182 -0
- 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/diagnosis-json-schema.json +234 -0
- package/.claude/workflows/cli-templates/schemas/explore-json-schema.json +124 -0
- package/.claude/workflows/cli-templates/schemas/fix-plan-json-schema.json +298 -0
- package/.claude/workflows/cli-templates/schemas/plan-json-schema.json +244 -0
- package/.claude/workflows/cli-templates/schemas/project-json-schema.json +221 -0
- package/.claude/workflows/cli-templates/schemas/review-deep-dive-results-schema.json +82 -0
- package/.claude/workflows/cli-templates/schemas/review-dimension-results-schema.json +51 -0
- package/.claude/workflows/cli-templates/tech-stacks/go-dev.md +91 -0
- package/.claude/workflows/cli-templates/tech-stacks/java-dev.md +107 -0
- package/.claude/workflows/cli-templates/tech-stacks/javascript-dev.md +58 -0
- package/.claude/workflows/cli-templates/tech-stacks/python-dev.md +79 -0
- package/.claude/workflows/cli-templates/tech-stacks/react-dev.md +103 -0
- package/.claude/workflows/cli-templates/tech-stacks/typescript-dev.md +83 -0
- package/.claude/workflows/cli-templates/ui-design/systems/animation-tokens.json +247 -0
- package/.claude/workflows/cli-templates/ui-design/systems/design-tokens.json +342 -0
- package/.claude/workflows/cli-templates/ui-design/systems/layout-templates.json +145 -0
- package/.claude/workflows/cli-tools-usage.md +526 -0
- package/.claude/workflows/coding-philosophy.md +70 -0
- package/.claude/workflows/context-tools.md +84 -0
- package/.claude/workflows/file-modification.md +64 -0
- package/.claude/workflows/review-directory-specification.md +336 -0
- package/.claude/workflows/task-core.md +214 -0
- package/.claude/workflows/tool-strategy.md +216 -0
- package/.claude/workflows/windows-platform.md +16 -0
- package/.claude/workflows/workflow-architecture.md +942 -0
- package/.codex/AGENTS.md +63 -0
- 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 -0
- package/.qwen/QWEN.md +25 -0
- package/LICENSE +21 -0
- package/README.md +294 -145
- package/ccw/README.md +145 -0
- package/ccw/package.json +65 -0
- 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 +37 -32
- /package/{bin → ccw/bin}/ccw-mcp.js +0 -0
- /package/{bin → ccw/bin}/ccw.js +0 -0
- /package/{dist → ccw/dist}/cli.d.ts +0 -0
- /package/{dist → ccw/dist}/cli.d.ts.map +0 -0
- /package/{dist → ccw/dist}/cli.js +0 -0
- /package/{dist → ccw/dist}/cli.js.map +0 -0
- /package/{dist → ccw/dist}/commands/cli.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/cli.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/cli.js +0 -0
- /package/{dist → ccw/dist}/commands/cli.js.map +0 -0
- /package/{dist → ccw/dist}/commands/core-memory.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/core-memory.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/core-memory.js +0 -0
- /package/{dist → ccw/dist}/commands/core-memory.js.map +0 -0
- /package/{dist → ccw/dist}/commands/hook.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/hook.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/hook.js +0 -0
- /package/{dist → ccw/dist}/commands/hook.js.map +0 -0
- /package/{dist → ccw/dist}/commands/install.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/install.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/install.js +0 -0
- /package/{dist → ccw/dist}/commands/install.js.map +0 -0
- /package/{dist → ccw/dist}/commands/list.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/list.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/list.js +0 -0
- /package/{dist → ccw/dist}/commands/list.js.map +0 -0
- /package/{dist → ccw/dist}/commands/memory.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/memory.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/memory.js +0 -0
- /package/{dist → ccw/dist}/commands/memory.js.map +0 -0
- /package/{dist → ccw/dist}/commands/serve.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/serve.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/serve.js +0 -0
- /package/{dist → ccw/dist}/commands/serve.js.map +0 -0
- /package/{dist → ccw/dist}/commands/session-path-resolver.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/session-path-resolver.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/session-path-resolver.js +0 -0
- /package/{dist → ccw/dist}/commands/session-path-resolver.js.map +0 -0
- /package/{dist → ccw/dist}/commands/session.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/session.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/session.js +0 -0
- /package/{dist → ccw/dist}/commands/session.js.map +0 -0
- /package/{dist → ccw/dist}/commands/stop.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/stop.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/stop.js +0 -0
- /package/{dist → ccw/dist}/commands/stop.js.map +0 -0
- /package/{dist → ccw/dist}/commands/tool.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/tool.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/tool.js +0 -0
- /package/{dist → ccw/dist}/commands/tool.js.map +0 -0
- /package/{dist → ccw/dist}/commands/uninstall.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/uninstall.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/uninstall.js +0 -0
- /package/{dist → ccw/dist}/commands/uninstall.js.map +0 -0
- /package/{dist → ccw/dist}/commands/upgrade.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/upgrade.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/upgrade.js +0 -0
- /package/{dist → ccw/dist}/commands/upgrade.js.map +0 -0
- /package/{dist → ccw/dist}/commands/view.d.ts +0 -0
- /package/{dist → ccw/dist}/commands/view.d.ts.map +0 -0
- /package/{dist → ccw/dist}/commands/view.js +0 -0
- /package/{dist → ccw/dist}/commands/view.js.map +0 -0
- /package/{dist → ccw/dist}/config/storage-paths.d.ts +0 -0
- /package/{dist → ccw/dist}/config/storage-paths.d.ts.map +0 -0
- /package/{dist → ccw/dist}/config/storage-paths.js +0 -0
- /package/{dist → ccw/dist}/config/storage-paths.js.map +0 -0
- /package/{dist → ccw/dist}/core/cache-manager.d.ts +0 -0
- /package/{dist → ccw/dist}/core/cache-manager.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/cache-manager.js +0 -0
- /package/{dist → ccw/dist}/core/cache-manager.js.map +0 -0
- /package/{dist → ccw/dist}/core/claude-freshness.d.ts +0 -0
- /package/{dist → ccw/dist}/core/claude-freshness.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/claude-freshness.js +0 -0
- /package/{dist → ccw/dist}/core/claude-freshness.js.map +0 -0
- /package/{dist → ccw/dist}/core/core-memory-store.d.ts +0 -0
- /package/{dist → ccw/dist}/core/core-memory-store.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/core-memory-store.js +0 -0
- /package/{dist → ccw/dist}/core/core-memory-store.js.map +0 -0
- /package/{dist → ccw/dist}/core/dashboard-generator-patch.d.ts +0 -0
- /package/{dist → ccw/dist}/core/dashboard-generator-patch.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/dashboard-generator-patch.js +0 -0
- /package/{dist → ccw/dist}/core/dashboard-generator-patch.js.map +0 -0
- /package/{dist → ccw/dist}/core/dashboard-generator.d.ts +0 -0
- /package/{dist → ccw/dist}/core/dashboard-generator.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/dashboard-generator.js +0 -0
- /package/{dist → ccw/dist}/core/dashboard-generator.js.map +0 -0
- /package/{dist → ccw/dist}/core/data-aggregator.d.ts +0 -0
- /package/{dist → ccw/dist}/core/data-aggregator.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/data-aggregator.js +0 -0
- /package/{dist → ccw/dist}/core/data-aggregator.js.map +0 -0
- /package/{dist → ccw/dist}/core/history-importer.d.ts +0 -0
- /package/{dist → ccw/dist}/core/history-importer.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/history-importer.js +0 -0
- /package/{dist → ccw/dist}/core/history-importer.js.map +0 -0
- /package/{dist → ccw/dist}/core/lite-scanner-complete.d.ts +0 -0
- /package/{dist → ccw/dist}/core/lite-scanner-complete.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/lite-scanner-complete.js +0 -0
- /package/{dist → ccw/dist}/core/lite-scanner-complete.js.map +0 -0
- /package/{dist → ccw/dist}/core/lite-scanner.d.ts +0 -0
- /package/{dist → ccw/dist}/core/lite-scanner.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/lite-scanner.js +0 -0
- /package/{dist → ccw/dist}/core/lite-scanner.js.map +0 -0
- /package/{dist → ccw/dist}/core/manifest.d.ts +0 -0
- /package/{dist → ccw/dist}/core/manifest.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/manifest.js +0 -0
- /package/{dist → ccw/dist}/core/manifest.js.map +0 -0
- /package/{dist → ccw/dist}/core/memory-embedder-bridge.d.ts +0 -0
- /package/{dist → ccw/dist}/core/memory-embedder-bridge.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/memory-embedder-bridge.js +0 -0
- /package/{dist → ccw/dist}/core/memory-embedder-bridge.js.map +0 -0
- /package/{dist → ccw/dist}/core/memory-store.d.ts +0 -0
- /package/{dist → ccw/dist}/core/memory-store.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/memory-store.js +0 -0
- /package/{dist → ccw/dist}/core/memory-store.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/ccw-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/ccw-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/ccw-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/ccw-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/claude-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/claude-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/claude-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/claude-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/cli-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/cli-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/cli-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/cli-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/codexlens-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/codexlens-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/codexlens-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/codexlens-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/core-memory-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/core-memory-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/core-memory-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/core-memory-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/files-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/files-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/files-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/files-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/graph-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/graph-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/graph-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/graph-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/help-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/help-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/help-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/help-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/hooks-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/hooks-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/hooks-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/hooks-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/mcp-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/mcp-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/mcp-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/mcp-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/mcp-templates-db.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/mcp-templates-db.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/mcp-templates-db.js +0 -0
- /package/{dist → ccw/dist}/core/routes/mcp-templates-db.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/memory-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/memory-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/memory-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/memory-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/rules-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/rules-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/rules-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/rules-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/session-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/session-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/session-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/session-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/skills-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/skills-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/skills-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/skills-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/status-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/status-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/status-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/status-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/routes/system-routes.d.ts +0 -0
- /package/{dist → ccw/dist}/core/routes/system-routes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/routes/system-routes.js +0 -0
- /package/{dist → ccw/dist}/core/routes/system-routes.js.map +0 -0
- /package/{dist → ccw/dist}/core/server.d.ts +0 -0
- /package/{dist → ccw/dist}/core/server.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/server.js +0 -0
- /package/{dist → ccw/dist}/core/server.js.map +0 -0
- /package/{dist → ccw/dist}/core/session-clustering-service.d.ts +0 -0
- /package/{dist → ccw/dist}/core/session-clustering-service.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/session-clustering-service.js +0 -0
- /package/{dist → ccw/dist}/core/session-clustering-service.js.map +0 -0
- /package/{dist → ccw/dist}/core/session-scanner.d.ts +0 -0
- /package/{dist → ccw/dist}/core/session-scanner.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/session-scanner.js +0 -0
- /package/{dist → ccw/dist}/core/session-scanner.js.map +0 -0
- /package/{dist → ccw/dist}/core/websocket.d.ts +0 -0
- /package/{dist → ccw/dist}/core/websocket.d.ts.map +0 -0
- /package/{dist → ccw/dist}/core/websocket.js +0 -0
- /package/{dist → ccw/dist}/core/websocket.js.map +0 -0
- /package/{dist → ccw/dist}/index.d.ts +0 -0
- /package/{dist → ccw/dist}/index.d.ts.map +0 -0
- /package/{dist → ccw/dist}/index.js +0 -0
- /package/{dist → ccw/dist}/index.js.map +0 -0
- /package/{dist → ccw/dist}/mcp-server/index.d.ts +0 -0
- /package/{dist → ccw/dist}/mcp-server/index.d.ts.map +0 -0
- /package/{dist → ccw/dist}/mcp-server/index.js +0 -0
- /package/{dist → ccw/dist}/mcp-server/index.js.map +0 -0
- /package/{dist → ccw/dist}/tools/classify-folders.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/classify-folders.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/classify-folders.js +0 -0
- /package/{dist → ccw/dist}/tools/classify-folders.js.map +0 -0
- /package/{dist → ccw/dist}/tools/cli-config-manager.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/cli-config-manager.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/cli-config-manager.js +0 -0
- /package/{dist → ccw/dist}/tools/cli-config-manager.js.map +0 -0
- /package/{dist → ccw/dist}/tools/cli-executor.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/cli-executor.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/cli-executor.js +0 -0
- /package/{dist → ccw/dist}/tools/cli-executor.js.map +0 -0
- /package/{dist → ccw/dist}/tools/cli-history-store.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/cli-history-store.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/cli-history-store.js +0 -0
- /package/{dist → ccw/dist}/tools/cli-history-store.js.map +0 -0
- /package/{dist → ccw/dist}/tools/codex-lens.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/codex-lens.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/codex-lens.js +0 -0
- /package/{dist → ccw/dist}/tools/codex-lens.js.map +0 -0
- /package/{dist → ccw/dist}/tools/convert-tokens-to-css.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/convert-tokens-to-css.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/convert-tokens-to-css.js +0 -0
- /package/{dist → ccw/dist}/tools/convert-tokens-to-css.js.map +0 -0
- /package/{dist → ccw/dist}/tools/core-memory.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/core-memory.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/core-memory.js +0 -0
- /package/{dist → ccw/dist}/tools/core-memory.js.map +0 -0
- /package/{dist → ccw/dist}/tools/detect-changed-modules.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/detect-changed-modules.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/detect-changed-modules.js +0 -0
- /package/{dist → ccw/dist}/tools/detect-changed-modules.js.map +0 -0
- /package/{dist → ccw/dist}/tools/discover-design-files.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/discover-design-files.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/discover-design-files.js +0 -0
- /package/{dist → ccw/dist}/tools/discover-design-files.js.map +0 -0
- /package/{dist → ccw/dist}/tools/edit-file.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/edit-file.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/edit-file.js +0 -0
- /package/{dist → ccw/dist}/tools/edit-file.js.map +0 -0
- /package/{dist → ccw/dist}/tools/generate-module-docs.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/generate-module-docs.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/generate-module-docs.js +0 -0
- /package/{dist → ccw/dist}/tools/generate-module-docs.js.map +0 -0
- /package/{dist → ccw/dist}/tools/get-modules-by-depth.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/get-modules-by-depth.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/get-modules-by-depth.js +0 -0
- /package/{dist → ccw/dist}/tools/get-modules-by-depth.js.map +0 -0
- /package/{dist → ccw/dist}/tools/index.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/index.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/index.js +0 -0
- /package/{dist → ccw/dist}/tools/index.js.map +0 -0
- /package/{dist → ccw/dist}/tools/native-session-discovery.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/native-session-discovery.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/native-session-discovery.js +0 -0
- /package/{dist → ccw/dist}/tools/native-session-discovery.js.map +0 -0
- /package/{dist → ccw/dist}/tools/notifier.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/notifier.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/notifier.js +0 -0
- /package/{dist → ccw/dist}/tools/notifier.js.map +0 -0
- /package/{dist → ccw/dist}/tools/read-file.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/read-file.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/read-file.js +0 -0
- /package/{dist → ccw/dist}/tools/read-file.js.map +0 -0
- /package/{dist → ccw/dist}/tools/resume-strategy.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/resume-strategy.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/resume-strategy.js +0 -0
- /package/{dist → ccw/dist}/tools/resume-strategy.js.map +0 -0
- /package/{dist → ccw/dist}/tools/session-content-parser.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/session-content-parser.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/session-content-parser.js +0 -0
- /package/{dist → ccw/dist}/tools/session-content-parser.js.map +0 -0
- /package/{dist → ccw/dist}/tools/session-manager.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/session-manager.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/session-manager.js +0 -0
- /package/{dist → ccw/dist}/tools/session-manager.js.map +0 -0
- /package/{dist → ccw/dist}/tools/smart-context.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/smart-context.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/smart-context.js +0 -0
- /package/{dist → ccw/dist}/tools/smart-context.js.map +0 -0
- /package/{dist → ccw/dist}/tools/smart-search.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/smart-search.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/smart-search.js +0 -0
- /package/{dist → ccw/dist}/tools/smart-search.js.map +0 -0
- /package/{dist → ccw/dist}/tools/storage-manager.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/storage-manager.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/storage-manager.js +0 -0
- /package/{dist → ccw/dist}/tools/storage-manager.js.map +0 -0
- /package/{dist → ccw/dist}/tools/ui-generate-preview.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/ui-generate-preview.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/ui-generate-preview.js +0 -0
- /package/{dist → ccw/dist}/tools/ui-generate-preview.js.map +0 -0
- /package/{dist → ccw/dist}/tools/ui-instantiate-prototypes.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/ui-instantiate-prototypes.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/ui-instantiate-prototypes.js +0 -0
- /package/{dist → ccw/dist}/tools/ui-instantiate-prototypes.js.map +0 -0
- /package/{dist → ccw/dist}/tools/update-module-claude.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/update-module-claude.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/update-module-claude.js +0 -0
- /package/{dist → ccw/dist}/tools/update-module-claude.js.map +0 -0
- /package/{dist → ccw/dist}/tools/write-file.d.ts +0 -0
- /package/{dist → ccw/dist}/tools/write-file.d.ts.map +0 -0
- /package/{dist → ccw/dist}/tools/write-file.js +0 -0
- /package/{dist → ccw/dist}/tools/write-file.js.map +0 -0
- /package/{dist → ccw/dist}/types/config.d.ts +0 -0
- /package/{dist → ccw/dist}/types/config.d.ts.map +0 -0
- /package/{dist → ccw/dist}/types/config.js +0 -0
- /package/{dist → ccw/dist}/types/config.js.map +0 -0
- /package/{dist → ccw/dist}/types/index.d.ts +0 -0
- /package/{dist → ccw/dist}/types/index.d.ts.map +0 -0
- /package/{dist → ccw/dist}/types/index.js +0 -0
- /package/{dist → ccw/dist}/types/index.js.map +0 -0
- /package/{dist → ccw/dist}/types/session.d.ts +0 -0
- /package/{dist → ccw/dist}/types/session.d.ts.map +0 -0
- /package/{dist → ccw/dist}/types/session.js +0 -0
- /package/{dist → ccw/dist}/types/session.js.map +0 -0
- /package/{dist → ccw/dist}/types/tool.d.ts +0 -0
- /package/{dist → ccw/dist}/types/tool.d.ts.map +0 -0
- /package/{dist → ccw/dist}/types/tool.js +0 -0
- /package/{dist → ccw/dist}/types/tool.js.map +0 -0
- /package/{dist → ccw/dist}/utils/browser-launcher.d.ts +0 -0
- /package/{dist → ccw/dist}/utils/browser-launcher.d.ts.map +0 -0
- /package/{dist → ccw/dist}/utils/browser-launcher.js +0 -0
- /package/{dist → ccw/dist}/utils/browser-launcher.js.map +0 -0
- /package/{dist → ccw/dist}/utils/file-utils.d.ts +0 -0
- /package/{dist → ccw/dist}/utils/file-utils.d.ts.map +0 -0
- /package/{dist → ccw/dist}/utils/file-utils.js +0 -0
- /package/{dist → ccw/dist}/utils/file-utils.js.map +0 -0
- /package/{dist → ccw/dist}/utils/path-resolver.d.ts +0 -0
- /package/{dist → ccw/dist}/utils/path-resolver.d.ts.map +0 -0
- /package/{dist → ccw/dist}/utils/path-resolver.js +0 -0
- /package/{dist → ccw/dist}/utils/path-resolver.js.map +0 -0
- /package/{dist → ccw/dist}/utils/path-validator.d.ts +0 -0
- /package/{dist → ccw/dist}/utils/path-validator.d.ts.map +0 -0
- /package/{dist → ccw/dist}/utils/path-validator.js +0 -0
- /package/{dist → ccw/dist}/utils/path-validator.js.map +0 -0
- /package/{dist → ccw/dist}/utils/ui.d.ts +0 -0
- /package/{dist → ccw/dist}/utils/ui.d.ts.map +0 -0
- /package/{dist → ccw/dist}/utils/ui.js +0 -0
- /package/{dist → ccw/dist}/utils/ui.js.map +0 -0
- /package/{src → ccw/src}/.workflow/.cli-history/history.db +0 -0
- /package/{src → ccw/src}/.workflow/.cli-history/history.db-shm +0 -0
- /package/{src → ccw/src}/.workflow/.cli-history/history.db-wal +0 -0
- /package/{src → ccw/src}/cli.ts +0 -0
- /package/{src → ccw/src}/commands/cli.ts +0 -0
- /package/{src → ccw/src}/commands/core-memory.ts +0 -0
- /package/{src → ccw/src}/commands/hook.ts +0 -0
- /package/{src → ccw/src}/commands/install.ts +0 -0
- /package/{src → ccw/src}/commands/list.ts +0 -0
- /package/{src → ccw/src}/commands/memory.ts +0 -0
- /package/{src → ccw/src}/commands/serve.ts +0 -0
- /package/{src → ccw/src}/commands/session-path-resolver.ts +0 -0
- /package/{src → ccw/src}/commands/session.ts +0 -0
- /package/{src → ccw/src}/commands/stop.ts +0 -0
- /package/{src → ccw/src}/commands/tool.ts +0 -0
- /package/{src → ccw/src}/commands/uninstall.ts +0 -0
- /package/{src → ccw/src}/commands/upgrade.ts +0 -0
- /package/{src → ccw/src}/commands/view.ts +0 -0
- /package/{src → ccw/src}/config/storage-paths.ts +0 -0
- /package/{src → ccw/src}/core/cache-manager.ts +0 -0
- /package/{src → ccw/src}/core/claude-freshness.ts +0 -0
- /package/{src → ccw/src}/core/core-memory-store.ts +0 -0
- /package/{src → ccw/src}/core/dashboard-generator-patch.ts +0 -0
- /package/{src → ccw/src}/core/dashboard-generator.ts +0 -0
- /package/{src → ccw/src}/core/data-aggregator.ts +0 -0
- /package/{src → ccw/src}/core/history-importer.ts +0 -0
- /package/{src → ccw/src}/core/lite-scanner-complete.ts +0 -0
- /package/{src → ccw/src}/core/lite-scanner.ts +0 -0
- /package/{src → ccw/src}/core/manifest.ts +0 -0
- /package/{src → ccw/src}/core/memory-embedder-bridge.ts +0 -0
- /package/{src → ccw/src}/core/memory-store.ts +0 -0
- /package/{src → ccw/src}/core/routes/ccw-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/claude-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/cli-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/codexlens-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/core-memory-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/files-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/graph-routes.md +0 -0
- /package/{src → ccw/src}/core/routes/graph-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/help-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/hooks-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/mcp-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/mcp-routes.ts.backup +0 -0
- /package/{src → ccw/src}/core/routes/mcp-templates-db.ts +0 -0
- /package/{src → ccw/src}/core/routes/memory-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/rules-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/session-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/skills-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/status-routes.ts +0 -0
- /package/{src → ccw/src}/core/routes/system-routes.ts +0 -0
- /package/{src → ccw/src}/core/server.ts +0 -0
- /package/{src → ccw/src}/core/session-clustering-service.ts +0 -0
- /package/{src → ccw/src}/core/session-scanner.ts +0 -0
- /package/{src → ccw/src}/core/websocket.ts +0 -0
- /package/{src → ccw/src}/index.ts +0 -0
- /package/{src → ccw/src}/mcp-server/index.ts +0 -0
- /package/{src → ccw/src}/templates/assets/css/github-dark.min.css +0 -0
- /package/{src → ccw/src}/templates/assets/css/github.min.css +0 -0
- /package/{src → ccw/src}/templates/assets/js/cytoscape.min.js +0 -0
- /package/{src → ccw/src}/templates/assets/js/d3.min.js +0 -0
- /package/{src → ccw/src}/templates/assets/js/highlight.min.js +0 -0
- /package/{src → ccw/src}/templates/assets/js/lucide.min.js +0 -0
- /package/{src → ccw/src}/templates/assets/js/marked.min.js +0 -0
- /package/{src → ccw/src}/templates/assets/js/tailwind.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/01-base.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/02-session.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/03-tasks.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/04-lite-tasks.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/05-context.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/06-cards.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/07-managers.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/08-review.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/09-explorer.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/10-cli-status.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/11-cli-history.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/12-cli-legacy.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/13-cli-ccw.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/14-cli-modals.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/15-cli-endpoints.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/16-cli-session.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/17-cli-conversation.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/18-cli-settings.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/19-cli-native-session.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/20-cli-taskqueue.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/21-cli-toolmgmt.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/22-cli-semantic.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/23-memory.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/24-prompt-history.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/25-skills-rules.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/26-claude-manager.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/27-graph-explorer.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/28-mcp-manager.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/29-help.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-css/30-core-memory.css +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/api.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/_conflict_tab.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/_exp_helpers.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/_review_tab.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/carousel.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/cli-history.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/cli-status.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/flowchart.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/global-notifications.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/hook-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/index-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/mcp-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/modals.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/navigation.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/notifications.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/sidebar.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/storage-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/tabs-context.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/tabs-other.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/task-drawer-core.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/task-drawer-renderers.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/task-queue-sidebar.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/theme.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/components/version-check.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/help-i18n.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/i18n.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/main.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/state.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/utils.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/claude-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/cli-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/codexlens-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/core-memory-clusters.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/core-memory.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/explorer.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/fix-session.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/graph-explorer.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/help.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/history.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/home.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/hook-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/lite-tasks.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/mcp-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/mcp-manager.js.backup +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/mcp-manager.js.new +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/memory.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/project-overview.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/prompt-history.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/review-session.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/rules-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/session-detail.js +0 -0
- /package/{src → ccw/src}/templates/dashboard-js/views/skills-manager.js +0 -0
- /package/{src → ccw/src}/templates/dashboard.html +0 -0
- /package/{src → ccw/src}/templates/hooks-config-example.json +0 -0
- /package/{src → ccw/src}/templates/review-cycle-dashboard.html +0 -0
- /package/{src → ccw/src}/templates/workflow-dashboard.html +0 -0
- /package/{src → ccw/src}/tools/classify-folders.ts +0 -0
- /package/{src → ccw/src}/tools/cli-config-manager.ts +0 -0
- /package/{src → ccw/src}/tools/cli-executor.ts +0 -0
- /package/{src → ccw/src}/tools/cli-history-store.ts +0 -0
- /package/{src → ccw/src}/tools/codex-lens.ts +0 -0
- /package/{src → ccw/src}/tools/convert-tokens-to-css.ts +0 -0
- /package/{src → ccw/src}/tools/core-memory.ts +0 -0
- /package/{src → ccw/src}/tools/detect-changed-modules.ts +0 -0
- /package/{src → ccw/src}/tools/discover-design-files.ts +0 -0
- /package/{src → ccw/src}/tools/edit-file.ts +0 -0
- /package/{src → ccw/src}/tools/generate-module-docs.ts +0 -0
- /package/{src → ccw/src}/tools/get-modules-by-depth.ts +0 -0
- /package/{src → ccw/src}/tools/index.ts +0 -0
- /package/{src → ccw/src}/tools/native-session-discovery.ts +0 -0
- /package/{src → ccw/src}/tools/notifier.ts +0 -0
- /package/{src → ccw/src}/tools/read-file.ts +0 -0
- /package/{src → ccw/src}/tools/resume-strategy.ts +0 -0
- /package/{src → ccw/src}/tools/session-content-parser.ts +0 -0
- /package/{src → ccw/src}/tools/session-manager.ts +0 -0
- /package/{src → ccw/src}/tools/smart-context.ts +0 -0
- /package/{src → ccw/src}/tools/smart-search.ts +0 -0
- /package/{src → ccw/src}/tools/smart-search.ts.backup +0 -0
- /package/{src → ccw/src}/tools/storage-manager.ts +0 -0
- /package/{src → ccw/src}/tools/ui-generate-preview.js +0 -0
- /package/{src → ccw/src}/tools/ui-instantiate-prototypes.js +0 -0
- /package/{src → ccw/src}/tools/update-module-claude.js +0 -0
- /package/{src → ccw/src}/tools/write-file.ts +0 -0
- /package/{src → ccw/src}/types/config.ts +0 -0
- /package/{src → ccw/src}/types/index.ts +0 -0
- /package/{src → ccw/src}/types/session.ts +0 -0
- /package/{src → ccw/src}/types/tool.ts +0 -0
- /package/{src → ccw/src}/utils/browser-launcher.ts +0 -0
- /package/{src → ccw/src}/utils/file-utils.ts +0 -0
- /package/{src → ccw/src}/utils/path-resolver.ts +0 -0
- /package/{src → ccw/src}/utils/path-validator.ts +0 -0
- /package/{src → ccw/src}/utils/ui.ts +0 -0
|
@@ -0,0 +1,1931 @@
|
|
|
1
|
+
"""Typer commands for CodexLens."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
import shutil
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any, Dict, Iterable, List, Optional
|
|
11
|
+
|
|
12
|
+
import typer
|
|
13
|
+
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
|
|
14
|
+
from rich.table import Table
|
|
15
|
+
|
|
16
|
+
from codexlens.config import Config
|
|
17
|
+
from codexlens.entities import IndexedFile, SearchResult, Symbol
|
|
18
|
+
from codexlens.errors import CodexLensError, ConfigError, ParseError, StorageError, SearchError
|
|
19
|
+
from codexlens.parsers.factory import ParserFactory
|
|
20
|
+
from codexlens.storage.path_mapper import PathMapper
|
|
21
|
+
from codexlens.storage.registry import RegistryStore, ProjectInfo
|
|
22
|
+
from codexlens.storage.index_tree import IndexTreeBuilder
|
|
23
|
+
from codexlens.storage.dir_index import DirIndexStore
|
|
24
|
+
from codexlens.search.chain_search import ChainSearchEngine, SearchOptions
|
|
25
|
+
|
|
26
|
+
from .output import (
|
|
27
|
+
console,
|
|
28
|
+
print_json,
|
|
29
|
+
render_file_inspect,
|
|
30
|
+
render_search_results,
|
|
31
|
+
render_status,
|
|
32
|
+
render_symbols,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
app = typer.Typer(help="CodexLens CLI — local code indexing and search.")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _configure_logging(verbose: bool) -> None:
|
|
39
|
+
level = logging.DEBUG if verbose else logging.INFO
|
|
40
|
+
logging.basicConfig(level=level, format="%(levelname)s %(message)s")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _parse_languages(raw: Optional[List[str]]) -> Optional[List[str]]:
|
|
44
|
+
if not raw:
|
|
45
|
+
return None
|
|
46
|
+
langs: List[str] = []
|
|
47
|
+
for item in raw:
|
|
48
|
+
for part in item.split(","):
|
|
49
|
+
part = part.strip()
|
|
50
|
+
if part:
|
|
51
|
+
langs.append(part)
|
|
52
|
+
return langs or None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _get_index_root() -> Path:
|
|
56
|
+
"""Get the index root directory from config or default."""
|
|
57
|
+
env_override = os.getenv("CODEXLENS_INDEX_DIR")
|
|
58
|
+
if env_override:
|
|
59
|
+
return Path(env_override).expanduser().resolve()
|
|
60
|
+
return Path.home() / ".codexlens" / "indexes"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _get_registry_path() -> Path:
|
|
64
|
+
"""Get the registry database path."""
|
|
65
|
+
env_override = os.getenv("CODEXLENS_DATA_DIR")
|
|
66
|
+
if env_override:
|
|
67
|
+
return Path(env_override).expanduser().resolve() / "registry.db"
|
|
68
|
+
return Path.home() / ".codexlens" / "registry.db"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@app.command()
|
|
72
|
+
def init(
|
|
73
|
+
path: Path = typer.Argument(Path("."), exists=True, file_okay=False, dir_okay=True, help="Project root to index."),
|
|
74
|
+
language: Optional[List[str]] = typer.Option(
|
|
75
|
+
None,
|
|
76
|
+
"--language",
|
|
77
|
+
"-l",
|
|
78
|
+
help="Limit indexing to specific languages (repeat or comma-separated).",
|
|
79
|
+
),
|
|
80
|
+
workers: Optional[int] = typer.Option(None, "--workers", "-w", min=1, max=16, help="Parallel worker processes (default: auto-detect based on CPU count, max 16)."),
|
|
81
|
+
force: bool = typer.Option(False, "--force", "-f", help="Force full reindex (skip incremental mode)."),
|
|
82
|
+
no_embeddings: bool = typer.Option(False, "--no-embeddings", help="Skip automatic embedding generation (if semantic deps installed)."),
|
|
83
|
+
embedding_model: str = typer.Option("code", "--embedding-model", help="Embedding model profile: fast, code, multilingual, balanced."),
|
|
84
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
85
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
86
|
+
) -> None:
|
|
87
|
+
"""Initialize or rebuild the index for a directory.
|
|
88
|
+
|
|
89
|
+
Indexes are stored in ~/.codexlens/indexes/ with mirrored directory structure.
|
|
90
|
+
Set CODEXLENS_INDEX_DIR to customize the index location.
|
|
91
|
+
|
|
92
|
+
By default, uses incremental indexing (skip unchanged files).
|
|
93
|
+
Use --force to rebuild all files regardless of modification time.
|
|
94
|
+
|
|
95
|
+
If semantic search dependencies are installed, automatically generates embeddings
|
|
96
|
+
after indexing completes. Use --no-embeddings to skip this step.
|
|
97
|
+
"""
|
|
98
|
+
_configure_logging(verbose)
|
|
99
|
+
config = Config()
|
|
100
|
+
languages = _parse_languages(language)
|
|
101
|
+
base_path = path.expanduser().resolve()
|
|
102
|
+
|
|
103
|
+
registry: RegistryStore | None = None
|
|
104
|
+
try:
|
|
105
|
+
registry = RegistryStore()
|
|
106
|
+
registry.initialize()
|
|
107
|
+
mapper = PathMapper()
|
|
108
|
+
|
|
109
|
+
builder = IndexTreeBuilder(registry, mapper, config, incremental=not force)
|
|
110
|
+
|
|
111
|
+
if force:
|
|
112
|
+
console.print(f"[bold]Building index for:[/bold] {base_path} [yellow](FULL reindex)[/yellow]")
|
|
113
|
+
else:
|
|
114
|
+
console.print(f"[bold]Building index for:[/bold] {base_path} [dim](incremental)[/dim]")
|
|
115
|
+
|
|
116
|
+
build_result = builder.build(
|
|
117
|
+
source_root=base_path,
|
|
118
|
+
languages=languages,
|
|
119
|
+
workers=workers,
|
|
120
|
+
force_full=force,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
result = {
|
|
124
|
+
"path": str(base_path),
|
|
125
|
+
"files_indexed": build_result.total_files,
|
|
126
|
+
"dirs_indexed": build_result.total_dirs,
|
|
127
|
+
"index_root": str(build_result.index_root),
|
|
128
|
+
"project_id": build_result.project_id,
|
|
129
|
+
"languages": languages or sorted(config.supported_languages.keys()),
|
|
130
|
+
"errors": len(build_result.errors),
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if json_mode:
|
|
134
|
+
print_json(success=True, result=result)
|
|
135
|
+
else:
|
|
136
|
+
console.print(f"[green]OK[/green] Indexed [bold]{build_result.total_files}[/bold] files in [bold]{build_result.total_dirs}[/bold] directories")
|
|
137
|
+
console.print(f" Index root: {build_result.index_root}")
|
|
138
|
+
if build_result.errors:
|
|
139
|
+
console.print(f" [yellow]Warnings:[/yellow] {len(build_result.errors)} errors")
|
|
140
|
+
|
|
141
|
+
# Auto-generate embeddings if semantic search is available
|
|
142
|
+
if not no_embeddings:
|
|
143
|
+
try:
|
|
144
|
+
from codexlens.semantic import SEMANTIC_AVAILABLE
|
|
145
|
+
from codexlens.cli.embedding_manager import generate_embeddings_recursive, get_embeddings_status
|
|
146
|
+
|
|
147
|
+
if SEMANTIC_AVAILABLE:
|
|
148
|
+
# Use the index root directory (not the _index.db file)
|
|
149
|
+
index_root = Path(build_result.index_root)
|
|
150
|
+
|
|
151
|
+
if not json_mode:
|
|
152
|
+
console.print("\n[bold]Generating embeddings...[/bold]")
|
|
153
|
+
console.print(f"Model: [cyan]{embedding_model}[/cyan]")
|
|
154
|
+
else:
|
|
155
|
+
# Output progress message for JSON mode (parsed by Node.js)
|
|
156
|
+
print("Generating embeddings...", flush=True)
|
|
157
|
+
|
|
158
|
+
# Progress callback - outputs progress for both json and non-json modes
|
|
159
|
+
# Node.js parseProgressLine() expects formats like:
|
|
160
|
+
# - "Batch X: N files, M chunks"
|
|
161
|
+
# - "Processing N files"
|
|
162
|
+
# - "Finalizing index"
|
|
163
|
+
def progress_update(msg: str):
|
|
164
|
+
if json_mode:
|
|
165
|
+
# Output without prefix so Node.js can parse it
|
|
166
|
+
# Strip leading spaces that embedding_manager adds
|
|
167
|
+
print(msg.strip(), flush=True)
|
|
168
|
+
elif verbose:
|
|
169
|
+
console.print(f" {msg}")
|
|
170
|
+
|
|
171
|
+
embed_result = generate_embeddings_recursive(
|
|
172
|
+
index_root,
|
|
173
|
+
model_profile=embedding_model,
|
|
174
|
+
force=False, # Don't force regenerate during init
|
|
175
|
+
chunk_size=2000,
|
|
176
|
+
progress_callback=progress_update, # Always use callback
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
if embed_result["success"]:
|
|
180
|
+
embed_data = embed_result["result"]
|
|
181
|
+
|
|
182
|
+
# Output completion message for Node.js to parse
|
|
183
|
+
if json_mode:
|
|
184
|
+
print(f"Embeddings complete: {embed_data['total_chunks_created']} chunks", flush=True)
|
|
185
|
+
|
|
186
|
+
# Get comprehensive coverage statistics
|
|
187
|
+
status_result = get_embeddings_status(index_root)
|
|
188
|
+
if status_result["success"]:
|
|
189
|
+
coverage = status_result["result"]
|
|
190
|
+
result["embeddings"] = {
|
|
191
|
+
"generated": True,
|
|
192
|
+
"total_indexes": coverage["total_indexes"],
|
|
193
|
+
"total_files": coverage["total_files"],
|
|
194
|
+
"files_with_embeddings": coverage["files_with_embeddings"],
|
|
195
|
+
"coverage_percent": coverage["coverage_percent"],
|
|
196
|
+
"total_chunks": coverage["total_chunks"],
|
|
197
|
+
}
|
|
198
|
+
else:
|
|
199
|
+
result["embeddings"] = {
|
|
200
|
+
"generated": True,
|
|
201
|
+
"total_chunks": embed_data["total_chunks_created"],
|
|
202
|
+
"files_processed": embed_data["total_files_processed"],
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if not json_mode:
|
|
206
|
+
console.print(f"[green]✓[/green] Generated embeddings for [bold]{embed_data['total_files_processed']}[/bold] files")
|
|
207
|
+
console.print(f" Total chunks: [bold]{embed_data['total_chunks_created']}[/bold]")
|
|
208
|
+
console.print(f" Indexes processed: [bold]{embed_data['indexes_successful']}/{embed_data['indexes_processed']}[/bold]")
|
|
209
|
+
else:
|
|
210
|
+
if not json_mode:
|
|
211
|
+
console.print(f"[yellow]Warning:[/yellow] Embedding generation failed: {embed_result.get('error', 'Unknown error')}")
|
|
212
|
+
result["embeddings"] = {
|
|
213
|
+
"generated": False,
|
|
214
|
+
"error": embed_result.get("error"),
|
|
215
|
+
}
|
|
216
|
+
else:
|
|
217
|
+
if not json_mode and verbose:
|
|
218
|
+
console.print("[dim]Semantic search not available. Skipping embeddings.[/dim]")
|
|
219
|
+
result["embeddings"] = {
|
|
220
|
+
"generated": False,
|
|
221
|
+
"error": "Semantic dependencies not installed",
|
|
222
|
+
}
|
|
223
|
+
except Exception as e:
|
|
224
|
+
if not json_mode and verbose:
|
|
225
|
+
console.print(f"[yellow]Warning:[/yellow] Could not generate embeddings: {e}")
|
|
226
|
+
result["embeddings"] = {
|
|
227
|
+
"generated": False,
|
|
228
|
+
"error": str(e),
|
|
229
|
+
}
|
|
230
|
+
else:
|
|
231
|
+
result["embeddings"] = {
|
|
232
|
+
"generated": False,
|
|
233
|
+
"error": "Skipped (--no-embeddings)",
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
except StorageError as exc:
|
|
237
|
+
if json_mode:
|
|
238
|
+
print_json(success=False, error=f"Storage error: {exc}")
|
|
239
|
+
else:
|
|
240
|
+
console.print(f"[red]Init failed (storage):[/red] {exc}")
|
|
241
|
+
raise typer.Exit(code=1)
|
|
242
|
+
except ConfigError as exc:
|
|
243
|
+
if json_mode:
|
|
244
|
+
print_json(success=False, error=f"Configuration error: {exc}")
|
|
245
|
+
else:
|
|
246
|
+
console.print(f"[red]Init failed (config):[/red] {exc}")
|
|
247
|
+
raise typer.Exit(code=1)
|
|
248
|
+
except ParseError as exc:
|
|
249
|
+
if json_mode:
|
|
250
|
+
print_json(success=False, error=f"Parse error: {exc}")
|
|
251
|
+
else:
|
|
252
|
+
console.print(f"[red]Init failed (parse):[/red] {exc}")
|
|
253
|
+
raise typer.Exit(code=1)
|
|
254
|
+
except PermissionError as exc:
|
|
255
|
+
if json_mode:
|
|
256
|
+
print_json(success=False, error=f"Permission denied: {exc}")
|
|
257
|
+
else:
|
|
258
|
+
console.print(f"[red]Init failed (permission denied):[/red] {exc}")
|
|
259
|
+
raise typer.Exit(code=1)
|
|
260
|
+
except CodexLensError as exc:
|
|
261
|
+
if json_mode:
|
|
262
|
+
print_json(success=False, error=str(exc))
|
|
263
|
+
else:
|
|
264
|
+
console.print(f"[red]Init failed:[/red] {exc}")
|
|
265
|
+
raise typer.Exit(code=1)
|
|
266
|
+
finally:
|
|
267
|
+
if registry is not None:
|
|
268
|
+
registry.close()
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@app.command()
|
|
272
|
+
def search(
|
|
273
|
+
query: str = typer.Argument(..., help="FTS query to run."),
|
|
274
|
+
path: Path = typer.Option(Path("."), "--path", "-p", help="Directory to search from."),
|
|
275
|
+
limit: int = typer.Option(20, "--limit", "-n", min=1, max=500, help="Max results."),
|
|
276
|
+
depth: int = typer.Option(-1, "--depth", "-d", help="Search depth (-1 = unlimited, 0 = current only)."),
|
|
277
|
+
files_only: bool = typer.Option(False, "--files-only", "-f", help="Return only file paths without content snippets."),
|
|
278
|
+
mode: str = typer.Option("auto", "--mode", "-m", help="Search mode: auto, exact, fuzzy, hybrid, vector, pure-vector."),
|
|
279
|
+
weights: Optional[str] = typer.Option(None, "--weights", help="Custom RRF weights as 'exact,fuzzy,vector' (e.g., '0.5,0.3,0.2')."),
|
|
280
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
281
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
282
|
+
) -> None:
|
|
283
|
+
"""Search indexed file contents using SQLite FTS5 or semantic vectors.
|
|
284
|
+
|
|
285
|
+
Uses chain search across directory indexes.
|
|
286
|
+
Use --depth to limit search recursion (0 = current dir only).
|
|
287
|
+
|
|
288
|
+
Search Modes:
|
|
289
|
+
- auto: Auto-detect (hybrid if embeddings exist, exact otherwise) [default]
|
|
290
|
+
- exact: Exact FTS using unicode61 tokenizer - for code identifiers
|
|
291
|
+
- fuzzy: Fuzzy FTS using trigram tokenizer - for typo-tolerant search
|
|
292
|
+
- hybrid: RRF fusion of exact + fuzzy + vector (recommended) - best recall
|
|
293
|
+
- vector: Vector search with exact FTS fallback - semantic + keyword
|
|
294
|
+
- pure-vector: Pure semantic vector search only - natural language queries
|
|
295
|
+
|
|
296
|
+
Vector Search Requirements:
|
|
297
|
+
Vector search modes require pre-generated embeddings.
|
|
298
|
+
Use 'codexlens embeddings-generate' to create embeddings first.
|
|
299
|
+
|
|
300
|
+
Hybrid Mode:
|
|
301
|
+
Default weights: exact=0.4, fuzzy=0.3, vector=0.3
|
|
302
|
+
Use --weights to customize (e.g., --weights 0.5,0.3,0.2)
|
|
303
|
+
|
|
304
|
+
Examples:
|
|
305
|
+
# Auto-detect mode (uses hybrid if embeddings available)
|
|
306
|
+
codexlens search "authentication"
|
|
307
|
+
|
|
308
|
+
# Explicit exact code search
|
|
309
|
+
codexlens search "authenticate_user" --mode exact
|
|
310
|
+
|
|
311
|
+
# Semantic search (requires embeddings)
|
|
312
|
+
codexlens search "how to verify user credentials" --mode pure-vector
|
|
313
|
+
|
|
314
|
+
# Force hybrid mode
|
|
315
|
+
codexlens search "authentication" --mode hybrid
|
|
316
|
+
"""
|
|
317
|
+
_configure_logging(verbose)
|
|
318
|
+
search_path = path.expanduser().resolve()
|
|
319
|
+
|
|
320
|
+
# Validate mode
|
|
321
|
+
valid_modes = ["auto", "exact", "fuzzy", "hybrid", "vector", "pure-vector"]
|
|
322
|
+
if mode not in valid_modes:
|
|
323
|
+
if json_mode:
|
|
324
|
+
print_json(success=False, error=f"Invalid mode: {mode}. Must be one of: {', '.join(valid_modes)}")
|
|
325
|
+
else:
|
|
326
|
+
console.print(f"[red]Invalid mode:[/red] {mode}")
|
|
327
|
+
console.print(f"[dim]Valid modes: {', '.join(valid_modes)}[/dim]")
|
|
328
|
+
raise typer.Exit(code=1)
|
|
329
|
+
|
|
330
|
+
# Parse custom weights if provided
|
|
331
|
+
hybrid_weights = None
|
|
332
|
+
if weights:
|
|
333
|
+
try:
|
|
334
|
+
weight_parts = [float(w.strip()) for w in weights.split(",")]
|
|
335
|
+
if len(weight_parts) == 3:
|
|
336
|
+
weight_sum = sum(weight_parts)
|
|
337
|
+
if abs(weight_sum - 1.0) > 0.01:
|
|
338
|
+
console.print(f"[yellow]Warning: Weights sum to {weight_sum:.2f}, should sum to 1.0. Normalizing...[/yellow]")
|
|
339
|
+
# Normalize weights
|
|
340
|
+
weight_parts = [w / weight_sum for w in weight_parts]
|
|
341
|
+
hybrid_weights = {
|
|
342
|
+
"exact": weight_parts[0],
|
|
343
|
+
"fuzzy": weight_parts[1],
|
|
344
|
+
"vector": weight_parts[2],
|
|
345
|
+
}
|
|
346
|
+
else:
|
|
347
|
+
console.print("[yellow]Warning: Invalid weights format (need 3 values). Using defaults.[/yellow]")
|
|
348
|
+
except ValueError:
|
|
349
|
+
console.print("[yellow]Warning: Invalid weights format. Using defaults.[/yellow]")
|
|
350
|
+
|
|
351
|
+
registry: RegistryStore | None = None
|
|
352
|
+
try:
|
|
353
|
+
registry = RegistryStore()
|
|
354
|
+
registry.initialize()
|
|
355
|
+
mapper = PathMapper()
|
|
356
|
+
|
|
357
|
+
engine = ChainSearchEngine(registry, mapper)
|
|
358
|
+
|
|
359
|
+
# Auto-detect mode if set to "auto"
|
|
360
|
+
actual_mode = mode
|
|
361
|
+
if mode == "auto":
|
|
362
|
+
# Check if embeddings are available by looking for project in registry
|
|
363
|
+
project_record = registry.find_by_source_path(str(search_path))
|
|
364
|
+
has_embeddings = False
|
|
365
|
+
|
|
366
|
+
if project_record:
|
|
367
|
+
# Check if index has embeddings
|
|
368
|
+
index_path = Path(project_record["index_root"]) / "_index.db"
|
|
369
|
+
try:
|
|
370
|
+
from codexlens.cli.embedding_manager import check_embeddings_status
|
|
371
|
+
embed_status = check_embeddings_status(index_path)
|
|
372
|
+
if embed_status["success"]:
|
|
373
|
+
embed_data = embed_status["result"]
|
|
374
|
+
has_embeddings = embed_data["has_embeddings"] and embed_data["chunks_count"] > 0
|
|
375
|
+
except Exception:
|
|
376
|
+
pass
|
|
377
|
+
|
|
378
|
+
# Choose mode based on embedding availability
|
|
379
|
+
if has_embeddings:
|
|
380
|
+
actual_mode = "hybrid"
|
|
381
|
+
if not json_mode and verbose:
|
|
382
|
+
console.print("[dim]Auto-detected mode: hybrid (embeddings available)[/dim]")
|
|
383
|
+
else:
|
|
384
|
+
actual_mode = "exact"
|
|
385
|
+
if not json_mode and verbose:
|
|
386
|
+
console.print("[dim]Auto-detected mode: exact (no embeddings)[/dim]")
|
|
387
|
+
|
|
388
|
+
# Map mode to options
|
|
389
|
+
if actual_mode == "exact":
|
|
390
|
+
hybrid_mode, enable_fuzzy, enable_vector, pure_vector = False, False, False, False
|
|
391
|
+
elif actual_mode == "fuzzy":
|
|
392
|
+
hybrid_mode, enable_fuzzy, enable_vector, pure_vector = False, True, False, False
|
|
393
|
+
elif actual_mode == "vector":
|
|
394
|
+
hybrid_mode, enable_fuzzy, enable_vector, pure_vector = True, False, True, False # Vector + exact fallback
|
|
395
|
+
elif actual_mode == "pure-vector":
|
|
396
|
+
hybrid_mode, enable_fuzzy, enable_vector, pure_vector = True, False, True, True # Pure vector only
|
|
397
|
+
elif actual_mode == "hybrid":
|
|
398
|
+
hybrid_mode, enable_fuzzy, enable_vector, pure_vector = True, True, True, False
|
|
399
|
+
else:
|
|
400
|
+
raise ValueError(f"Invalid mode: {actual_mode}")
|
|
401
|
+
|
|
402
|
+
options = SearchOptions(
|
|
403
|
+
depth=depth,
|
|
404
|
+
total_limit=limit,
|
|
405
|
+
files_only=files_only,
|
|
406
|
+
hybrid_mode=hybrid_mode,
|
|
407
|
+
enable_fuzzy=enable_fuzzy,
|
|
408
|
+
enable_vector=enable_vector,
|
|
409
|
+
pure_vector=pure_vector,
|
|
410
|
+
hybrid_weights=hybrid_weights,
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
if files_only:
|
|
414
|
+
file_paths = engine.search_files_only(query, search_path, options)
|
|
415
|
+
payload = {"query": query, "count": len(file_paths), "files": file_paths}
|
|
416
|
+
if json_mode:
|
|
417
|
+
print_json(success=True, result=payload)
|
|
418
|
+
else:
|
|
419
|
+
for fp in file_paths:
|
|
420
|
+
console.print(fp)
|
|
421
|
+
else:
|
|
422
|
+
result = engine.search(query, search_path, options)
|
|
423
|
+
results_list = [
|
|
424
|
+
{
|
|
425
|
+
"path": r.path,
|
|
426
|
+
"score": r.score,
|
|
427
|
+
"excerpt": r.excerpt,
|
|
428
|
+
"source": getattr(r, "search_source", None),
|
|
429
|
+
"symbol": getattr(r, "symbol", None),
|
|
430
|
+
}
|
|
431
|
+
for r in result.results
|
|
432
|
+
]
|
|
433
|
+
|
|
434
|
+
payload = {
|
|
435
|
+
"query": query,
|
|
436
|
+
"mode": actual_mode,
|
|
437
|
+
"count": len(results_list),
|
|
438
|
+
"results": results_list,
|
|
439
|
+
"stats": {
|
|
440
|
+
"dirs_searched": result.stats.dirs_searched,
|
|
441
|
+
"files_matched": result.stats.files_matched,
|
|
442
|
+
"time_ms": result.stats.time_ms,
|
|
443
|
+
},
|
|
444
|
+
}
|
|
445
|
+
if json_mode:
|
|
446
|
+
print_json(success=True, result=payload)
|
|
447
|
+
else:
|
|
448
|
+
render_search_results(result.results, verbose=verbose)
|
|
449
|
+
console.print(f"[dim]Mode: {actual_mode} | Searched {result.stats.dirs_searched} directories in {result.stats.time_ms:.1f}ms[/dim]")
|
|
450
|
+
|
|
451
|
+
except SearchError as exc:
|
|
452
|
+
if json_mode:
|
|
453
|
+
print_json(success=False, error=f"Search error: {exc}")
|
|
454
|
+
else:
|
|
455
|
+
console.print(f"[red]Search failed (query):[/red] {exc}")
|
|
456
|
+
raise typer.Exit(code=1)
|
|
457
|
+
except StorageError as exc:
|
|
458
|
+
if json_mode:
|
|
459
|
+
print_json(success=False, error=f"Storage error: {exc}")
|
|
460
|
+
else:
|
|
461
|
+
console.print(f"[red]Search failed (storage):[/red] {exc}")
|
|
462
|
+
raise typer.Exit(code=1)
|
|
463
|
+
except CodexLensError as exc:
|
|
464
|
+
if json_mode:
|
|
465
|
+
print_json(success=False, error=str(exc))
|
|
466
|
+
else:
|
|
467
|
+
console.print(f"[red]Search failed:[/red] {exc}")
|
|
468
|
+
raise typer.Exit(code=1)
|
|
469
|
+
finally:
|
|
470
|
+
if registry is not None:
|
|
471
|
+
registry.close()
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
@app.command()
|
|
475
|
+
def symbol(
|
|
476
|
+
name: str = typer.Argument(..., help="Symbol name to look up."),
|
|
477
|
+
path: Path = typer.Option(Path("."), "--path", "-p", help="Directory to search from."),
|
|
478
|
+
kind: Optional[str] = typer.Option(
|
|
479
|
+
None,
|
|
480
|
+
"--kind",
|
|
481
|
+
"-k",
|
|
482
|
+
help="Filter by kind (function|class|method).",
|
|
483
|
+
),
|
|
484
|
+
limit: int = typer.Option(50, "--limit", "-n", min=1, max=500, help="Max symbols."),
|
|
485
|
+
depth: int = typer.Option(-1, "--depth", "-d", help="Search depth (-1 = unlimited)."),
|
|
486
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
487
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
488
|
+
) -> None:
|
|
489
|
+
"""Look up symbols by name and optional kind."""
|
|
490
|
+
_configure_logging(verbose)
|
|
491
|
+
search_path = path.expanduser().resolve()
|
|
492
|
+
|
|
493
|
+
registry: RegistryStore | None = None
|
|
494
|
+
try:
|
|
495
|
+
registry = RegistryStore()
|
|
496
|
+
registry.initialize()
|
|
497
|
+
mapper = PathMapper()
|
|
498
|
+
|
|
499
|
+
engine = ChainSearchEngine(registry, mapper)
|
|
500
|
+
options = SearchOptions(depth=depth, total_limit=limit)
|
|
501
|
+
|
|
502
|
+
syms = engine.search_symbols(name, search_path, kind=kind, options=options)
|
|
503
|
+
|
|
504
|
+
payload = {"name": name, "kind": kind, "count": len(syms), "symbols": syms}
|
|
505
|
+
if json_mode:
|
|
506
|
+
print_json(success=True, result=payload)
|
|
507
|
+
else:
|
|
508
|
+
render_symbols(syms)
|
|
509
|
+
|
|
510
|
+
except SearchError as exc:
|
|
511
|
+
if json_mode:
|
|
512
|
+
print_json(success=False, error=f"Search error: {exc}")
|
|
513
|
+
else:
|
|
514
|
+
console.print(f"[red]Symbol lookup failed (search):[/red] {exc}")
|
|
515
|
+
raise typer.Exit(code=1)
|
|
516
|
+
except StorageError as exc:
|
|
517
|
+
if json_mode:
|
|
518
|
+
print_json(success=False, error=f"Storage error: {exc}")
|
|
519
|
+
else:
|
|
520
|
+
console.print(f"[red]Symbol lookup failed (storage):[/red] {exc}")
|
|
521
|
+
raise typer.Exit(code=1)
|
|
522
|
+
except CodexLensError as exc:
|
|
523
|
+
if json_mode:
|
|
524
|
+
print_json(success=False, error=str(exc))
|
|
525
|
+
else:
|
|
526
|
+
console.print(f"[red]Symbol lookup failed:[/red] {exc}")
|
|
527
|
+
raise typer.Exit(code=1)
|
|
528
|
+
finally:
|
|
529
|
+
if registry is not None:
|
|
530
|
+
registry.close()
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
@app.command()
|
|
534
|
+
def inspect(
|
|
535
|
+
file: Path = typer.Argument(..., exists=True, dir_okay=False, help="File to analyze."),
|
|
536
|
+
symbols: bool = typer.Option(True, "--symbols/--no-symbols", help="Show discovered symbols."),
|
|
537
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
538
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
539
|
+
) -> None:
|
|
540
|
+
"""Analyze a single file and display symbols."""
|
|
541
|
+
_configure_logging(verbose)
|
|
542
|
+
config = Config()
|
|
543
|
+
factory = ParserFactory(config)
|
|
544
|
+
|
|
545
|
+
file_path = file.expanduser().resolve()
|
|
546
|
+
try:
|
|
547
|
+
text = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
548
|
+
language_id = config.language_for_path(file_path) or "unknown"
|
|
549
|
+
parser = factory.get_parser(language_id)
|
|
550
|
+
indexed = parser.parse(text, file_path)
|
|
551
|
+
payload = {"file": indexed, "content_lines": len(text.splitlines())}
|
|
552
|
+
if json_mode:
|
|
553
|
+
print_json(success=True, result=payload)
|
|
554
|
+
else:
|
|
555
|
+
if symbols:
|
|
556
|
+
render_file_inspect(indexed.path, indexed.language, indexed.symbols)
|
|
557
|
+
else:
|
|
558
|
+
render_status({"file": indexed.path, "language": indexed.language})
|
|
559
|
+
except ParseError as exc:
|
|
560
|
+
if json_mode:
|
|
561
|
+
print_json(success=False, error=f"Parse error: {exc}")
|
|
562
|
+
else:
|
|
563
|
+
console.print(f"[red]Inspect failed (parse):[/red] {exc}")
|
|
564
|
+
raise typer.Exit(code=1)
|
|
565
|
+
except FileNotFoundError as exc:
|
|
566
|
+
if json_mode:
|
|
567
|
+
print_json(success=False, error=f"File not found: {exc}")
|
|
568
|
+
else:
|
|
569
|
+
console.print(f"[red]Inspect failed (file not found):[/red] {exc}")
|
|
570
|
+
raise typer.Exit(code=1)
|
|
571
|
+
except PermissionError as exc:
|
|
572
|
+
if json_mode:
|
|
573
|
+
print_json(success=False, error=f"Permission denied: {exc}")
|
|
574
|
+
else:
|
|
575
|
+
console.print(f"[red]Inspect failed (permission denied):[/red] {exc}")
|
|
576
|
+
raise typer.Exit(code=1)
|
|
577
|
+
except CodexLensError as exc:
|
|
578
|
+
if json_mode:
|
|
579
|
+
print_json(success=False, error=str(exc))
|
|
580
|
+
else:
|
|
581
|
+
console.print(f"[red]Inspect failed:[/red] {exc}")
|
|
582
|
+
raise typer.Exit(code=1)
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
@app.command()
|
|
586
|
+
def status(
|
|
587
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
588
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
589
|
+
) -> None:
|
|
590
|
+
"""Show index status and configuration."""
|
|
591
|
+
_configure_logging(verbose)
|
|
592
|
+
|
|
593
|
+
registry: RegistryStore | None = None
|
|
594
|
+
try:
|
|
595
|
+
registry = RegistryStore()
|
|
596
|
+
registry.initialize()
|
|
597
|
+
mapper = PathMapper()
|
|
598
|
+
|
|
599
|
+
# Get all projects
|
|
600
|
+
projects = registry.list_projects()
|
|
601
|
+
|
|
602
|
+
# Calculate total stats
|
|
603
|
+
total_files = sum(p.total_files for p in projects)
|
|
604
|
+
total_dirs = sum(p.total_dirs for p in projects)
|
|
605
|
+
|
|
606
|
+
# Get index root size
|
|
607
|
+
index_root = mapper.index_root
|
|
608
|
+
index_size = 0
|
|
609
|
+
if index_root.exists():
|
|
610
|
+
for f in index_root.rglob("*"):
|
|
611
|
+
if f.is_file():
|
|
612
|
+
index_size += f.stat().st_size
|
|
613
|
+
|
|
614
|
+
# Check schema version and enabled features
|
|
615
|
+
schema_version = None
|
|
616
|
+
has_dual_fts = False
|
|
617
|
+
if projects and index_root.exists():
|
|
618
|
+
# Check first index database for features
|
|
619
|
+
index_files = list(index_root.rglob("_index.db"))
|
|
620
|
+
if index_files:
|
|
621
|
+
try:
|
|
622
|
+
with DirIndexStore(index_files[0]) as store:
|
|
623
|
+
with store._lock:
|
|
624
|
+
conn = store._get_connection()
|
|
625
|
+
schema_version = store._get_schema_version(conn)
|
|
626
|
+
# Check if dual FTS tables exist
|
|
627
|
+
cursor = conn.execute(
|
|
628
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name IN ('search_fts_exact', 'search_fts_fuzzy')"
|
|
629
|
+
)
|
|
630
|
+
fts_tables = [row[0] for row in cursor.fetchall()]
|
|
631
|
+
has_dual_fts = len(fts_tables) == 2
|
|
632
|
+
except Exception:
|
|
633
|
+
pass
|
|
634
|
+
|
|
635
|
+
# Check embeddings coverage
|
|
636
|
+
embeddings_info = None
|
|
637
|
+
has_vector_search = False
|
|
638
|
+
try:
|
|
639
|
+
from codexlens.cli.embedding_manager import get_embeddings_status
|
|
640
|
+
|
|
641
|
+
if index_root.exists():
|
|
642
|
+
embed_status = get_embeddings_status(index_root)
|
|
643
|
+
if embed_status["success"]:
|
|
644
|
+
embeddings_info = embed_status["result"]
|
|
645
|
+
# Enable vector search if coverage >= 50%
|
|
646
|
+
has_vector_search = embeddings_info["coverage_percent"] >= 50.0
|
|
647
|
+
except ImportError:
|
|
648
|
+
# Embedding manager not available
|
|
649
|
+
pass
|
|
650
|
+
except Exception as e:
|
|
651
|
+
logger.debug(f"Failed to get embeddings status: {e}")
|
|
652
|
+
|
|
653
|
+
stats = {
|
|
654
|
+
"index_root": str(index_root),
|
|
655
|
+
"registry_path": str(_get_registry_path()),
|
|
656
|
+
"projects_count": len(projects),
|
|
657
|
+
"total_files": total_files,
|
|
658
|
+
"total_dirs": total_dirs,
|
|
659
|
+
"index_size_bytes": index_size,
|
|
660
|
+
"index_size_mb": round(index_size / (1024 * 1024), 2),
|
|
661
|
+
"schema_version": schema_version,
|
|
662
|
+
"features": {
|
|
663
|
+
"exact_fts": True, # Always available
|
|
664
|
+
"fuzzy_fts": has_dual_fts,
|
|
665
|
+
"hybrid_search": has_dual_fts,
|
|
666
|
+
"vector_search": has_vector_search,
|
|
667
|
+
},
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
# Add embeddings info if available
|
|
671
|
+
if embeddings_info:
|
|
672
|
+
stats["embeddings"] = embeddings_info
|
|
673
|
+
|
|
674
|
+
if json_mode:
|
|
675
|
+
print_json(success=True, result=stats)
|
|
676
|
+
else:
|
|
677
|
+
console.print("[bold]CodexLens Status[/bold]")
|
|
678
|
+
console.print(f" Index Root: {stats['index_root']}")
|
|
679
|
+
console.print(f" Registry: {stats['registry_path']}")
|
|
680
|
+
console.print(f" Projects: {stats['projects_count']}")
|
|
681
|
+
console.print(f" Total Files: {stats['total_files']}")
|
|
682
|
+
console.print(f" Total Directories: {stats['total_dirs']}")
|
|
683
|
+
console.print(f" Index Size: {stats['index_size_mb']} MB")
|
|
684
|
+
if schema_version:
|
|
685
|
+
console.print(f" Schema Version: {schema_version}")
|
|
686
|
+
console.print("\n[bold]Search Backends:[/bold]")
|
|
687
|
+
console.print(f" Exact FTS: ✓ (unicode61)")
|
|
688
|
+
if has_dual_fts:
|
|
689
|
+
console.print(f" Fuzzy FTS: ✓ (trigram)")
|
|
690
|
+
console.print(f" Hybrid Search: ✓ (RRF fusion)")
|
|
691
|
+
else:
|
|
692
|
+
console.print(f" Fuzzy FTS: ✗ (run 'migrate' to enable)")
|
|
693
|
+
console.print(f" Hybrid Search: ✗ (run 'migrate' to enable)")
|
|
694
|
+
|
|
695
|
+
if has_vector_search:
|
|
696
|
+
console.print(f" Vector Search: ✓ (embeddings available)")
|
|
697
|
+
else:
|
|
698
|
+
console.print(f" Vector Search: ✗ (no embeddings or coverage < 50%)")
|
|
699
|
+
|
|
700
|
+
# Display embeddings statistics if available
|
|
701
|
+
if embeddings_info:
|
|
702
|
+
console.print("\n[bold]Embeddings Coverage:[/bold]")
|
|
703
|
+
console.print(f" Total Indexes: {embeddings_info['total_indexes']}")
|
|
704
|
+
console.print(f" Total Files: {embeddings_info['total_files']}")
|
|
705
|
+
console.print(f" Files with Embeddings: {embeddings_info['files_with_embeddings']}")
|
|
706
|
+
console.print(f" Coverage: {embeddings_info['coverage_percent']:.1f}%")
|
|
707
|
+
console.print(f" Total Chunks: {embeddings_info['total_chunks']}")
|
|
708
|
+
|
|
709
|
+
except StorageError as exc:
|
|
710
|
+
if json_mode:
|
|
711
|
+
print_json(success=False, error=f"Storage error: {exc}")
|
|
712
|
+
else:
|
|
713
|
+
console.print(f"[red]Status failed (storage):[/red] {exc}")
|
|
714
|
+
raise typer.Exit(code=1)
|
|
715
|
+
except CodexLensError as exc:
|
|
716
|
+
if json_mode:
|
|
717
|
+
print_json(success=False, error=str(exc))
|
|
718
|
+
else:
|
|
719
|
+
console.print(f"[red]Status failed:[/red] {exc}")
|
|
720
|
+
raise typer.Exit(code=1)
|
|
721
|
+
finally:
|
|
722
|
+
if registry is not None:
|
|
723
|
+
registry.close()
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
@app.command()
|
|
727
|
+
def projects(
|
|
728
|
+
action: str = typer.Argument("list", help="Action: list, show, remove"),
|
|
729
|
+
project_path: Optional[Path] = typer.Argument(None, help="Project path (for show/remove)."),
|
|
730
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
731
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
732
|
+
) -> None:
|
|
733
|
+
"""Manage registered projects in the global registry.
|
|
734
|
+
|
|
735
|
+
Actions:
|
|
736
|
+
- list: Show all registered projects
|
|
737
|
+
- show <path>: Show details for a specific project
|
|
738
|
+
- remove <path>: Remove a project from the registry
|
|
739
|
+
"""
|
|
740
|
+
_configure_logging(verbose)
|
|
741
|
+
|
|
742
|
+
registry: RegistryStore | None = None
|
|
743
|
+
try:
|
|
744
|
+
registry = RegistryStore()
|
|
745
|
+
registry.initialize()
|
|
746
|
+
|
|
747
|
+
if action == "list":
|
|
748
|
+
project_list = registry.list_projects()
|
|
749
|
+
if json_mode:
|
|
750
|
+
result = [
|
|
751
|
+
{
|
|
752
|
+
"id": p.id,
|
|
753
|
+
"source_root": str(p.source_root),
|
|
754
|
+
"index_root": str(p.index_root),
|
|
755
|
+
"total_files": p.total_files,
|
|
756
|
+
"total_dirs": p.total_dirs,
|
|
757
|
+
"status": p.status,
|
|
758
|
+
}
|
|
759
|
+
for p in project_list
|
|
760
|
+
]
|
|
761
|
+
print_json(success=True, result=result)
|
|
762
|
+
else:
|
|
763
|
+
if not project_list:
|
|
764
|
+
console.print("[yellow]No projects registered.[/yellow]")
|
|
765
|
+
else:
|
|
766
|
+
table = Table(title="Registered Projects")
|
|
767
|
+
table.add_column("ID", style="dim")
|
|
768
|
+
table.add_column("Source Root")
|
|
769
|
+
table.add_column("Files", justify="right")
|
|
770
|
+
table.add_column("Dirs", justify="right")
|
|
771
|
+
table.add_column("Status")
|
|
772
|
+
|
|
773
|
+
for p in project_list:
|
|
774
|
+
table.add_row(
|
|
775
|
+
str(p.id),
|
|
776
|
+
str(p.source_root),
|
|
777
|
+
str(p.total_files),
|
|
778
|
+
str(p.total_dirs),
|
|
779
|
+
p.status,
|
|
780
|
+
)
|
|
781
|
+
console.print(table)
|
|
782
|
+
|
|
783
|
+
elif action == "show":
|
|
784
|
+
if not project_path:
|
|
785
|
+
raise typer.BadParameter("Project path required for 'show' action")
|
|
786
|
+
|
|
787
|
+
project_path = project_path.expanduser().resolve()
|
|
788
|
+
project_info = registry.get_project(project_path)
|
|
789
|
+
|
|
790
|
+
if not project_info:
|
|
791
|
+
if json_mode:
|
|
792
|
+
print_json(success=False, error=f"Project not found: {project_path}")
|
|
793
|
+
else:
|
|
794
|
+
console.print(f"[red]Project not found:[/red] {project_path}")
|
|
795
|
+
raise typer.Exit(code=1)
|
|
796
|
+
|
|
797
|
+
if json_mode:
|
|
798
|
+
result = {
|
|
799
|
+
"id": project_info.id,
|
|
800
|
+
"source_root": str(project_info.source_root),
|
|
801
|
+
"index_root": str(project_info.index_root),
|
|
802
|
+
"total_files": project_info.total_files,
|
|
803
|
+
"total_dirs": project_info.total_dirs,
|
|
804
|
+
"status": project_info.status,
|
|
805
|
+
"created_at": project_info.created_at,
|
|
806
|
+
"last_indexed": project_info.last_indexed,
|
|
807
|
+
}
|
|
808
|
+
print_json(success=True, result=result)
|
|
809
|
+
else:
|
|
810
|
+
console.print(f"[bold]Project:[/bold] {project_info.source_root}")
|
|
811
|
+
console.print(f" ID: {project_info.id}")
|
|
812
|
+
console.print(f" Index Root: {project_info.index_root}")
|
|
813
|
+
console.print(f" Files: {project_info.total_files}")
|
|
814
|
+
console.print(f" Directories: {project_info.total_dirs}")
|
|
815
|
+
console.print(f" Status: {project_info.status}")
|
|
816
|
+
|
|
817
|
+
# Show directory breakdown
|
|
818
|
+
dirs = registry.get_project_dirs(project_info.id)
|
|
819
|
+
if dirs:
|
|
820
|
+
console.print(f"\n [bold]Indexed Directories:[/bold] {len(dirs)}")
|
|
821
|
+
for d in dirs[:10]:
|
|
822
|
+
console.print(f" - {d.source_path.name}/ ({d.files_count} files)")
|
|
823
|
+
if len(dirs) > 10:
|
|
824
|
+
console.print(f" ... and {len(dirs) - 10} more")
|
|
825
|
+
|
|
826
|
+
elif action == "remove":
|
|
827
|
+
if not project_path:
|
|
828
|
+
raise typer.BadParameter("Project path required for 'remove' action")
|
|
829
|
+
|
|
830
|
+
project_path = project_path.expanduser().resolve()
|
|
831
|
+
removed = registry.unregister_project(project_path)
|
|
832
|
+
|
|
833
|
+
if removed:
|
|
834
|
+
mapper = PathMapper()
|
|
835
|
+
index_root = mapper.source_to_index_dir(project_path)
|
|
836
|
+
if index_root.exists():
|
|
837
|
+
shutil.rmtree(index_root)
|
|
838
|
+
|
|
839
|
+
if json_mode:
|
|
840
|
+
print_json(success=True, result={"removed": str(project_path)})
|
|
841
|
+
else:
|
|
842
|
+
console.print(f"[green]Removed:[/green] {project_path}")
|
|
843
|
+
else:
|
|
844
|
+
if json_mode:
|
|
845
|
+
print_json(success=False, error=f"Project not found: {project_path}")
|
|
846
|
+
else:
|
|
847
|
+
console.print(f"[yellow]Project not found:[/yellow] {project_path}")
|
|
848
|
+
|
|
849
|
+
else:
|
|
850
|
+
raise typer.BadParameter(f"Unknown action: {action}. Use list, show, or remove.")
|
|
851
|
+
|
|
852
|
+
except typer.BadParameter:
|
|
853
|
+
raise
|
|
854
|
+
except StorageError as exc:
|
|
855
|
+
if json_mode:
|
|
856
|
+
print_json(success=False, error=f"Storage error: {exc}")
|
|
857
|
+
else:
|
|
858
|
+
console.print(f"[red]Projects command failed (storage):[/red] {exc}")
|
|
859
|
+
raise typer.Exit(code=1)
|
|
860
|
+
except PermissionError as exc:
|
|
861
|
+
if json_mode:
|
|
862
|
+
print_json(success=False, error=f"Permission denied: {exc}")
|
|
863
|
+
else:
|
|
864
|
+
console.print(f"[red]Projects command failed (permission denied):[/red] {exc}")
|
|
865
|
+
raise typer.Exit(code=1)
|
|
866
|
+
except CodexLensError as exc:
|
|
867
|
+
if json_mode:
|
|
868
|
+
print_json(success=False, error=str(exc))
|
|
869
|
+
else:
|
|
870
|
+
console.print(f"[red]Projects command failed:[/red] {exc}")
|
|
871
|
+
raise typer.Exit(code=1)
|
|
872
|
+
finally:
|
|
873
|
+
if registry is not None:
|
|
874
|
+
registry.close()
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
@app.command()
|
|
878
|
+
def config(
|
|
879
|
+
action: str = typer.Argument("show", help="Action: show, set, migrate"),
|
|
880
|
+
key: Optional[str] = typer.Argument(None, help="Config key (for set action)."),
|
|
881
|
+
value: Optional[str] = typer.Argument(None, help="Config value (for set action)."),
|
|
882
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
883
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
884
|
+
) -> None:
|
|
885
|
+
"""Manage CodexLens configuration.
|
|
886
|
+
|
|
887
|
+
Actions:
|
|
888
|
+
- show: Display current configuration
|
|
889
|
+
- set <key> <value>: Set configuration value
|
|
890
|
+
- migrate <new_path>: Migrate indexes to new location
|
|
891
|
+
|
|
892
|
+
Config keys:
|
|
893
|
+
- index_dir: Directory to store indexes (default: ~/.codexlens/indexes)
|
|
894
|
+
"""
|
|
895
|
+
_configure_logging(verbose)
|
|
896
|
+
|
|
897
|
+
config_file = Path.home() / ".codexlens" / "config.json"
|
|
898
|
+
|
|
899
|
+
def load_config() -> Dict[str, Any]:
|
|
900
|
+
if config_file.exists():
|
|
901
|
+
return json.loads(config_file.read_text(encoding="utf-8"))
|
|
902
|
+
return {}
|
|
903
|
+
|
|
904
|
+
def save_config(cfg: Dict[str, Any]) -> None:
|
|
905
|
+
config_file.parent.mkdir(parents=True, exist_ok=True)
|
|
906
|
+
config_file.write_text(json.dumps(cfg, indent=2), encoding="utf-8")
|
|
907
|
+
|
|
908
|
+
try:
|
|
909
|
+
if action == "show":
|
|
910
|
+
cfg = load_config()
|
|
911
|
+
current_index_dir = os.getenv("CODEXLENS_INDEX_DIR") or cfg.get("index_dir") or str(Path.home() / ".codexlens" / "indexes")
|
|
912
|
+
|
|
913
|
+
result = {
|
|
914
|
+
"config_file": str(config_file),
|
|
915
|
+
"index_dir": current_index_dir,
|
|
916
|
+
"env_override": os.getenv("CODEXLENS_INDEX_DIR"),
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
if json_mode:
|
|
920
|
+
print_json(success=True, result=result)
|
|
921
|
+
else:
|
|
922
|
+
console.print("[bold]CodexLens Configuration[/bold]")
|
|
923
|
+
console.print(f" Config File: {result['config_file']}")
|
|
924
|
+
console.print(f" Index Directory: {result['index_dir']}")
|
|
925
|
+
if result['env_override']:
|
|
926
|
+
console.print(f" [dim](Override via CODEXLENS_INDEX_DIR)[/dim]")
|
|
927
|
+
|
|
928
|
+
elif action == "set":
|
|
929
|
+
if not key:
|
|
930
|
+
raise typer.BadParameter("Config key required for 'set' action")
|
|
931
|
+
if not value:
|
|
932
|
+
raise typer.BadParameter("Config value required for 'set' action")
|
|
933
|
+
|
|
934
|
+
cfg = load_config()
|
|
935
|
+
|
|
936
|
+
if key == "index_dir":
|
|
937
|
+
new_path = Path(value).expanduser().resolve()
|
|
938
|
+
cfg["index_dir"] = str(new_path)
|
|
939
|
+
save_config(cfg)
|
|
940
|
+
|
|
941
|
+
if json_mode:
|
|
942
|
+
print_json(success=True, result={"key": key, "value": str(new_path)})
|
|
943
|
+
else:
|
|
944
|
+
console.print(f"[green]Set {key}=[/green] {new_path}")
|
|
945
|
+
console.print("[yellow]Note: Existing indexes remain at old location. Use 'config migrate' to move them.[/yellow]")
|
|
946
|
+
else:
|
|
947
|
+
raise typer.BadParameter(f"Unknown config key: {key}")
|
|
948
|
+
|
|
949
|
+
elif action == "migrate":
|
|
950
|
+
if not key:
|
|
951
|
+
raise typer.BadParameter("New path required for 'migrate' action")
|
|
952
|
+
|
|
953
|
+
new_path = Path(key).expanduser().resolve()
|
|
954
|
+
mapper = PathMapper()
|
|
955
|
+
old_path = mapper.index_root
|
|
956
|
+
|
|
957
|
+
if not old_path.exists():
|
|
958
|
+
if json_mode:
|
|
959
|
+
print_json(success=False, error="No indexes to migrate")
|
|
960
|
+
else:
|
|
961
|
+
console.print("[yellow]No indexes to migrate.[/yellow]")
|
|
962
|
+
return
|
|
963
|
+
|
|
964
|
+
# Create new directory
|
|
965
|
+
new_path.mkdir(parents=True, exist_ok=True)
|
|
966
|
+
|
|
967
|
+
# Count items to migrate
|
|
968
|
+
items = list(old_path.iterdir())
|
|
969
|
+
migrated = 0
|
|
970
|
+
|
|
971
|
+
with Progress(
|
|
972
|
+
SpinnerColumn(),
|
|
973
|
+
TextColumn("[progress.description]{task.description}"),
|
|
974
|
+
BarColumn(),
|
|
975
|
+
TextColumn("{task.completed}/{task.total}"),
|
|
976
|
+
TimeElapsedColumn(),
|
|
977
|
+
console=console,
|
|
978
|
+
) as progress:
|
|
979
|
+
task = progress.add_task("Migrating indexes", total=len(items))
|
|
980
|
+
|
|
981
|
+
for item in items:
|
|
982
|
+
dest = new_path / item.name
|
|
983
|
+
if item.is_dir():
|
|
984
|
+
shutil.copytree(item, dest, dirs_exist_ok=True)
|
|
985
|
+
else:
|
|
986
|
+
shutil.copy2(item, dest)
|
|
987
|
+
migrated += 1
|
|
988
|
+
progress.advance(task)
|
|
989
|
+
|
|
990
|
+
# Update config
|
|
991
|
+
cfg = load_config()
|
|
992
|
+
cfg["index_dir"] = str(new_path)
|
|
993
|
+
save_config(cfg)
|
|
994
|
+
|
|
995
|
+
# Update registry paths
|
|
996
|
+
registry = RegistryStore()
|
|
997
|
+
registry.initialize()
|
|
998
|
+
registry.update_index_paths(old_path, new_path)
|
|
999
|
+
registry.close()
|
|
1000
|
+
|
|
1001
|
+
result = {
|
|
1002
|
+
"migrated_from": str(old_path),
|
|
1003
|
+
"migrated_to": str(new_path),
|
|
1004
|
+
"items_migrated": migrated,
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
if json_mode:
|
|
1008
|
+
print_json(success=True, result=result)
|
|
1009
|
+
else:
|
|
1010
|
+
console.print(f"[green]Migrated {migrated} items to:[/green] {new_path}")
|
|
1011
|
+
console.print("[dim]Old indexes can be manually deleted after verifying migration.[/dim]")
|
|
1012
|
+
|
|
1013
|
+
else:
|
|
1014
|
+
raise typer.BadParameter(f"Unknown action: {action}. Use show, set, or migrate.")
|
|
1015
|
+
|
|
1016
|
+
except typer.BadParameter:
|
|
1017
|
+
raise
|
|
1018
|
+
except ConfigError as exc:
|
|
1019
|
+
if json_mode:
|
|
1020
|
+
print_json(success=False, error=f"Configuration error: {exc}")
|
|
1021
|
+
else:
|
|
1022
|
+
console.print(f"[red]Config command failed (config):[/red] {exc}")
|
|
1023
|
+
raise typer.Exit(code=1)
|
|
1024
|
+
except StorageError as exc:
|
|
1025
|
+
if json_mode:
|
|
1026
|
+
print_json(success=False, error=f"Storage error: {exc}")
|
|
1027
|
+
else:
|
|
1028
|
+
console.print(f"[red]Config command failed (storage):[/red] {exc}")
|
|
1029
|
+
raise typer.Exit(code=1)
|
|
1030
|
+
except PermissionError as exc:
|
|
1031
|
+
if json_mode:
|
|
1032
|
+
print_json(success=False, error=f"Permission denied: {exc}")
|
|
1033
|
+
else:
|
|
1034
|
+
console.print(f"[red]Config command failed (permission denied):[/red] {exc}")
|
|
1035
|
+
raise typer.Exit(code=1)
|
|
1036
|
+
except CodexLensError as exc:
|
|
1037
|
+
if json_mode:
|
|
1038
|
+
print_json(success=False, error=str(exc))
|
|
1039
|
+
else:
|
|
1040
|
+
console.print(f"[red]Config command failed:[/red] {exc}")
|
|
1041
|
+
raise typer.Exit(code=1)
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
@app.command()
|
|
1045
|
+
def migrate(
|
|
1046
|
+
path: Path = typer.Argument(Path("."), exists=True, file_okay=False, dir_okay=True, help="Project root to migrate."),
|
|
1047
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
1048
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
1049
|
+
) -> None:
|
|
1050
|
+
"""Migrate project indexes to latest schema (Dual-FTS upgrade).
|
|
1051
|
+
|
|
1052
|
+
Upgrades all _index.db files in the project to schema version 4, which includes:
|
|
1053
|
+
- Dual FTS tables (exact + fuzzy)
|
|
1054
|
+
- Encoding detection support
|
|
1055
|
+
- Incremental indexing metadata
|
|
1056
|
+
|
|
1057
|
+
This is a safe operation that preserves all existing data.
|
|
1058
|
+
Progress is shown during migration.
|
|
1059
|
+
"""
|
|
1060
|
+
_configure_logging(verbose)
|
|
1061
|
+
base_path = path.expanduser().resolve()
|
|
1062
|
+
|
|
1063
|
+
registry: RegistryStore | None = None
|
|
1064
|
+
try:
|
|
1065
|
+
registry = RegistryStore()
|
|
1066
|
+
registry.initialize()
|
|
1067
|
+
mapper = PathMapper()
|
|
1068
|
+
|
|
1069
|
+
# Find project
|
|
1070
|
+
project_info = registry.get_project(base_path)
|
|
1071
|
+
if not project_info:
|
|
1072
|
+
raise CodexLensError(f"No index found for: {base_path}. Run 'codex-lens init' first.")
|
|
1073
|
+
|
|
1074
|
+
index_dir = mapper.source_to_index_dir(base_path)
|
|
1075
|
+
if not index_dir.exists():
|
|
1076
|
+
raise CodexLensError(f"Index directory not found: {index_dir}")
|
|
1077
|
+
|
|
1078
|
+
# Find all _index.db files
|
|
1079
|
+
index_files = list(index_dir.rglob("_index.db"))
|
|
1080
|
+
|
|
1081
|
+
if not index_files:
|
|
1082
|
+
if json_mode:
|
|
1083
|
+
print_json(success=True, result={"message": "No indexes to migrate", "migrated": 0})
|
|
1084
|
+
else:
|
|
1085
|
+
console.print("[yellow]No indexes found to migrate.[/yellow]")
|
|
1086
|
+
return
|
|
1087
|
+
|
|
1088
|
+
migrated_count = 0
|
|
1089
|
+
error_count = 0
|
|
1090
|
+
already_migrated = 0
|
|
1091
|
+
|
|
1092
|
+
with Progress(
|
|
1093
|
+
SpinnerColumn(),
|
|
1094
|
+
TextColumn("[progress.description]{task.description}"),
|
|
1095
|
+
BarColumn(),
|
|
1096
|
+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
|
1097
|
+
TextColumn("({task.completed}/{task.total})"),
|
|
1098
|
+
TimeElapsedColumn(),
|
|
1099
|
+
console=console,
|
|
1100
|
+
) as progress:
|
|
1101
|
+
task = progress.add_task(f"Migrating {len(index_files)} indexes...", total=len(index_files))
|
|
1102
|
+
|
|
1103
|
+
for db_path in index_files:
|
|
1104
|
+
try:
|
|
1105
|
+
store = DirIndexStore(db_path)
|
|
1106
|
+
|
|
1107
|
+
# Check current version
|
|
1108
|
+
with store._lock:
|
|
1109
|
+
conn = store._get_connection()
|
|
1110
|
+
current_version = store._get_schema_version(conn)
|
|
1111
|
+
|
|
1112
|
+
if current_version >= DirIndexStore.SCHEMA_VERSION:
|
|
1113
|
+
already_migrated += 1
|
|
1114
|
+
if verbose:
|
|
1115
|
+
progress.console.print(f"[dim]Already migrated: {db_path.parent.name}[/dim]")
|
|
1116
|
+
elif current_version > 0:
|
|
1117
|
+
# Apply migrations
|
|
1118
|
+
store._apply_migrations(conn, current_version)
|
|
1119
|
+
store._set_schema_version(conn, DirIndexStore.SCHEMA_VERSION)
|
|
1120
|
+
conn.commit()
|
|
1121
|
+
migrated_count += 1
|
|
1122
|
+
if verbose:
|
|
1123
|
+
progress.console.print(f"[green]Migrated: {db_path.parent.name} (v{current_version} → v{DirIndexStore.SCHEMA_VERSION})[/green]")
|
|
1124
|
+
else:
|
|
1125
|
+
# New database, initialize directly
|
|
1126
|
+
store.initialize()
|
|
1127
|
+
migrated_count += 1
|
|
1128
|
+
|
|
1129
|
+
store.close()
|
|
1130
|
+
|
|
1131
|
+
except Exception as e:
|
|
1132
|
+
error_count += 1
|
|
1133
|
+
if verbose:
|
|
1134
|
+
progress.console.print(f"[red]Error migrating {db_path}: {e}[/red]")
|
|
1135
|
+
|
|
1136
|
+
progress.update(task, advance=1)
|
|
1137
|
+
|
|
1138
|
+
result = {
|
|
1139
|
+
"path": str(base_path),
|
|
1140
|
+
"total_indexes": len(index_files),
|
|
1141
|
+
"migrated": migrated_count,
|
|
1142
|
+
"already_migrated": already_migrated,
|
|
1143
|
+
"errors": error_count,
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
if json_mode:
|
|
1147
|
+
print_json(success=True, result=result)
|
|
1148
|
+
else:
|
|
1149
|
+
console.print(f"[green]Migration complete:[/green]")
|
|
1150
|
+
console.print(f" Total indexes: {len(index_files)}")
|
|
1151
|
+
console.print(f" Migrated: {migrated_count}")
|
|
1152
|
+
console.print(f" Already up-to-date: {already_migrated}")
|
|
1153
|
+
if error_count > 0:
|
|
1154
|
+
console.print(f" [yellow]Errors: {error_count}[/yellow]")
|
|
1155
|
+
|
|
1156
|
+
except StorageError as exc:
|
|
1157
|
+
if json_mode:
|
|
1158
|
+
print_json(success=False, error=f"Storage error: {exc}")
|
|
1159
|
+
else:
|
|
1160
|
+
console.print(f"[red]Migration failed (storage):[/red] {exc}")
|
|
1161
|
+
raise typer.Exit(code=1)
|
|
1162
|
+
except CodexLensError as exc:
|
|
1163
|
+
if json_mode:
|
|
1164
|
+
print_json(success=False, error=str(exc))
|
|
1165
|
+
else:
|
|
1166
|
+
console.print(f"[red]Migration failed:[/red] {exc}")
|
|
1167
|
+
raise typer.Exit(code=1)
|
|
1168
|
+
finally:
|
|
1169
|
+
if registry is not None:
|
|
1170
|
+
registry.close()
|
|
1171
|
+
|
|
1172
|
+
|
|
1173
|
+
@app.command()
|
|
1174
|
+
def clean(
|
|
1175
|
+
path: Optional[Path] = typer.Argument(None, help="Project path to clean (removes project index)."),
|
|
1176
|
+
all_indexes: bool = typer.Option(False, "--all", "-a", help="Remove all indexes."),
|
|
1177
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
1178
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
1179
|
+
) -> None:
|
|
1180
|
+
"""Remove CodexLens index data.
|
|
1181
|
+
|
|
1182
|
+
Without arguments, shows current index size.
|
|
1183
|
+
With path, removes that project's indexes.
|
|
1184
|
+
With --all, removes all indexes (use with caution).
|
|
1185
|
+
"""
|
|
1186
|
+
_configure_logging(verbose)
|
|
1187
|
+
|
|
1188
|
+
try:
|
|
1189
|
+
mapper = PathMapper()
|
|
1190
|
+
index_root = mapper.index_root
|
|
1191
|
+
|
|
1192
|
+
if all_indexes:
|
|
1193
|
+
# Remove everything
|
|
1194
|
+
if not index_root.exists():
|
|
1195
|
+
if json_mode:
|
|
1196
|
+
print_json(success=True, result={"cleaned": None, "message": "No indexes to clean"})
|
|
1197
|
+
else:
|
|
1198
|
+
console.print("[yellow]No indexes to clean.[/yellow]")
|
|
1199
|
+
return
|
|
1200
|
+
|
|
1201
|
+
# Calculate size before removal
|
|
1202
|
+
total_size = 0
|
|
1203
|
+
for f in index_root.rglob("*"):
|
|
1204
|
+
if f.is_file():
|
|
1205
|
+
total_size += f.stat().st_size
|
|
1206
|
+
|
|
1207
|
+
# Remove registry first
|
|
1208
|
+
registry_path = _get_registry_path()
|
|
1209
|
+
if registry_path.exists():
|
|
1210
|
+
registry_path.unlink()
|
|
1211
|
+
|
|
1212
|
+
# Remove all indexes
|
|
1213
|
+
shutil.rmtree(index_root)
|
|
1214
|
+
|
|
1215
|
+
result = {
|
|
1216
|
+
"cleaned": str(index_root),
|
|
1217
|
+
"size_freed_mb": round(total_size / (1024 * 1024), 2),
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
if json_mode:
|
|
1221
|
+
print_json(success=True, result=result)
|
|
1222
|
+
else:
|
|
1223
|
+
console.print(f"[green]Removed all indexes:[/green] {result['size_freed_mb']} MB freed")
|
|
1224
|
+
|
|
1225
|
+
elif path:
|
|
1226
|
+
# Remove specific project
|
|
1227
|
+
project_path = path.expanduser().resolve()
|
|
1228
|
+
project_index = mapper.source_to_index_dir(project_path)
|
|
1229
|
+
|
|
1230
|
+
if not project_index.exists():
|
|
1231
|
+
if json_mode:
|
|
1232
|
+
print_json(success=False, error=f"No index found for: {project_path}")
|
|
1233
|
+
else:
|
|
1234
|
+
console.print(f"[yellow]No index found for:[/yellow] {project_path}")
|
|
1235
|
+
return
|
|
1236
|
+
|
|
1237
|
+
# Calculate size
|
|
1238
|
+
total_size = 0
|
|
1239
|
+
for f in project_index.rglob("*"):
|
|
1240
|
+
if f.is_file():
|
|
1241
|
+
total_size += f.stat().st_size
|
|
1242
|
+
|
|
1243
|
+
# Remove from registry
|
|
1244
|
+
registry = RegistryStore()
|
|
1245
|
+
registry.initialize()
|
|
1246
|
+
registry.unregister_project(project_path)
|
|
1247
|
+
registry.close()
|
|
1248
|
+
|
|
1249
|
+
# Remove indexes
|
|
1250
|
+
shutil.rmtree(project_index)
|
|
1251
|
+
|
|
1252
|
+
result = {
|
|
1253
|
+
"cleaned": str(project_path),
|
|
1254
|
+
"index_path": str(project_index),
|
|
1255
|
+
"size_freed_mb": round(total_size / (1024 * 1024), 2),
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
if json_mode:
|
|
1259
|
+
print_json(success=True, result=result)
|
|
1260
|
+
else:
|
|
1261
|
+
console.print(f"[green]Removed indexes for:[/green] {project_path}")
|
|
1262
|
+
console.print(f" Freed: {result['size_freed_mb']} MB")
|
|
1263
|
+
|
|
1264
|
+
else:
|
|
1265
|
+
# Show current status
|
|
1266
|
+
if not index_root.exists():
|
|
1267
|
+
if json_mode:
|
|
1268
|
+
print_json(success=True, result={"index_root": str(index_root), "exists": False})
|
|
1269
|
+
else:
|
|
1270
|
+
console.print("[yellow]No indexes found.[/yellow]")
|
|
1271
|
+
return
|
|
1272
|
+
|
|
1273
|
+
total_size = 0
|
|
1274
|
+
for f in index_root.rglob("*"):
|
|
1275
|
+
if f.is_file():
|
|
1276
|
+
total_size += f.stat().st_size
|
|
1277
|
+
|
|
1278
|
+
registry = RegistryStore()
|
|
1279
|
+
registry.initialize()
|
|
1280
|
+
projects = registry.list_projects()
|
|
1281
|
+
registry.close()
|
|
1282
|
+
|
|
1283
|
+
result = {
|
|
1284
|
+
"index_root": str(index_root),
|
|
1285
|
+
"projects_count": len(projects),
|
|
1286
|
+
"total_size_mb": round(total_size / (1024 * 1024), 2),
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
if json_mode:
|
|
1290
|
+
print_json(success=True, result=result)
|
|
1291
|
+
else:
|
|
1292
|
+
console.print("[bold]Index Status[/bold]")
|
|
1293
|
+
console.print(f" Location: {result['index_root']}")
|
|
1294
|
+
console.print(f" Projects: {result['projects_count']}")
|
|
1295
|
+
console.print(f" Total Size: {result['total_size_mb']} MB")
|
|
1296
|
+
console.print("\n[dim]Use 'clean <path>' to remove a specific project or 'clean --all' to remove everything.[/dim]")
|
|
1297
|
+
|
|
1298
|
+
except StorageError as exc:
|
|
1299
|
+
if json_mode:
|
|
1300
|
+
print_json(success=False, error=f"Storage error: {exc}")
|
|
1301
|
+
else:
|
|
1302
|
+
console.print(f"[red]Clean failed (storage):[/red] {exc}")
|
|
1303
|
+
raise typer.Exit(code=1)
|
|
1304
|
+
except PermissionError as exc:
|
|
1305
|
+
if json_mode:
|
|
1306
|
+
print_json(success=False, error=f"Permission denied: {exc}")
|
|
1307
|
+
else:
|
|
1308
|
+
console.print(f"[red]Clean failed (permission denied):[/red] {exc}")
|
|
1309
|
+
raise typer.Exit(code=1)
|
|
1310
|
+
except CodexLensError as exc:
|
|
1311
|
+
if json_mode:
|
|
1312
|
+
print_json(success=False, error=str(exc))
|
|
1313
|
+
else:
|
|
1314
|
+
console.print(f"[red]Clean failed:[/red] {exc}")
|
|
1315
|
+
raise typer.Exit(code=1)
|
|
1316
|
+
|
|
1317
|
+
|
|
1318
|
+
@app.command("semantic-list")
|
|
1319
|
+
def semantic_list(
|
|
1320
|
+
path: Path = typer.Option(Path("."), "--path", "-p", help="Project path to list metadata from."),
|
|
1321
|
+
offset: int = typer.Option(0, "--offset", "-o", min=0, help="Number of records to skip."),
|
|
1322
|
+
limit: int = typer.Option(50, "--limit", "-n", min=1, max=100, help="Maximum records to return."),
|
|
1323
|
+
tool_filter: Optional[str] = typer.Option(None, "--tool", "-t", help="Filter by LLM tool (gemini/qwen)."),
|
|
1324
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
1325
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
1326
|
+
) -> None:
|
|
1327
|
+
"""List semantic metadata entries for indexed files.
|
|
1328
|
+
|
|
1329
|
+
Shows files that have LLM-generated summaries and keywords.
|
|
1330
|
+
Results are aggregated from all index databases in the project.
|
|
1331
|
+
"""
|
|
1332
|
+
_configure_logging(verbose)
|
|
1333
|
+
base_path = path.expanduser().resolve()
|
|
1334
|
+
|
|
1335
|
+
registry: Optional[RegistryStore] = None
|
|
1336
|
+
try:
|
|
1337
|
+
registry = RegistryStore()
|
|
1338
|
+
registry.initialize()
|
|
1339
|
+
mapper = PathMapper()
|
|
1340
|
+
|
|
1341
|
+
project_info = registry.get_project(base_path)
|
|
1342
|
+
if not project_info:
|
|
1343
|
+
raise CodexLensError(f"No index found for: {base_path}. Run 'codex-lens init' first.")
|
|
1344
|
+
|
|
1345
|
+
index_dir = Path(project_info.index_root)
|
|
1346
|
+
if not index_dir.exists():
|
|
1347
|
+
raise CodexLensError(f"Index directory not found: {index_dir}")
|
|
1348
|
+
|
|
1349
|
+
all_results: list = []
|
|
1350
|
+
total_count = 0
|
|
1351
|
+
|
|
1352
|
+
index_files = sorted(index_dir.rglob("_index.db"))
|
|
1353
|
+
|
|
1354
|
+
for db_path in index_files:
|
|
1355
|
+
try:
|
|
1356
|
+
store = DirIndexStore(db_path)
|
|
1357
|
+
store.initialize()
|
|
1358
|
+
|
|
1359
|
+
results, count = store.list_semantic_metadata(
|
|
1360
|
+
offset=0,
|
|
1361
|
+
limit=1000,
|
|
1362
|
+
llm_tool=tool_filter,
|
|
1363
|
+
)
|
|
1364
|
+
|
|
1365
|
+
source_dir = mapper.index_to_source(db_path.parent)
|
|
1366
|
+
for r in results:
|
|
1367
|
+
r["source_dir"] = str(source_dir)
|
|
1368
|
+
|
|
1369
|
+
all_results.extend(results)
|
|
1370
|
+
total_count += count
|
|
1371
|
+
|
|
1372
|
+
store.close()
|
|
1373
|
+
except Exception as e:
|
|
1374
|
+
if verbose:
|
|
1375
|
+
console.print(f"[yellow]Warning: Error reading {db_path}: {e}[/yellow]")
|
|
1376
|
+
|
|
1377
|
+
all_results.sort(key=lambda x: x["generated_at"], reverse=True)
|
|
1378
|
+
paginated = all_results[offset : offset + limit]
|
|
1379
|
+
|
|
1380
|
+
result = {
|
|
1381
|
+
"path": str(base_path),
|
|
1382
|
+
"total": total_count,
|
|
1383
|
+
"offset": offset,
|
|
1384
|
+
"limit": limit,
|
|
1385
|
+
"count": len(paginated),
|
|
1386
|
+
"entries": paginated,
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
if json_mode:
|
|
1390
|
+
print_json(success=True, result=result)
|
|
1391
|
+
else:
|
|
1392
|
+
if not paginated:
|
|
1393
|
+
console.print("[yellow]No semantic metadata found.[/yellow]")
|
|
1394
|
+
console.print("Run 'codex-lens enhance' to generate metadata for indexed files.")
|
|
1395
|
+
else:
|
|
1396
|
+
table = Table(title=f"Semantic Metadata ({total_count} total)")
|
|
1397
|
+
table.add_column("File", style="cyan", max_width=40)
|
|
1398
|
+
table.add_column("Language", style="dim")
|
|
1399
|
+
table.add_column("Purpose", max_width=30)
|
|
1400
|
+
table.add_column("Keywords", max_width=25)
|
|
1401
|
+
table.add_column("Tool")
|
|
1402
|
+
|
|
1403
|
+
for entry in paginated:
|
|
1404
|
+
keywords_str = ", ".join(entry["keywords"][:3])
|
|
1405
|
+
if len(entry["keywords"]) > 3:
|
|
1406
|
+
keywords_str += f" (+{len(entry['keywords']) - 3})"
|
|
1407
|
+
|
|
1408
|
+
table.add_row(
|
|
1409
|
+
entry["file_name"],
|
|
1410
|
+
entry["language"] or "-",
|
|
1411
|
+
(entry["purpose"] or "-")[:30],
|
|
1412
|
+
keywords_str or "-",
|
|
1413
|
+
entry["llm_tool"] or "-",
|
|
1414
|
+
)
|
|
1415
|
+
|
|
1416
|
+
console.print(table)
|
|
1417
|
+
|
|
1418
|
+
if total_count > len(paginated):
|
|
1419
|
+
console.print(
|
|
1420
|
+
f"[dim]Showing {offset + 1}-{offset + len(paginated)} of {total_count}. "
|
|
1421
|
+
"Use --offset and --limit for pagination.[/dim]"
|
|
1422
|
+
)
|
|
1423
|
+
|
|
1424
|
+
except StorageError as exc:
|
|
1425
|
+
if json_mode:
|
|
1426
|
+
print_json(success=False, error=f"Storage error: {exc}")
|
|
1427
|
+
else:
|
|
1428
|
+
console.print(f"[red]Semantic-list failed (storage):[/red] {exc}")
|
|
1429
|
+
raise typer.Exit(code=1)
|
|
1430
|
+
except CodexLensError as exc:
|
|
1431
|
+
if json_mode:
|
|
1432
|
+
print_json(success=False, error=str(exc))
|
|
1433
|
+
else:
|
|
1434
|
+
console.print(f"[red]Semantic-list failed:[/red] {exc}")
|
|
1435
|
+
raise typer.Exit(code=1)
|
|
1436
|
+
finally:
|
|
1437
|
+
if registry is not None:
|
|
1438
|
+
registry.close()
|
|
1439
|
+
|
|
1440
|
+
|
|
1441
|
+
# ==================== Model Management Commands ====================
|
|
1442
|
+
|
|
1443
|
+
@app.command(name="model-list")
|
|
1444
|
+
def model_list(
|
|
1445
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
1446
|
+
) -> None:
|
|
1447
|
+
"""List available embedding models and their installation status.
|
|
1448
|
+
|
|
1449
|
+
Shows 4 model profiles (fast, code, multilingual, balanced) with:
|
|
1450
|
+
- Installation status
|
|
1451
|
+
- Model size and dimensions
|
|
1452
|
+
- Use case recommendations
|
|
1453
|
+
"""
|
|
1454
|
+
try:
|
|
1455
|
+
from codexlens.cli.model_manager import list_models
|
|
1456
|
+
|
|
1457
|
+
result = list_models()
|
|
1458
|
+
|
|
1459
|
+
if json_mode:
|
|
1460
|
+
print_json(**result)
|
|
1461
|
+
else:
|
|
1462
|
+
if not result["success"]:
|
|
1463
|
+
console.print(f"[red]Error:[/red] {result.get('error', 'Unknown error')}")
|
|
1464
|
+
raise typer.Exit(code=1)
|
|
1465
|
+
|
|
1466
|
+
data = result["result"]
|
|
1467
|
+
models = data["models"]
|
|
1468
|
+
cache_dir = data["cache_dir"]
|
|
1469
|
+
cache_exists = data["cache_exists"]
|
|
1470
|
+
|
|
1471
|
+
console.print("[bold]Available Embedding Models:[/bold]")
|
|
1472
|
+
console.print(f"Cache directory: [dim]{cache_dir}[/dim] {'(exists)' if cache_exists else '(not found)'}\n")
|
|
1473
|
+
|
|
1474
|
+
table = Table(show_header=True, header_style="bold")
|
|
1475
|
+
table.add_column("Profile", style="cyan")
|
|
1476
|
+
table.add_column("Model Name", style="blue")
|
|
1477
|
+
table.add_column("Dims", justify="right")
|
|
1478
|
+
table.add_column("Size (MB)", justify="right")
|
|
1479
|
+
table.add_column("Status", justify="center")
|
|
1480
|
+
table.add_column("Use Case", style="dim")
|
|
1481
|
+
|
|
1482
|
+
for model in models:
|
|
1483
|
+
status_icon = "[green]✓[/green]" if model["installed"] else "[dim]—[/dim]"
|
|
1484
|
+
size_display = (
|
|
1485
|
+
f"{model['actual_size_mb']:.1f}" if model["installed"]
|
|
1486
|
+
else f"~{model['estimated_size_mb']}"
|
|
1487
|
+
)
|
|
1488
|
+
table.add_row(
|
|
1489
|
+
model["profile"],
|
|
1490
|
+
model["model_name"],
|
|
1491
|
+
str(model["dimensions"]),
|
|
1492
|
+
size_display,
|
|
1493
|
+
status_icon,
|
|
1494
|
+
model["use_case"][:40] + "..." if len(model["use_case"]) > 40 else model["use_case"],
|
|
1495
|
+
)
|
|
1496
|
+
|
|
1497
|
+
console.print(table)
|
|
1498
|
+
console.print("\n[dim]Use 'codexlens model-download <profile>' to download a model[/dim]")
|
|
1499
|
+
|
|
1500
|
+
except ImportError:
|
|
1501
|
+
if json_mode:
|
|
1502
|
+
print_json(success=False, error="fastembed not installed. Install with: pip install codexlens[semantic]")
|
|
1503
|
+
else:
|
|
1504
|
+
console.print("[red]Error:[/red] fastembed not installed")
|
|
1505
|
+
console.print("[yellow]Install with:[/yellow] pip install codexlens[semantic]")
|
|
1506
|
+
raise typer.Exit(code=1)
|
|
1507
|
+
|
|
1508
|
+
|
|
1509
|
+
@app.command(name="model-download")
|
|
1510
|
+
def model_download(
|
|
1511
|
+
profile: str = typer.Argument(..., help="Model profile to download (fast, code, multilingual, balanced)."),
|
|
1512
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
1513
|
+
) -> None:
|
|
1514
|
+
"""Download an embedding model by profile name.
|
|
1515
|
+
|
|
1516
|
+
Example:
|
|
1517
|
+
codexlens model-download code # Download code-optimized model
|
|
1518
|
+
"""
|
|
1519
|
+
try:
|
|
1520
|
+
from codexlens.cli.model_manager import download_model
|
|
1521
|
+
|
|
1522
|
+
if not json_mode:
|
|
1523
|
+
console.print(f"[bold]Downloading model:[/bold] {profile}")
|
|
1524
|
+
console.print("[dim]This may take a few minutes depending on your internet connection...[/dim]\n")
|
|
1525
|
+
|
|
1526
|
+
# Create progress callback for non-JSON mode
|
|
1527
|
+
progress_callback = None if json_mode else lambda msg: console.print(f"[cyan]{msg}[/cyan]")
|
|
1528
|
+
|
|
1529
|
+
result = download_model(profile, progress_callback=progress_callback)
|
|
1530
|
+
|
|
1531
|
+
if json_mode:
|
|
1532
|
+
print_json(**result)
|
|
1533
|
+
else:
|
|
1534
|
+
if not result["success"]:
|
|
1535
|
+
console.print(f"[red]Error:[/red] {result.get('error', 'Unknown error')}")
|
|
1536
|
+
raise typer.Exit(code=1)
|
|
1537
|
+
|
|
1538
|
+
data = result["result"]
|
|
1539
|
+
console.print(f"[green]✓[/green] Model downloaded successfully!")
|
|
1540
|
+
console.print(f" Profile: {data['profile']}")
|
|
1541
|
+
console.print(f" Model: {data['model_name']}")
|
|
1542
|
+
console.print(f" Cache size: {data['cache_size_mb']:.1f} MB")
|
|
1543
|
+
console.print(f" Location: [dim]{data['cache_path']}[/dim]")
|
|
1544
|
+
|
|
1545
|
+
except ImportError:
|
|
1546
|
+
if json_mode:
|
|
1547
|
+
print_json(success=False, error="fastembed not installed. Install with: pip install codexlens[semantic]")
|
|
1548
|
+
else:
|
|
1549
|
+
console.print("[red]Error:[/red] fastembed not installed")
|
|
1550
|
+
console.print("[yellow]Install with:[/yellow] pip install codexlens[semantic]")
|
|
1551
|
+
raise typer.Exit(code=1)
|
|
1552
|
+
|
|
1553
|
+
|
|
1554
|
+
@app.command(name="model-delete")
|
|
1555
|
+
def model_delete(
|
|
1556
|
+
profile: str = typer.Argument(..., help="Model profile to delete (fast, code, multilingual, balanced)."),
|
|
1557
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
1558
|
+
) -> None:
|
|
1559
|
+
"""Delete a downloaded embedding model from cache.
|
|
1560
|
+
|
|
1561
|
+
Example:
|
|
1562
|
+
codexlens model-delete fast # Delete fast model
|
|
1563
|
+
"""
|
|
1564
|
+
from codexlens.cli.model_manager import delete_model
|
|
1565
|
+
|
|
1566
|
+
if not json_mode:
|
|
1567
|
+
console.print(f"[bold yellow]Deleting model:[/bold yellow] {profile}")
|
|
1568
|
+
|
|
1569
|
+
result = delete_model(profile)
|
|
1570
|
+
|
|
1571
|
+
if json_mode:
|
|
1572
|
+
print_json(**result)
|
|
1573
|
+
else:
|
|
1574
|
+
if not result["success"]:
|
|
1575
|
+
console.print(f"[red]Error:[/red] {result.get('error', 'Unknown error')}")
|
|
1576
|
+
raise typer.Exit(code=1)
|
|
1577
|
+
|
|
1578
|
+
data = result["result"]
|
|
1579
|
+
console.print(f"[green]✓[/green] Model deleted successfully!")
|
|
1580
|
+
console.print(f" Profile: {data['profile']}")
|
|
1581
|
+
console.print(f" Model: {data['model_name']}")
|
|
1582
|
+
console.print(f" Freed space: {data['deleted_size_mb']:.1f} MB")
|
|
1583
|
+
|
|
1584
|
+
|
|
1585
|
+
@app.command(name="model-info")
|
|
1586
|
+
def model_info(
|
|
1587
|
+
profile: str = typer.Argument(..., help="Model profile to get info (fast, code, multilingual, balanced)."),
|
|
1588
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
1589
|
+
) -> None:
|
|
1590
|
+
"""Get detailed information about a model profile.
|
|
1591
|
+
|
|
1592
|
+
Example:
|
|
1593
|
+
codexlens model-info code # Get code model details
|
|
1594
|
+
"""
|
|
1595
|
+
from codexlens.cli.model_manager import get_model_info
|
|
1596
|
+
|
|
1597
|
+
result = get_model_info(profile)
|
|
1598
|
+
|
|
1599
|
+
if json_mode:
|
|
1600
|
+
print_json(**result)
|
|
1601
|
+
else:
|
|
1602
|
+
if not result["success"]:
|
|
1603
|
+
console.print(f"[red]Error:[/red] {result.get('error', 'Unknown error')}")
|
|
1604
|
+
raise typer.Exit(code=1)
|
|
1605
|
+
|
|
1606
|
+
data = result["result"]
|
|
1607
|
+
console.print(f"[bold]Model Profile:[/bold] {data['profile']}")
|
|
1608
|
+
console.print(f" Model name: {data['model_name']}")
|
|
1609
|
+
console.print(f" Dimensions: {data['dimensions']}")
|
|
1610
|
+
console.print(f" Status: {'[green]Installed[/green]' if data['installed'] else '[dim]Not installed[/dim]'}")
|
|
1611
|
+
if data['installed'] and data['actual_size_mb']:
|
|
1612
|
+
console.print(f" Cache size: {data['actual_size_mb']:.1f} MB")
|
|
1613
|
+
console.print(f" Location: [dim]{data['cache_path']}[/dim]")
|
|
1614
|
+
else:
|
|
1615
|
+
console.print(f" Estimated size: ~{data['estimated_size_mb']} MB")
|
|
1616
|
+
console.print(f"\n Description: {data['description']}")
|
|
1617
|
+
console.print(f" Use case: {data['use_case']}")
|
|
1618
|
+
|
|
1619
|
+
|
|
1620
|
+
# ==================== Embedding Management Commands ====================
|
|
1621
|
+
|
|
1622
|
+
@app.command(name="embeddings-status")
|
|
1623
|
+
def embeddings_status(
|
|
1624
|
+
path: Optional[Path] = typer.Argument(
|
|
1625
|
+
None,
|
|
1626
|
+
exists=True,
|
|
1627
|
+
help="Path to specific _index.db file or directory containing indexes. If not specified, uses default index root.",
|
|
1628
|
+
),
|
|
1629
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
1630
|
+
) -> None:
|
|
1631
|
+
"""Check embedding status for one or all indexes.
|
|
1632
|
+
|
|
1633
|
+
Shows embedding statistics including:
|
|
1634
|
+
- Number of chunks generated
|
|
1635
|
+
- File coverage percentage
|
|
1636
|
+
- Files missing embeddings
|
|
1637
|
+
|
|
1638
|
+
Examples:
|
|
1639
|
+
codexlens embeddings-status # Check all indexes
|
|
1640
|
+
codexlens embeddings-status ~/.codexlens/indexes/project/_index.db # Check specific index
|
|
1641
|
+
codexlens embeddings-status ~/projects/my-app # Check project (auto-finds index)
|
|
1642
|
+
"""
|
|
1643
|
+
from codexlens.cli.embedding_manager import check_index_embeddings, get_embedding_stats_summary
|
|
1644
|
+
|
|
1645
|
+
# Determine what to check
|
|
1646
|
+
if path is None:
|
|
1647
|
+
# Check all indexes in default root
|
|
1648
|
+
index_root = _get_index_root()
|
|
1649
|
+
result = get_embedding_stats_summary(index_root)
|
|
1650
|
+
|
|
1651
|
+
if json_mode:
|
|
1652
|
+
print_json(**result)
|
|
1653
|
+
else:
|
|
1654
|
+
if not result["success"]:
|
|
1655
|
+
console.print(f"[red]Error:[/red] {result.get('error', 'Unknown error')}")
|
|
1656
|
+
raise typer.Exit(code=1)
|
|
1657
|
+
|
|
1658
|
+
data = result["result"]
|
|
1659
|
+
total = data["total_indexes"]
|
|
1660
|
+
with_emb = data["indexes_with_embeddings"]
|
|
1661
|
+
total_chunks = data["total_chunks"]
|
|
1662
|
+
|
|
1663
|
+
console.print(f"[bold]Embedding Status Summary[/bold]")
|
|
1664
|
+
console.print(f"Index root: [dim]{index_root}[/dim]\n")
|
|
1665
|
+
console.print(f"Total indexes: {total}")
|
|
1666
|
+
console.print(f"Indexes with embeddings: [{'green' if with_emb > 0 else 'yellow'}]{with_emb}[/]/{total}")
|
|
1667
|
+
console.print(f"Total chunks: {total_chunks:,}\n")
|
|
1668
|
+
|
|
1669
|
+
if data["indexes"]:
|
|
1670
|
+
table = Table(show_header=True, header_style="bold")
|
|
1671
|
+
table.add_column("Project", style="cyan")
|
|
1672
|
+
table.add_column("Files", justify="right")
|
|
1673
|
+
table.add_column("Chunks", justify="right")
|
|
1674
|
+
table.add_column("Coverage", justify="right")
|
|
1675
|
+
table.add_column("Status", justify="center")
|
|
1676
|
+
|
|
1677
|
+
for idx_stat in data["indexes"]:
|
|
1678
|
+
status_icon = "[green]✓[/green]" if idx_stat["has_embeddings"] else "[dim]—[/dim]"
|
|
1679
|
+
coverage = f"{idx_stat['coverage_percent']:.1f}%" if idx_stat["has_embeddings"] else "—"
|
|
1680
|
+
|
|
1681
|
+
table.add_row(
|
|
1682
|
+
idx_stat["project"],
|
|
1683
|
+
str(idx_stat["total_files"]),
|
|
1684
|
+
f"{idx_stat['total_chunks']:,}" if idx_stat["has_embeddings"] else "0",
|
|
1685
|
+
coverage,
|
|
1686
|
+
status_icon,
|
|
1687
|
+
)
|
|
1688
|
+
|
|
1689
|
+
console.print(table)
|
|
1690
|
+
|
|
1691
|
+
else:
|
|
1692
|
+
# Check specific index or find index for project
|
|
1693
|
+
target_path = path.expanduser().resolve()
|
|
1694
|
+
|
|
1695
|
+
if target_path.is_file() and target_path.name == "_index.db":
|
|
1696
|
+
# Direct index file
|
|
1697
|
+
index_path = target_path
|
|
1698
|
+
elif target_path.is_dir():
|
|
1699
|
+
# Try to find index for this project
|
|
1700
|
+
registry = RegistryStore()
|
|
1701
|
+
try:
|
|
1702
|
+
registry.initialize()
|
|
1703
|
+
mapper = PathMapper()
|
|
1704
|
+
index_path = mapper.source_to_index_db(target_path)
|
|
1705
|
+
|
|
1706
|
+
if not index_path.exists():
|
|
1707
|
+
console.print(f"[red]Error:[/red] No index found for {target_path}")
|
|
1708
|
+
console.print("Run 'codexlens init' first to create an index")
|
|
1709
|
+
raise typer.Exit(code=1)
|
|
1710
|
+
finally:
|
|
1711
|
+
registry.close()
|
|
1712
|
+
else:
|
|
1713
|
+
console.print(f"[red]Error:[/red] Path must be _index.db file or directory")
|
|
1714
|
+
raise typer.Exit(code=1)
|
|
1715
|
+
|
|
1716
|
+
result = check_index_embeddings(index_path)
|
|
1717
|
+
|
|
1718
|
+
if json_mode:
|
|
1719
|
+
print_json(**result)
|
|
1720
|
+
else:
|
|
1721
|
+
if not result["success"]:
|
|
1722
|
+
console.print(f"[red]Error:[/red] {result.get('error', 'Unknown error')}")
|
|
1723
|
+
raise typer.Exit(code=1)
|
|
1724
|
+
|
|
1725
|
+
data = result["result"]
|
|
1726
|
+
has_emb = data["has_embeddings"]
|
|
1727
|
+
|
|
1728
|
+
console.print(f"[bold]Embedding Status[/bold]")
|
|
1729
|
+
console.print(f"Index: [dim]{data['index_path']}[/dim]\n")
|
|
1730
|
+
|
|
1731
|
+
if has_emb:
|
|
1732
|
+
console.print(f"[green]✓[/green] Embeddings available")
|
|
1733
|
+
console.print(f" Total chunks: {data['total_chunks']:,}")
|
|
1734
|
+
console.print(f" Total files: {data['total_files']:,}")
|
|
1735
|
+
console.print(f" Files with embeddings: {data['files_with_chunks']:,}/{data['total_files']}")
|
|
1736
|
+
console.print(f" Coverage: {data['coverage_percent']:.1f}%")
|
|
1737
|
+
|
|
1738
|
+
if data["files_without_chunks"] > 0:
|
|
1739
|
+
console.print(f"\n[yellow]Warning:[/yellow] {data['files_without_chunks']} files missing embeddings")
|
|
1740
|
+
if data["missing_files_sample"]:
|
|
1741
|
+
console.print(" Sample missing files:")
|
|
1742
|
+
for file in data["missing_files_sample"]:
|
|
1743
|
+
console.print(f" [dim]{file}[/dim]")
|
|
1744
|
+
else:
|
|
1745
|
+
console.print(f"[yellow]—[/yellow] No embeddings found")
|
|
1746
|
+
console.print(f" Total files indexed: {data['total_files']:,}")
|
|
1747
|
+
console.print("\n[dim]Generate embeddings with:[/dim]")
|
|
1748
|
+
console.print(f" [cyan]codexlens embeddings-generate {index_path}[/cyan]")
|
|
1749
|
+
|
|
1750
|
+
|
|
1751
|
+
@app.command(name="embeddings-generate")
|
|
1752
|
+
def embeddings_generate(
|
|
1753
|
+
path: Path = typer.Argument(
|
|
1754
|
+
...,
|
|
1755
|
+
exists=True,
|
|
1756
|
+
help="Path to _index.db file or project directory.",
|
|
1757
|
+
),
|
|
1758
|
+
model: str = typer.Option(
|
|
1759
|
+
"code",
|
|
1760
|
+
"--model",
|
|
1761
|
+
"-m",
|
|
1762
|
+
help="Model profile: fast, code, multilingual, balanced.",
|
|
1763
|
+
),
|
|
1764
|
+
force: bool = typer.Option(
|
|
1765
|
+
False,
|
|
1766
|
+
"--force",
|
|
1767
|
+
"-f",
|
|
1768
|
+
help="Force regeneration even if embeddings exist.",
|
|
1769
|
+
),
|
|
1770
|
+
chunk_size: int = typer.Option(
|
|
1771
|
+
2000,
|
|
1772
|
+
"--chunk-size",
|
|
1773
|
+
help="Maximum chunk size in characters.",
|
|
1774
|
+
),
|
|
1775
|
+
recursive: bool = typer.Option(
|
|
1776
|
+
False,
|
|
1777
|
+
"--recursive",
|
|
1778
|
+
"-r",
|
|
1779
|
+
help="Recursively process all _index.db files in directory tree.",
|
|
1780
|
+
),
|
|
1781
|
+
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
|
|
1782
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose output."),
|
|
1783
|
+
) -> None:
|
|
1784
|
+
"""Generate semantic embeddings for code search.
|
|
1785
|
+
|
|
1786
|
+
Creates vector embeddings for all files in an index to enable
|
|
1787
|
+
semantic search capabilities. Embeddings are stored in the same
|
|
1788
|
+
database as the FTS index.
|
|
1789
|
+
|
|
1790
|
+
Model Profiles:
|
|
1791
|
+
- fast: BAAI/bge-small-en-v1.5 (384 dims, ~80MB)
|
|
1792
|
+
- code: jinaai/jina-embeddings-v2-base-code (768 dims, ~150MB) [recommended]
|
|
1793
|
+
- multilingual: intfloat/multilingual-e5-large (1024 dims, ~1GB)
|
|
1794
|
+
- balanced: mixedbread-ai/mxbai-embed-large-v1 (1024 dims, ~600MB)
|
|
1795
|
+
|
|
1796
|
+
Examples:
|
|
1797
|
+
codexlens embeddings-generate ~/projects/my-app # Auto-find index for project
|
|
1798
|
+
codexlens embeddings-generate ~/.codexlens/indexes/project/_index.db # Specific index
|
|
1799
|
+
codexlens embeddings-generate ~/projects/my-app --model fast --force # Regenerate with fast model
|
|
1800
|
+
"""
|
|
1801
|
+
_configure_logging(verbose)
|
|
1802
|
+
|
|
1803
|
+
from codexlens.cli.embedding_manager import generate_embeddings, generate_embeddings_recursive
|
|
1804
|
+
|
|
1805
|
+
# Resolve path
|
|
1806
|
+
target_path = path.expanduser().resolve()
|
|
1807
|
+
|
|
1808
|
+
# Determine if we should use recursive mode
|
|
1809
|
+
use_recursive = False
|
|
1810
|
+
index_path = None
|
|
1811
|
+
index_root = None
|
|
1812
|
+
|
|
1813
|
+
if target_path.is_file() and target_path.name == "_index.db":
|
|
1814
|
+
# Direct index file
|
|
1815
|
+
index_path = target_path
|
|
1816
|
+
if recursive:
|
|
1817
|
+
# Use parent directory for recursive processing
|
|
1818
|
+
use_recursive = True
|
|
1819
|
+
index_root = target_path.parent
|
|
1820
|
+
elif target_path.is_dir():
|
|
1821
|
+
if recursive:
|
|
1822
|
+
# Recursive mode: process all _index.db files in directory tree
|
|
1823
|
+
use_recursive = True
|
|
1824
|
+
index_root = target_path
|
|
1825
|
+
else:
|
|
1826
|
+
# Non-recursive: Try to find index for this project
|
|
1827
|
+
registry = RegistryStore()
|
|
1828
|
+
try:
|
|
1829
|
+
registry.initialize()
|
|
1830
|
+
mapper = PathMapper()
|
|
1831
|
+
index_path = mapper.source_to_index_db(target_path)
|
|
1832
|
+
|
|
1833
|
+
if not index_path.exists():
|
|
1834
|
+
console.print(f"[red]Error:[/red] No index found for {target_path}")
|
|
1835
|
+
console.print("Run 'codexlens init' first to create an index")
|
|
1836
|
+
raise typer.Exit(code=1)
|
|
1837
|
+
finally:
|
|
1838
|
+
registry.close()
|
|
1839
|
+
else:
|
|
1840
|
+
console.print(f"[red]Error:[/red] Path must be _index.db file or directory")
|
|
1841
|
+
raise typer.Exit(code=1)
|
|
1842
|
+
|
|
1843
|
+
# Progress callback
|
|
1844
|
+
def progress_update(msg: str):
|
|
1845
|
+
if not json_mode and verbose:
|
|
1846
|
+
console.print(f" {msg}")
|
|
1847
|
+
|
|
1848
|
+
console.print(f"[bold]Generating embeddings[/bold]")
|
|
1849
|
+
if use_recursive:
|
|
1850
|
+
console.print(f"Index root: [dim]{index_root}[/dim]")
|
|
1851
|
+
console.print(f"Mode: [yellow]Recursive[/yellow]")
|
|
1852
|
+
else:
|
|
1853
|
+
console.print(f"Index: [dim]{index_path}[/dim]")
|
|
1854
|
+
console.print(f"Model: [cyan]{model}[/cyan]\n")
|
|
1855
|
+
|
|
1856
|
+
if use_recursive:
|
|
1857
|
+
result = generate_embeddings_recursive(
|
|
1858
|
+
index_root,
|
|
1859
|
+
model_profile=model,
|
|
1860
|
+
force=force,
|
|
1861
|
+
chunk_size=chunk_size,
|
|
1862
|
+
progress_callback=progress_update,
|
|
1863
|
+
)
|
|
1864
|
+
else:
|
|
1865
|
+
result = generate_embeddings(
|
|
1866
|
+
index_path,
|
|
1867
|
+
model_profile=model,
|
|
1868
|
+
force=force,
|
|
1869
|
+
chunk_size=chunk_size,
|
|
1870
|
+
progress_callback=progress_update,
|
|
1871
|
+
)
|
|
1872
|
+
|
|
1873
|
+
if json_mode:
|
|
1874
|
+
print_json(**result)
|
|
1875
|
+
else:
|
|
1876
|
+
if not result["success"]:
|
|
1877
|
+
error_msg = result.get("error", "Unknown error")
|
|
1878
|
+
console.print(f"[red]Error:[/red] {error_msg}")
|
|
1879
|
+
|
|
1880
|
+
# Provide helpful hints
|
|
1881
|
+
if "already has" in error_msg:
|
|
1882
|
+
console.print("\n[dim]Use --force to regenerate existing embeddings[/dim]")
|
|
1883
|
+
elif "Semantic search not available" in error_msg:
|
|
1884
|
+
console.print("\n[dim]Install semantic dependencies:[/dim]")
|
|
1885
|
+
console.print(" [cyan]pip install codexlens[semantic][/cyan]")
|
|
1886
|
+
|
|
1887
|
+
raise typer.Exit(code=1)
|
|
1888
|
+
|
|
1889
|
+
data = result["result"]
|
|
1890
|
+
|
|
1891
|
+
if use_recursive:
|
|
1892
|
+
# Recursive mode output
|
|
1893
|
+
console.print(f"[green]✓[/green] Recursive embeddings generation complete!")
|
|
1894
|
+
console.print(f" Indexes processed: {data['indexes_processed']}")
|
|
1895
|
+
console.print(f" Indexes successful: {data['indexes_successful']}")
|
|
1896
|
+
if data['indexes_failed'] > 0:
|
|
1897
|
+
console.print(f" [yellow]Indexes failed: {data['indexes_failed']}[/yellow]")
|
|
1898
|
+
console.print(f" Total chunks created: {data['total_chunks_created']:,}")
|
|
1899
|
+
console.print(f" Total files processed: {data['total_files_processed']}")
|
|
1900
|
+
if data['total_files_failed'] > 0:
|
|
1901
|
+
console.print(f" [yellow]Total files failed: {data['total_files_failed']}[/yellow]")
|
|
1902
|
+
console.print(f" Model profile: {data['model_profile']}")
|
|
1903
|
+
|
|
1904
|
+
# Show details if verbose
|
|
1905
|
+
if verbose and data.get('details'):
|
|
1906
|
+
console.print("\n[dim]Index details:[/dim]")
|
|
1907
|
+
for detail in data['details']:
|
|
1908
|
+
status_icon = "[green]✓[/green]" if detail['success'] else "[red]✗[/red]"
|
|
1909
|
+
console.print(f" {status_icon} {detail['path']}")
|
|
1910
|
+
if not detail['success'] and detail.get('error'):
|
|
1911
|
+
console.print(f" [dim]Error: {detail['error']}[/dim]")
|
|
1912
|
+
else:
|
|
1913
|
+
# Single index mode output
|
|
1914
|
+
elapsed = data["elapsed_time"]
|
|
1915
|
+
|
|
1916
|
+
console.print(f"[green]✓[/green] Embeddings generated successfully!")
|
|
1917
|
+
console.print(f" Model: {data['model_name']}")
|
|
1918
|
+
console.print(f" Chunks created: {data['chunks_created']:,}")
|
|
1919
|
+
console.print(f" Files processed: {data['files_processed']}")
|
|
1920
|
+
|
|
1921
|
+
if data["files_failed"] > 0:
|
|
1922
|
+
console.print(f" [yellow]Files failed: {data['files_failed']}[/yellow]")
|
|
1923
|
+
if data["failed_files"]:
|
|
1924
|
+
console.print(" [dim]First failures:[/dim]")
|
|
1925
|
+
for file_path, error in data["failed_files"]:
|
|
1926
|
+
console.print(f" [dim]{file_path}: {error}[/dim]")
|
|
1927
|
+
|
|
1928
|
+
console.print(f" Time: {elapsed:.1f}s")
|
|
1929
|
+
|
|
1930
|
+
console.print("\n[dim]Use vector search with:[/dim]")
|
|
1931
|
+
console.print(" [cyan]codexlens search 'your query' --mode pure-vector[/cyan]")
|