ai-codeindex 0.26.0__tar.gz → 0.26.2__tar.gz
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.
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.gitignore +1 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/CHANGELOG.md +28 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/PKG-INFO +2 -2
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/README.md +1 -1
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/planning/ROADMAP.md +2 -2
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/pyproject.toml +1 -1
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/README_AI.md +11 -11
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_hooks.py +54 -2
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_scan.py +68 -10
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/enricher.py +81 -3
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/init_wizard.py +16 -3
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/README_AI.md +2 -2
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_hooks.py +116 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_enricher.py +127 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_enricher_integration.py +30 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_detection.py +65 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.editorconfig +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/ISSUE_TEMPLATE/bug.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/ISSUE_TEMPLATE/enhancement.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/ISSUE_TEMPLATE/epic.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/ISSUE_TEMPLATE/feature.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/workflows/ci.yml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/workflows/publish.yml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/.gitignore +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/memories/design_philosophy.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/memories/development_workflow.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/memories/project_overview.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/memories/release_automation.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/memories/suggested_commands.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/CLAUDE.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/CODE_OF_CONDUCT.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/CONTRIBUTING.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/FOR_LOOMGRAPH.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/LICENSE +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/Makefile +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/PROJECT_SYMBOLS.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/README_zh.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/SECURITY.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/.gitignore +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/Makefile +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/grade.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/questions.yaml.example +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/report.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/run_bench.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/targets.yaml.example +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/001-use-tree-sitter-for-parsing.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/002-external-ai-cli-integration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/003-add-swift-objc-support.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/004-automatic-claude-md-update.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/005-navigation-disclaimer-and-readme-size-cap.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/006-distribution-architecture-split.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/design/document-aggregation.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/design/initial-design.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/design/kiss-universal-description.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/design/parallel-strategy.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/design-philosophy.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/benchmark/2026-05-readme-impact.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/QUICK_START_RELEASE.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/claude-code-adoption-guide.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/claude-code-adoption-guide.zh.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/gitflow-workflow.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/github-issue-quick-reference.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/package-naming.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/pre-release-checklist.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/setup.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/team-workflow-guide.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/test-architecture.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/evaluation/before-after/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/evaluation/case-studies/php-payment-project.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/evaluation/loomgraph-efficiency-comparison.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/advanced-usage.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/claude-code-integration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/configuration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/contributing.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/getting-started.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/git-hooks-integration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/json-output-integration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/loomgraph-integration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/planning/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/planning/executive-summary.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.10.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.12.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.12.1.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.14.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.15.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.17.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.17.2.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.17.3.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.18.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.19.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.2.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.20.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.23.1.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.23.2.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.24.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.25.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.3.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.3.1.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.3.2.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.4.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.5.0-beta1.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.7.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.8.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.9.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/CLAUDE.md.php-project +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/CLAUDE.md.template +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/ai-integration-guide.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/frameworks/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/frameworks/template/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/frameworks/template/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/frameworks/template/test_template_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/frameworks/template/yourframework_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/loomgraph_output.json +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/loomgraph_php_output.json +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/loomgraph_sample.php +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/loomgraph_sample.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/parse_integration_example.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/print_env.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/hooks/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/hooks/templates/post-commit-update-logic.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/hooks/templates/post-commit-v4 +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/swift-objc-support-analysis.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/swift-poc-summary.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/tech-debt-codeindex-v2.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/tech-debt-codeindex.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/tech-debt-loomgraph-v2.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/tech-debt-loomgraph.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/workflow-comparison.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/bump_version.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/check_docs_release.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/check_version_consistency.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/close-epic9-issues.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/diagnose_ai_failures.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/hooks/hook-common.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/hooks/pre-push +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/legacy/PROJECT_INDEX.json +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/legacy/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/legacy/hierarchical_strategy.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/pre_release_check.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/release.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/test_hook_e2e.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/validate_php_project.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/skills/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/skills/create.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/skills/install.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/skills/src/mo-arch/SKILL.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/skills/src/mo-index/SKILL.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/adaptive_config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/adaptive_selector.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/ai_helper.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/claude_md.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_claude_md.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_common.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_config_commands.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_docs.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_parse.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_tech_debt.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/config_help.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/directory_tree.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/docstring_processor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/doctor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/errors.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/extractors/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/extractors/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/extractors/spring.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/extractors/thinkphp.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/file_classifier.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/framework_detect.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/hierarchical.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/hooks.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/incremental.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/invoker.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/objc_association.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parallel.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parser.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/base.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java_parser.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/utils.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/route_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/route_registry.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/scanner.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/semantic_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/skill_helpers.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/smart_writer.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/symbol_index.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/symbol_scorer.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/tech_debt.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/tech_debt_formatters.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/templates/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/templates/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/templates/claude_md_core.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/test_smells.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writer.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/core.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/detailed_generator.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/navigation_generator.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/overview_generator.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/utils.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/generator.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/scripts/analyze_legacy_tests.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/scripts/compare_coverage.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/scripts/compare_test_results.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/specs/java.yaml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/specs/php.yaml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/specs/python.yaml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/templates/inheritance_test.py.j2 +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/conftest.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/extractors/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/extractors/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/extractors/test_spring.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/extractors/test_thinkphp.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/extractors/test_thinkphp_description.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/cli_scan_defaults.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/help_system.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/init_wizard.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/symbol_overload_detection.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/tech_debt_detection.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/tech_debt_reporting.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/Controller.php +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/Service.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/Simple.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/broken.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/complete.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/service.ts +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/simple.php +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/simple.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/unsupported.txt +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/enum.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/generics.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/imports.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/interface.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/record.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/sealed_class.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/simple_class.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring/Application.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring/User.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring/UserController.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring/UserRepository.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring/UserService.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring_controller.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/typescript/app.js +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/typescript/component.tsx +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/typescript/service.ts +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/test_hierarchical_test/level1/file1.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/test_hierarchical_test/level1/level2a/file2.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/test_hierarchical_test/level1/level2a/level3/file4.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/test_hierarchical_test/level1/level2b/file3.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/test_hierarchy_simple.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_adaptive_config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_adaptive_selector.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_ai_helper.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_backward_compatibility.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_call_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_claude_md.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_claude_md_injection.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_config_gitignore.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_debt_scan.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_docstring_options.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_json.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_parse.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_scan_defaults_bdd.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_tech_debt.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_config_adaptive.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_dataclass_structure.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_directory_tree.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_docstring_config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_docstring_processor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_doctor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_error_handling.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_file_classifier.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_help_system_bdd.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_hook_post_commit.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_hooks.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_hooks_config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_hooks_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_init_minimal_scope.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_init_wizard_bdd.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_integration_swift_objc.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_annotations.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_edge_cases.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_error_recovery.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_generic_bounds.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_lambda.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_lombok.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_module.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_parser.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_spring.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_throws.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_json_output.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_lazy_loading.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_list_dirs_diagnostic.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_loomgraph_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_objc_association_utils.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parallel_scan.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_objc_association.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_objc_basic.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_objc_bridging.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_objc_categories.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_docstrings.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_extensions.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_generics.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_poc.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_properties.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_property_wrappers.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_protocols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_signatures.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_comment_extraction.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_docstring_extraction.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_import_alias.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_loomgraph_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_project_index_semantic.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_python_calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_python_docstring_description.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_python_import_alias.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_python_inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_route_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_route_info.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_route_registry.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_route_table_description.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_route_table_display.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_scanall_auto_ai.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_scanner_passthrough.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_semantic_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_skill_helpers.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer_adaptive.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer_docstring.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer_enriched.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer_semantic.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_story_4_4_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_symbol_overload.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_symbol_scorer.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_bdd.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_detector.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_formatters.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_ios.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_java.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_reporter.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_test_smells.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_thinkphp_route_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_typescript_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_typescript_parser.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_windows_path_optimization.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_writer_preserves_enrichment.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/writers/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/writers/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/writers/test_generators.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/writers/test_utils.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/uv.lock +0 -0
|
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.26.2] - 2026-06-22
|
|
11
|
+
|
|
12
|
+
**Theme**: enrichment-quality patch. `scan-all --ai` was silently writing punt
|
|
13
|
+
text ("I need the file names") as the directory description for leaf dirs and
|
|
14
|
+
caching it as `enrichment: ok`. A/B on a real TS monorepo: 23/50 punts → 0/50.
|
|
15
|
+
No contract change.
|
|
16
|
+
|
|
17
|
+
> **Upgrade note**: existing `README_AI.md` files enriched by ≤0.26.1 may carry
|
|
18
|
+
> poisoned descriptions stamped `enrichment: ok`, which the cache will not
|
|
19
|
+
> refresh on its own. After upgrading, run **`codeindex scan-all --ai --retry-all`**
|
|
20
|
+
> once to flush and regenerate them.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **`scan-all --ai` enrichment now feeds each directory its OWN files/symbols, fixing leaf-dir punts** (GH #94): `_enrich_directories_with_ai` built the prompt from `build_safe_subdir_context(child_dirs)` — child *directory* names only — while `build_enrich_prompt` instructed the model "based ONLY on the file names and symbol names above." A leaf dir's content is *files*, not subdirs, so the prompt carried nothing to describe; worse, a single uninformative child like `__tests__` made the subdir context non-empty and short-circuited the README fallback. On a TypeScript monorepo this hit 21/50 enriched dirs (`controllers`, `services`, `routes`, `screens`, `pages` — all the leaf code dirs), and the model correctly punted ("I need the file names and symbol names"). New `cli_scan._build_enrich_summary` re-parses the directory's own files **non-recursively** (`scan_directory(recursive=False)` — no subtree leak) and runs them through the existing `extract_symbol_summary`, then `enricher.merge_enrich_context` combines that (primary) with the subdir names (supplementary). Both sources are AST/tree-derived, never README markdown, so the anti-injection-chain property `build_safe_subdir_context` was built for is preserved. `build_enrich_prompt`'s instruction was de-lied ("based ONLY on the information above (file names, symbol names, and subdirectories)") and a dir with genuinely no indexable content is now marked `failed (reason: no indexable content)` — retryable — instead of being sent a self-contradictory prompt. *(The original issue blamed `parallel_workers=16` concurrency; that was a confounded experiment — enrichment is a serial loop and the punts occurred serially. Diagnosis corrected by source read + clean repro before this fix.)*
|
|
25
|
+
- **Punt detection (`looks_like_refusal`) now covers the leaf-dir phrasings it was missing** (GH #94, extends GH #85): the GH #85 refusal table had `i need more` but not `i need specific`, and **zero Chinese prefixes** — so `I need specific file names…` / `我需要…文件名和符号名` / `请提供…` slipped through and were stamped `<!-- enrichment: ok -->`, poisoning the cache (skipped on re-run without `--retry-all`). Added `i need specific` plus a deliberately specific Chinese set (`我需要`, `请提供`, `需要具体`, `信息不足`, `我看到的信息`) — kept narrow so legit one-liners that merely contain `需要` (e.g. "需要登录的接口") are not misclassified, locked by `test_chinese_descriptions_with_xuyao_are_not_refusals`.
|
|
26
|
+
|
|
27
|
+
## [0.26.1] - 2026-06-05
|
|
28
|
+
|
|
29
|
+
**Theme**: GitFlow + non-Python UX patch. Four bug fixes from continued fabricOS dogfood — all paths where `codeindex` silently no-op'd or warned about state that wasn't real. No contract changes.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- **`codeindex hooks install post-commit` now warns when `.codeindex.yaml` disables the hook** (GH #87): `codeindex init` ships the yaml with `hooks.post_commit.enabled: false` by default, so the installed `.git/hooks/post-commit` wrapper would check the flag at runtime and silently no-op. The install command printed ✓, the user committed code, and `README_AI.md` never updated — classic "installed but not working" trap. New `_maybe_warn_post_commit_disabled` helper reads the yaml after install; when `post_commit.enabled` is false (or absent), prints an actionable reminder with the exact yaml snippet to flip. No behavior change to the install itself — patch-safe. (The doubly-opt-in default itself is a separate contract question deliberately deferred from this patch; the reminder is enough to unblock the first-time path.)
|
|
34
|
+
- **`codeindex init` no longer false-flags installed TS/JS parsers as missing + install hint matches the documented pipx path** (GH #86): `init_wizard.PARSER_PACKAGES` enumerated only python/php/java even though scanner gained TS/JS parsers (#73) and the parser modules exist under `src/codeindex/parsers/{typescript,javascript}/`. Result on a TS-only project: `init --yes` printed `Warning: Missing parsers for: javascript, typescript` despite `pipx inject ai-codeindex tree-sitter-{typescript,javascript}` confirming the packages were already installed. Worse, the hint said `Install with: pip install ai-codeindex[...]` — contradicts the entire documented install path (`pipx install ai-codeindex` everywhere else in CLAUDE.md, README, hooks/index SKILL) and doesn't even work cleanly for a pipx-managed env. Fix: extend `PARSER_PACKAGES` to include typescript/javascript; change the install hint to `pipx inject ai-codeindex tree-sitter-<lang> [tree-sitter-<lang2>...]` (matches the rest of the doc surface). New structural test `test_parser_package_map_covers_scanner_supported_set` locks the invariant — adding a language to scanner.py without exposing it via `PARSER_PACKAGES` will fail the test, preventing the GH #86 drift class from recurring (same pattern as the #73 structural guard).
|
|
35
|
+
- **`scan-all --ai` no longer caches AI refusal text as `enrichment: ok`** (GH #85): when the configured AI backend declined to answer for a directory (e.g. haiku returning "I don't see any file names or symbol names provided…"), Phase 2 wrote the refusal verbatim into the directory's `README_AI.md` blockquote AND stamped `<!-- enrichment: ok -->`. Subsequent `scan-all --ai` runs saw the `ok` marker, skipped re-enrichment, and the garbage description stuck in the cache forever. New `enricher.looks_like_refusal(text)` helper detects common refusal prefixes (case-insensitive: `I don't`, `I cannot`, `I'm unable`, `no file`, `insufficient context`, `as an AI`, etc.); when matched, the directory is marked `failed (reason: ai-refused)` so the next run retries automatically (idempotent re-enrichment policy already in place). Refusal-pattern detection happens on the cleaned/truncated AI output (~80 chars) — refusal phrasing always lives in the first ~30 chars so truncation doesn't blind the check.
|
|
36
|
+
- **Post-commit hook now fires on merge commits** (GH #84): the shell wrapper's loop guard used `git diff-tree --no-commit-id --name-only -r HEAD`, which returns **empty on merge commits** by default — `-m` is required to enumerate per-parent changes. Empty → `NON_DOC_FILES` empty → wrapper exits 0 without delegating to `codeindex hooks run post-commit`. Net effect on GitFlow projects: `README_AI.md` files never auto-updated on PR merges (the commits that actually bring new code to `main` / `develop`). Reported live on fabricOS HEAD `171702b` (Merge PR #7). Fix: add `-m` to the diff-tree command. Verified against a real merge commit in this repo (`e240ba0` — Merge develop for 0.26.0 release): old logic saw 0 files, new logic sees the 20 files actually changed. New regression test in `tests/test_cli_hooks.py::TestHookGeneration::test_post_commit_loop_guard_handles_merge_commits` locks both directions (rejects the broken pattern, requires either `-m` or `git show --name-only`).
|
|
37
|
+
|
|
10
38
|
## [0.26.0] - 2026-06-01
|
|
11
39
|
|
|
12
40
|
**Theme**: dogfood-driven CLI bug sweep. Five user-reported issues from fabricOS dogfood — mostly UX cliffs in `init` and `list-dirs` on non-Python projects, plus a navigation-correctness bug in nav-level `README_AI.md`. One contract change in `init --yes` so first `scan-all --ai` works out of the box.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ai-codeindex
|
|
3
|
-
Version: 0.26.
|
|
3
|
+
Version: 0.26.2
|
|
4
4
|
Summary: AI-native code indexing tool for large codebases
|
|
5
5
|
Project-URL: Homepage, https://github.com/dreamlx/codeindex
|
|
6
6
|
Project-URL: Documentation, https://github.com/dreamlx/codeindex
|
|
@@ -578,7 +578,7 @@ See [Release Automation Guide](docs/development/QUICK_START_RELEASE.md) for deta
|
|
|
578
578
|
|
|
579
579
|
## Roadmap
|
|
580
580
|
|
|
581
|
-
**Current version**: v0.
|
|
581
|
+
**Current version**: v0.26.2
|
|
582
582
|
|
|
583
583
|
**Recent milestones**:
|
|
584
584
|
- v0.23.0 — **AI-Enhanced Module Descriptions**: two-phase pipeline, auto-AI enrichment, post-commit thin wrapper
|
|
@@ -521,7 +521,7 @@ See [Release Automation Guide](docs/development/QUICK_START_RELEASE.md) for deta
|
|
|
521
521
|
|
|
522
522
|
## Roadmap
|
|
523
523
|
|
|
524
|
-
**Current version**: v0.
|
|
524
|
+
**Current version**: v0.26.2
|
|
525
525
|
|
|
526
526
|
**Recent milestones**:
|
|
527
527
|
- v0.23.0 — **AI-Enhanced Module Descriptions**: two-phase pipeline, auto-AI enrichment, post-commit thin wrapper
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# codeindex Strategic Roadmap
|
|
2
2
|
|
|
3
3
|
**Last Updated**: 2026-03-06
|
|
4
|
-
**Current Version**: v0.
|
|
4
|
+
**Current Version**: v0.26.2
|
|
5
5
|
**Vision**: Universal Code Parser - Best-in-class multi-language AST parser for AI-assisted development
|
|
6
6
|
**Positioning**: Focused on code parsing and structured data extraction, not AI analysis
|
|
7
7
|
|
|
@@ -534,4 +534,4 @@
|
|
|
534
534
|
**Next Review**: 2026-03-31
|
|
535
535
|
**Maintained By**: @dreamlx
|
|
536
536
|
**Last Updated**: 2026-03-06
|
|
537
|
-
**Current Version**: v0.
|
|
537
|
+
**Current Version**: v0.26.2
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<!-- codeindex navigation index — agent: drill into source via Read/Grep for precise mechanism; do not treat this as final word. -->
|
|
2
|
-
<!-- Generated by codeindex (detailed) at 2026-06-
|
|
2
|
+
<!-- Generated by codeindex (detailed) at 2026-06-21T23:56:14.087118 -->
|
|
3
3
|
|
|
4
4
|
# codeindex
|
|
5
5
|
|
|
6
6
|
## Overview
|
|
7
7
|
|
|
8
8
|
- **Files**: 89
|
|
9
|
-
- **Symbols**:
|
|
9
|
+
- **Symbols**: 574
|
|
10
10
|
|
|
11
11
|
## Files
|
|
12
12
|
|
|
@@ -162,7 +162,7 @@ This module provides:
|
|
|
162
162
|
- `def install_hook(hook_name: str, repo_path: Optional[Path] = None) -> bool`
|
|
163
163
|
- `def uninstall_hook(hook_name: str, repo_path: Optional[Path] = None) -> bool`
|
|
164
164
|
|
|
165
|
-
_... and
|
|
165
|
+
_... and 7 more symbols_
|
|
166
166
|
|
|
167
167
|
### cli_parse.py
|
|
168
168
|
_CLI parse command - Parse a single source file and output JSON.
|
|
@@ -227,6 +227,11 @@ s_
|
|
|
227
227
|
timeout: int = 120,
|
|
228
228
|
retry_all: bool = False,
|
|
229
229
|
) -> None`
|
|
230
|
+
- `def _build_enrich_summary(
|
|
231
|
+
dir_path: Path,
|
|
232
|
+
child_dirs: list[Path],
|
|
233
|
+
config: Config,
|
|
234
|
+
) -> str`
|
|
230
235
|
- `def _enrich_directories_with_ai(
|
|
231
236
|
dirs: list[Path],
|
|
232
237
|
tree: DirectoryTree,
|
|
@@ -237,14 +242,8 @@ s_
|
|
|
237
242
|
enrichment_cache: dict[Path, str] | None = None,
|
|
238
243
|
) -> None`
|
|
239
244
|
- `def _print_enrichment_failure_hint(failed_dirs: list[str]) -> None`
|
|
240
|
-
- `def _process_directory_with_smartwriter(
|
|
241
|
-
dir_path: Path,
|
|
242
|
-
tree: DirectoryTree,
|
|
243
|
-
config: Config,
|
|
244
|
-
docstring_processor=None,
|
|
245
|
-
) -> tuple[Path, bool, str, int]`
|
|
246
245
|
|
|
247
|
-
_... and
|
|
246
|
+
_... and 3 more symbols_
|
|
248
247
|
|
|
249
248
|
### cli_symbols.py
|
|
250
249
|
_CLI commands for symbol indexing and dependency analysis.
|
|
@@ -345,7 +344,8 @@ co_
|
|
|
345
344
|
- `def show_full_config_help() -> None`
|
|
346
345
|
- `def _show_param_section(param_name: str) -> None`
|
|
347
346
|
- `def explain_parameter(
|
|
348
|
-
param_name: str,
|
|
347
|
+
param_name: str, current_value: Optional[any] = None, cpu_count: Optional[int] = None
|
|
348
|
+
|
|
349
349
|
|
|
350
350
|
---
|
|
351
351
|
_Content truncated due to size limit. See individual module README files for details._
|
|
@@ -316,8 +316,11 @@ exit 0
|
|
|
316
316
|
# Post-commit hook for codeindex
|
|
317
317
|
# Thin wrapper — all logic in Python (auto-updated via pip)
|
|
318
318
|
|
|
319
|
-
# Avoid infinite loop: skip if last commit only contains README_AI.md
|
|
320
|
-
|
|
319
|
+
# Avoid infinite loop: skip if last commit only contains README_AI.md.
|
|
320
|
+
# -m is required so merge commits enumerate per-parent changes — without it
|
|
321
|
+
# `git diff-tree -r HEAD` returns empty on every merge commit and the hook
|
|
322
|
+
# silently skips every PR merge in a GitFlow project (GH #84).
|
|
323
|
+
LAST_COMMIT_FILES=$(git diff-tree --no-commit-id --name-only -r -m HEAD)
|
|
321
324
|
NON_DOC_FILES=$(echo "$LAST_COMMIT_FILES" | \\
|
|
322
325
|
grep -v "README_AI.md" | grep -v "PROJECT_INDEX.md" || true)
|
|
323
326
|
if [ -z "$NON_DOC_FILES" ]; then
|
|
@@ -539,6 +542,48 @@ def hooks():
|
|
|
539
542
|
pass
|
|
540
543
|
|
|
541
544
|
|
|
545
|
+
def _maybe_warn_post_commit_disabled(project_dir: Path) -> None:
|
|
546
|
+
"""Print a reminder if ``hooks.post_commit.enabled`` is false in
|
|
547
|
+
``.codeindex.yaml``.
|
|
548
|
+
|
|
549
|
+
``codeindex init`` ships the yaml with ``enabled: false`` by default,
|
|
550
|
+
so the installed ``.git/hooks/post-commit`` wrapper no-ops at runtime
|
|
551
|
+
even though the install command printed ✓. User commits, READMEs don't
|
|
552
|
+
update, "it doesn't work" — see GH #87.
|
|
553
|
+
|
|
554
|
+
We don't flip the flag automatically (contract change, see #75 for the
|
|
555
|
+
boundary). The reminder makes the contract visible at install time so
|
|
556
|
+
the user can decide.
|
|
557
|
+
"""
|
|
558
|
+
yaml_path = project_dir / ".codeindex.yaml"
|
|
559
|
+
if not yaml_path.exists():
|
|
560
|
+
return
|
|
561
|
+
|
|
562
|
+
try:
|
|
563
|
+
import yaml
|
|
564
|
+
|
|
565
|
+
with open(yaml_path) as f:
|
|
566
|
+
data = yaml.safe_load(f) or {}
|
|
567
|
+
except Exception:
|
|
568
|
+
# Yaml unreadable or parse error — silent skip; the install itself
|
|
569
|
+
# succeeded, we don't want this advisory to mask the real result.
|
|
570
|
+
return
|
|
571
|
+
|
|
572
|
+
enabled = data.get("hooks", {}).get("post_commit", {}).get("enabled", False)
|
|
573
|
+
if enabled:
|
|
574
|
+
return
|
|
575
|
+
|
|
576
|
+
console.print(
|
|
577
|
+
"[yellow]⚠[/yellow] [bold]post_commit.enabled is false in "
|
|
578
|
+
".codeindex.yaml[/bold] — the installed hook wrapper checks this "
|
|
579
|
+
"flag at runtime and will no-op until you flip it.\n"
|
|
580
|
+
" Edit [cyan].codeindex.yaml[/cyan]:\n"
|
|
581
|
+
" hooks:\n"
|
|
582
|
+
" post_commit:\n"
|
|
583
|
+
" [bold]enabled: true[/bold]\n"
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
|
|
542
587
|
@hooks.command()
|
|
543
588
|
@click.option(
|
|
544
589
|
"--all",
|
|
@@ -625,6 +670,13 @@ def install(hook_name: Optional[str], install_all: bool, force: bool):
|
|
|
625
670
|
f"[dim]→ Skipped {skipped_count} already installed hook(s)[/dim]\n"
|
|
626
671
|
)
|
|
627
672
|
|
|
673
|
+
# GH #87: surface the runtime-disabled trap. If post-commit was just
|
|
674
|
+
# installed (or was already installed), the wrapper still no-ops when
|
|
675
|
+
# .codeindex.yaml has post_commit.enabled=false (the init default).
|
|
676
|
+
# Without this reminder, install prints ✓ but commits trigger nothing.
|
|
677
|
+
if "post-commit" in hooks_to_install:
|
|
678
|
+
_maybe_warn_post_commit_disabled(Path.cwd())
|
|
679
|
+
|
|
628
680
|
except ValueError as e:
|
|
629
681
|
console.print(f"[red]✗[/red] Error: {e}", style="red")
|
|
630
682
|
raise click.Abort()
|
|
@@ -634,6 +634,47 @@ def _process_directories_parallel(
|
|
|
634
634
|
)
|
|
635
635
|
|
|
636
636
|
|
|
637
|
+
def _build_enrich_summary(
|
|
638
|
+
dir_path: Path,
|
|
639
|
+
child_dirs: list[Path],
|
|
640
|
+
config: Config,
|
|
641
|
+
) -> str:
|
|
642
|
+
"""Build the enrichment prompt context for one directory (GH #94).
|
|
643
|
+
|
|
644
|
+
Combines the directory's OWN file/symbol summary — re-parsed from source
|
|
645
|
+
(AST), non-recursively, so subtree content does not leak in — with its
|
|
646
|
+
subdirectory names. The dir's own content is the primary signal; subdir
|
|
647
|
+
names are supplementary. This fixes leaf dirs (e.g. ``controllers`` whose
|
|
648
|
+
only child is ``__tests__``) that previously got only a useless
|
|
649
|
+
``Subdirectories: __tests__`` and made the model punt.
|
|
650
|
+
|
|
651
|
+
Args:
|
|
652
|
+
dir_path: Directory being enriched.
|
|
653
|
+
child_dirs: Indexed child directories (from ``tree.get_children``).
|
|
654
|
+
config: Active configuration (for language/exclude filtering).
|
|
655
|
+
|
|
656
|
+
Returns:
|
|
657
|
+
Combined context string, or empty if the dir has no indexable content.
|
|
658
|
+
"""
|
|
659
|
+
from .enricher import (
|
|
660
|
+
build_safe_subdir_context,
|
|
661
|
+
extract_symbol_summary,
|
|
662
|
+
merge_enrich_context,
|
|
663
|
+
)
|
|
664
|
+
from .parallel import parse_files_parallel
|
|
665
|
+
from .scanner import scan_directory
|
|
666
|
+
|
|
667
|
+
subdir_context = build_safe_subdir_context(child_dirs)
|
|
668
|
+
|
|
669
|
+
own_summary = ""
|
|
670
|
+
scan_result = scan_directory(dir_path, config, recursive=False)
|
|
671
|
+
if scan_result.files:
|
|
672
|
+
parse_results = parse_files_parallel(scan_result.files, config, quiet=True)
|
|
673
|
+
own_summary = extract_symbol_summary(parse_results)
|
|
674
|
+
|
|
675
|
+
return merge_enrich_context(own_summary, subdir_context)
|
|
676
|
+
|
|
677
|
+
|
|
637
678
|
def _enrich_directories_with_ai(
|
|
638
679
|
dirs: list[Path],
|
|
639
680
|
tree: DirectoryTree,
|
|
@@ -665,9 +706,8 @@ def _enrich_directories_with_ai(
|
|
|
665
706
|
"""
|
|
666
707
|
from .enricher import (
|
|
667
708
|
build_enrich_prompt,
|
|
668
|
-
build_safe_subdir_context,
|
|
669
|
-
extract_summary_from_readme,
|
|
670
709
|
inject_blockquote,
|
|
710
|
+
looks_like_refusal,
|
|
671
711
|
mark_enrichment_status,
|
|
672
712
|
should_enrich,
|
|
673
713
|
)
|
|
@@ -714,17 +754,21 @@ def _enrich_directories_with_ai(
|
|
|
714
754
|
for dir_path in enrich_dirs:
|
|
715
755
|
readme_path = dir_path / config.output_file
|
|
716
756
|
|
|
717
|
-
#
|
|
718
|
-
#
|
|
719
|
-
#
|
|
720
|
-
# (
|
|
757
|
+
# Build context from the dir's OWN files/symbols (primary) plus its
|
|
758
|
+
# subdirectory names (supplementary). Both come from AST/tree sources,
|
|
759
|
+
# never README markdown, so the anti-injection-chain property holds
|
|
760
|
+
# (GH #94).
|
|
721
761
|
child_dirs = tree.get_children(dir_path)
|
|
722
|
-
summary =
|
|
723
|
-
|
|
724
|
-
if not summary:
|
|
725
|
-
summary = extract_summary_from_readme(readme_path)
|
|
762
|
+
summary = _build_enrich_summary(dir_path, child_dirs, config)
|
|
726
763
|
|
|
727
764
|
if not summary:
|
|
765
|
+
# Nothing indexable to describe — mark failed (retryable) rather
|
|
766
|
+
# than send a prompt that asks the model to describe nothing.
|
|
767
|
+
if readme_path.exists():
|
|
768
|
+
mark_enrichment_status(
|
|
769
|
+
readme_path, "failed", reason="no indexable content"
|
|
770
|
+
)
|
|
771
|
+
failed_dirs.append(dir_path.name)
|
|
728
772
|
continue
|
|
729
773
|
|
|
730
774
|
# Include parent directory name for context
|
|
@@ -759,6 +803,20 @@ def _enrich_directories_with_ai(
|
|
|
759
803
|
failed_dirs.append(dir_path.name)
|
|
760
804
|
continue
|
|
761
805
|
|
|
806
|
+
# AI returned text, but is it an actual description or a refusal?
|
|
807
|
+
# Stamping refusal text with `enrichment: ok` poisons the cache forever
|
|
808
|
+
# because subsequent runs see the marker and skip re-enrichment (GH #85).
|
|
809
|
+
if looks_like_refusal(description):
|
|
810
|
+
if readme_path.exists():
|
|
811
|
+
mark_enrichment_status(readme_path, "failed", reason="ai-refused")
|
|
812
|
+
failed_dirs.append(dir_path.name)
|
|
813
|
+
if not quiet:
|
|
814
|
+
console.print(
|
|
815
|
+
f"[yellow]⚠[/yellow] {dir_path.name}: AI declined "
|
|
816
|
+
f"(refusal pattern) — will retry next `scan-all --ai`"
|
|
817
|
+
)
|
|
818
|
+
continue
|
|
819
|
+
|
|
762
820
|
# Inject into README_AI.md
|
|
763
821
|
if readme_path.exists():
|
|
764
822
|
inject_blockquote(readme_path, description)
|
|
@@ -18,6 +18,54 @@ _MAX_SYMBOLS_PER_FILE = 5
|
|
|
18
18
|
# Maximum total files to include in the prompt
|
|
19
19
|
_MAX_FILES = 15
|
|
20
20
|
|
|
21
|
+
# Refusal prefixes used to detect AI responses that decline to summarise the
|
|
22
|
+
# directory (typically because the prompt context was thin enough that the
|
|
23
|
+
# model can't say anything specific). When the model returns "I don't see any
|
|
24
|
+
# file names..." we must NOT stamp `enrichment: ok` — that poisons the cache
|
|
25
|
+
# permanently (GH #85). Instead the response is treated as a failure with
|
|
26
|
+
# reason "ai-refused" so the next `scan-all --ai` retries automatically.
|
|
27
|
+
#
|
|
28
|
+
# Matched against the lowercased, stripped response. Keep prefixes short so
|
|
29
|
+
# the check is robust to upstream truncation (the cli_scan path truncates
|
|
30
|
+
# enrichment output to ~80 chars; refusal phrasing is always in the first 30).
|
|
31
|
+
_REFUSAL_PREFIXES = (
|
|
32
|
+
"i don't",
|
|
33
|
+
"i do not",
|
|
34
|
+
"i cannot",
|
|
35
|
+
"i can't",
|
|
36
|
+
"i'm unable",
|
|
37
|
+
"i am unable",
|
|
38
|
+
"i need more",
|
|
39
|
+
"i need specific", # GH #94: leaf-dir punt asking for omitted file/symbol names
|
|
40
|
+
"no file",
|
|
41
|
+
"insufficient context",
|
|
42
|
+
"without more",
|
|
43
|
+
"sorry, i",
|
|
44
|
+
"as an ai",
|
|
45
|
+
# Chinese punts (GH #94). Kept specific so legit one-liners that merely
|
|
46
|
+
# contain 需要 (e.g. "需要登录的接口") are not misclassified.
|
|
47
|
+
"我需要",
|
|
48
|
+
"请提供",
|
|
49
|
+
"需要具体",
|
|
50
|
+
"信息不足",
|
|
51
|
+
"我看到的信息",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def looks_like_refusal(text: str) -> bool:
|
|
56
|
+
"""Return True if the cleaned AI response looks like a refusal / inability.
|
|
57
|
+
|
|
58
|
+
Used by ``scan-all --ai`` Phase 2 to distinguish a usable one-line
|
|
59
|
+
description from boilerplate refusal text. The refusal text is never
|
|
60
|
+
project-information and stamping it with ``<!-- enrichment: ok -->``
|
|
61
|
+
pins it in the cache; the next run sees the marker and skips
|
|
62
|
+
re-enrichment, so the garbage description sticks indefinitely (GH #85).
|
|
63
|
+
"""
|
|
64
|
+
t = (text or "").strip().lower()
|
|
65
|
+
if not t:
|
|
66
|
+
return False
|
|
67
|
+
return any(t.startswith(p) for p in _REFUSAL_PREFIXES)
|
|
68
|
+
|
|
21
69
|
|
|
22
70
|
def extract_symbol_summary(parse_results: list[ParseResult]) -> str:
|
|
23
71
|
"""Extract a compact summary of file names + symbol names for AI prompt.
|
|
@@ -125,6 +173,35 @@ def build_safe_subdir_context(child_dirs: list[Path]) -> str:
|
|
|
125
173
|
return "Subdirectories: " + ", ".join(names) + suffix
|
|
126
174
|
|
|
127
175
|
|
|
176
|
+
def merge_enrich_context(own_summary: str, subdir_context: str) -> str:
|
|
177
|
+
"""Combine a directory's own file/symbol summary with its subdir names.
|
|
178
|
+
|
|
179
|
+
GH #94: a directory's OWN files and symbols are the primary signal for a
|
|
180
|
+
one-line description; subdirectory names are only supplementary. The
|
|
181
|
+
previous enrichment path used subdir context with a README fallback and a
|
|
182
|
+
single uninformative child (e.g. ``__tests__``) made the subdir context
|
|
183
|
+
non-empty, short-circuiting the dir's own content and leaving leaf dirs
|
|
184
|
+
with an empty prompt — so the model punted ("I need the file names").
|
|
185
|
+
|
|
186
|
+
Both inputs come from AST/tree sources (``extract_symbol_summary`` and
|
|
187
|
+
``build_safe_subdir_context``), never from README markdown, preserving the
|
|
188
|
+
anti-injection-chain property ``build_safe_subdir_context`` was built for.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
own_summary: ``extract_symbol_summary`` output (file: symbols; ...).
|
|
192
|
+
subdir_context: ``build_safe_subdir_context`` output (Subdirectories: ...).
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Combined context string, or empty string if both inputs are empty.
|
|
196
|
+
"""
|
|
197
|
+
parts = []
|
|
198
|
+
if own_summary and own_summary.strip():
|
|
199
|
+
parts.append(f"Files: {own_summary.strip()}")
|
|
200
|
+
if subdir_context and subdir_context.strip():
|
|
201
|
+
parts.append(subdir_context.strip())
|
|
202
|
+
return "\n".join(parts)
|
|
203
|
+
|
|
204
|
+
|
|
128
205
|
def build_enrich_prompt(
|
|
129
206
|
dir_name: str,
|
|
130
207
|
symbol_summary: str,
|
|
@@ -148,13 +225,14 @@ def build_enrich_prompt(
|
|
|
148
225
|
return (
|
|
149
226
|
context
|
|
150
227
|
+ "\n"
|
|
151
|
-
"Based ONLY on the file names
|
|
152
|
-
"functional description of this
|
|
228
|
+
"Based ONLY on the information above (file names, symbol names, and "
|
|
229
|
+
"subdirectories), write a concise functional description of this "
|
|
230
|
+
"module (30 chars or less). "
|
|
153
231
|
"Describe WHAT it does, not HOW. "
|
|
154
232
|
"Examples: '会员等级、积分、权益卡管理', 'Payment gateway (Alipay/WeChat)', "
|
|
155
233
|
"'物流配送与运费计算'. "
|
|
156
234
|
"Output ONLY the description text. No quotes, no markdown, no explanation. "
|
|
157
|
-
"Do NOT invent features not evidenced by the
|
|
235
|
+
"Do NOT invent features not evidenced by the names above."
|
|
158
236
|
)
|
|
159
237
|
|
|
160
238
|
|
|
@@ -94,11 +94,19 @@ FRAMEWORK_PATTERNS: Dict[str, Dict[str, str]] = {
|
|
|
94
94
|
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
# Parser package mapping: language -> tree-sitter
|
|
97
|
+
# Parser package mapping: language -> tree-sitter Python import name.
|
|
98
|
+
#
|
|
99
|
+
# Must stay in sync with ``scanner.LANGUAGE_EXTENSIONS``. The structural
|
|
100
|
+
# test ``test_parser_package_map_covers_scanner_supported_set`` locks the
|
|
101
|
+
# invariant — adding a language to scanner.py without exposing it here
|
|
102
|
+
# silently re-introduces the GH #86 false-positive ("missing parsers" for
|
|
103
|
+
# parsers that are actually installed).
|
|
98
104
|
PARSER_PACKAGES = {
|
|
99
105
|
"python": "tree_sitter_python",
|
|
100
106
|
"php": "tree_sitter_php",
|
|
101
107
|
"java": "tree_sitter_java",
|
|
108
|
+
"typescript": "tree_sitter_typescript",
|
|
109
|
+
"javascript": "tree_sitter_javascript",
|
|
102
110
|
}
|
|
103
111
|
|
|
104
112
|
|
|
@@ -146,8 +154,13 @@ def get_parser_install_guidance(languages: list[str]) -> dict:
|
|
|
146
154
|
}
|
|
147
155
|
|
|
148
156
|
if missing:
|
|
149
|
-
|
|
150
|
-
|
|
157
|
+
# Use `pipx inject ai-codeindex tree-sitter-<lang>` to match the
|
|
158
|
+
# documented install path (CLAUDE.md, README, hooks/index SKILL all
|
|
159
|
+
# use pipx). The previous `pip install ai-codeindex[<lang>]` hint
|
|
160
|
+
# contradicted the recommended path AND broke for pipx-managed
|
|
161
|
+
# envs — see GH #86 (4b).
|
|
162
|
+
pkgs = " ".join(f"tree-sitter-{lang}" for lang in missing)
|
|
163
|
+
result["install_command"] = f"pipx inject ai-codeindex {pkgs}"
|
|
151
164
|
|
|
152
165
|
return result
|
|
153
166
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<!-- codeindex navigation index — agent: drill into source via Read/Grep for precise mechanism; do not treat this as final word. -->
|
|
2
|
-
<!-- Generated by codeindex (detailed) at 2026-06-
|
|
2
|
+
<!-- Generated by codeindex (detailed) at 2026-06-21T23:56:14.360118 -->
|
|
3
3
|
|
|
4
4
|
# tests
|
|
5
5
|
|
|
6
6
|
## Overview
|
|
7
7
|
|
|
8
8
|
- **Files**: 125
|
|
9
|
-
- **Symbols**:
|
|
9
|
+
- **Symbols**: 2172
|
|
10
10
|
|
|
11
11
|
## Files
|
|
12
12
|
|
|
@@ -223,6 +223,40 @@ class TestHookGeneration:
|
|
|
223
223
|
|
|
224
224
|
assert "codeindex-managed hook" in script
|
|
225
225
|
|
|
226
|
+
def test_post_commit_loop_guard_handles_merge_commits(self):
|
|
227
|
+
"""Regression for GH #84.
|
|
228
|
+
|
|
229
|
+
``git diff-tree --no-commit-id --name-only -r HEAD`` returns empty
|
|
230
|
+
on merge commits by default — it needs ``-m`` to enumerate the
|
|
231
|
+
per-parent changes. Without the flag, the loop guard sees zero
|
|
232
|
+
files on every merge commit, hits the "all docs" early-exit, and
|
|
233
|
+
the wrapper never delegates to ``codeindex hooks run post-commit``.
|
|
234
|
+
|
|
235
|
+
Net effect on GitFlow projects: ``README_AI.md`` files never
|
|
236
|
+
auto-update on PR merges (the commits that bring new code to
|
|
237
|
+
``main`` / ``develop``). Reported live on fabricOS HEAD ``171702b``.
|
|
238
|
+
"""
|
|
239
|
+
script = generate_hook_script("post-commit")
|
|
240
|
+
|
|
241
|
+
# The broken pattern: -r HEAD without -m. Asserted as a literal
|
|
242
|
+
# substring so future whitespace/format tweaks don't accidentally
|
|
243
|
+
# let it back in.
|
|
244
|
+
assert "diff-tree --no-commit-id --name-only -r HEAD" not in script, (
|
|
245
|
+
"Post-commit loop guard uses `git diff-tree -r HEAD` without -m. "
|
|
246
|
+
"On merge commits this returns empty and the hook silently skips "
|
|
247
|
+
"(GH #84). Use `-m` or `git show --name-only`."
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
# The fix: either -m on diff-tree OR git show --name-only. Both
|
|
251
|
+
# produce non-empty output on merge commits.
|
|
252
|
+
has_dash_m = "diff-tree" in script and " -m " in script
|
|
253
|
+
has_git_show = "git show --name-only" in script
|
|
254
|
+
assert has_dash_m or has_git_show, (
|
|
255
|
+
"Post-commit hook must enumerate files on merge commits. "
|
|
256
|
+
"Expected either `git diff-tree ... -m HEAD` or "
|
|
257
|
+
"`git show --name-only ... HEAD` in the loop guard (GH #84)."
|
|
258
|
+
)
|
|
259
|
+
|
|
226
260
|
|
|
227
261
|
class TestBackupAndRestore:
|
|
228
262
|
"""Test backup and restore functionality."""
|
|
@@ -297,3 +331,85 @@ class TestCLIIntegration:
|
|
|
297
331
|
"""Should provide hooks status CLI command."""
|
|
298
332
|
# This will be implemented with Click
|
|
299
333
|
pass
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
class TestPostCommitEnabledWarning:
|
|
337
|
+
"""GH #87 — ``codeindex hooks install post-commit`` must surface the
|
|
338
|
+
runtime-disabled trap.
|
|
339
|
+
|
|
340
|
+
``codeindex init`` writes ``.codeindex.yaml`` with
|
|
341
|
+
``hooks.post_commit.enabled: false`` by default. Without a reminder at
|
|
342
|
+
install time, users see the install ✓, make commits, and nothing
|
|
343
|
+
happens because the wrapper checks the flag at runtime. These tests
|
|
344
|
+
cover the three meaningful states (disabled / enabled / no yaml)."""
|
|
345
|
+
|
|
346
|
+
def _yaml(self, enabled: bool) -> str:
|
|
347
|
+
return (
|
|
348
|
+
"version: 1\n"
|
|
349
|
+
"hooks:\n"
|
|
350
|
+
" post_commit:\n"
|
|
351
|
+
f" enabled: {str(enabled).lower()}\n"
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
def test_install_warns_when_yaml_disables_post_commit(self, tmp_path):
|
|
355
|
+
from click.testing import CliRunner
|
|
356
|
+
|
|
357
|
+
from codeindex.cli import main
|
|
358
|
+
|
|
359
|
+
(tmp_path / ".git" / "hooks").mkdir(parents=True)
|
|
360
|
+
(tmp_path / ".codeindex.yaml").write_text(self._yaml(enabled=False))
|
|
361
|
+
|
|
362
|
+
runner = CliRunner()
|
|
363
|
+
original_cwd = os.getcwd()
|
|
364
|
+
try:
|
|
365
|
+
os.chdir(tmp_path)
|
|
366
|
+
result = runner.invoke(main, ["hooks", "install", "post-commit"])
|
|
367
|
+
finally:
|
|
368
|
+
os.chdir(original_cwd)
|
|
369
|
+
|
|
370
|
+
assert result.exit_code == 0, result.output
|
|
371
|
+
assert "post_commit.enabled is false" in result.output, result.output
|
|
372
|
+
# The user-visible fix (the yaml snippet) must be present.
|
|
373
|
+
assert "enabled: true" in result.output
|
|
374
|
+
|
|
375
|
+
def test_install_silent_when_yaml_enables_post_commit(self, tmp_path):
|
|
376
|
+
from click.testing import CliRunner
|
|
377
|
+
|
|
378
|
+
from codeindex.cli import main
|
|
379
|
+
|
|
380
|
+
(tmp_path / ".git" / "hooks").mkdir(parents=True)
|
|
381
|
+
(tmp_path / ".codeindex.yaml").write_text(self._yaml(enabled=True))
|
|
382
|
+
|
|
383
|
+
runner = CliRunner()
|
|
384
|
+
original_cwd = os.getcwd()
|
|
385
|
+
try:
|
|
386
|
+
os.chdir(tmp_path)
|
|
387
|
+
result = runner.invoke(main, ["hooks", "install", "post-commit"])
|
|
388
|
+
finally:
|
|
389
|
+
os.chdir(original_cwd)
|
|
390
|
+
|
|
391
|
+
assert result.exit_code == 0, result.output
|
|
392
|
+
# No reminder when the user has explicitly enabled it.
|
|
393
|
+
assert "post_commit.enabled is false" not in result.output
|
|
394
|
+
|
|
395
|
+
def test_install_silent_when_no_yaml(self, tmp_path):
|
|
396
|
+
"""Without ``.codeindex.yaml`` we don't know the project's intent;
|
|
397
|
+
the install itself succeeds, advisory stays silent — matches the
|
|
398
|
+
rule "don't mask the real result of a non-yaml-driven command"."""
|
|
399
|
+
from click.testing import CliRunner
|
|
400
|
+
|
|
401
|
+
from codeindex.cli import main
|
|
402
|
+
|
|
403
|
+
(tmp_path / ".git" / "hooks").mkdir(parents=True)
|
|
404
|
+
# No .codeindex.yaml.
|
|
405
|
+
|
|
406
|
+
runner = CliRunner()
|
|
407
|
+
original_cwd = os.getcwd()
|
|
408
|
+
try:
|
|
409
|
+
os.chdir(tmp_path)
|
|
410
|
+
result = runner.invoke(main, ["hooks", "install", "post-commit"])
|
|
411
|
+
finally:
|
|
412
|
+
os.chdir(original_cwd)
|
|
413
|
+
|
|
414
|
+
assert result.exit_code == 0, result.output
|
|
415
|
+
assert "post_commit.enabled is false" not in result.output
|