ai-codeindex 0.26.0__tar.gz → 0.26.1__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.1}/.gitignore +1 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/CHANGELOG.md +11 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/PKG-INFO +1 -1
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/pyproject.toml +1 -1
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/README_AI.md +3 -3
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli_hooks.py +54 -2
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli_scan.py +15 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/enricher.py +40 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/init_wizard.py +16 -3
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/README_AI.md +2 -2
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_cli_hooks.py +116 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_enricher.py +73 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_detection.py +65 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.editorconfig +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.github/ISSUE_TEMPLATE/bug.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.github/ISSUE_TEMPLATE/enhancement.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.github/ISSUE_TEMPLATE/epic.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.github/ISSUE_TEMPLATE/feature.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.github/workflows/ci.yml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.github/workflows/publish.yml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.serena/.gitignore +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.serena/memories/design_philosophy.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.serena/memories/development_workflow.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.serena/memories/project_overview.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.serena/memories/release_automation.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/.serena/memories/suggested_commands.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/CLAUDE.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/CODE_OF_CONDUCT.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/CONTRIBUTING.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/FOR_LOOMGRAPH.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/LICENSE +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/Makefile +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/PROJECT_SYMBOLS.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/README_zh.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/SECURITY.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/bench/.gitignore +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/bench/Makefile +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/bench/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/bench/grade.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/bench/questions.yaml.example +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/bench/report.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/bench/run_bench.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/bench/targets.yaml.example +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/adr/001-use-tree-sitter-for-parsing.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/adr/002-external-ai-cli-integration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/adr/003-add-swift-objc-support.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/adr/004-automatic-claude-md-update.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/adr/005-navigation-disclaimer-and-readme-size-cap.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/adr/006-distribution-architecture-split.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/design/document-aggregation.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/design/initial-design.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/design/kiss-universal-description.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/design/parallel-strategy.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/architecture/design-philosophy.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/benchmark/2026-05-readme-impact.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/development/QUICK_START_RELEASE.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/development/claude-code-adoption-guide.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/development/claude-code-adoption-guide.zh.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/development/gitflow-workflow.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/development/github-issue-quick-reference.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/development/package-naming.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/development/pre-release-checklist.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/development/setup.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/development/team-workflow-guide.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/development/test-architecture.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/evaluation/before-after/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/evaluation/case-studies/php-payment-project.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/evaluation/loomgraph-efficiency-comparison.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/guides/advanced-usage.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/guides/claude-code-integration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/guides/configuration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/guides/contributing.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/guides/getting-started.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/guides/git-hooks-integration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/guides/json-output-integration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/guides/loomgraph-integration.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/planning/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/planning/ROADMAP.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/planning/executive-summary.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.10.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.12.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.12.1.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.14.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.15.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.17.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.17.2.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.17.3.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.18.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.19.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.2.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.20.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.23.1.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.23.2.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.24.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.25.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.3.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.3.1.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.3.2.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.4.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.5.0-beta1.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.7.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.8.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/docs/releases/RELEASE_NOTES_v0.9.0.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/CLAUDE.md.php-project +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/CLAUDE.md.template +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/ai-integration-guide.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/frameworks/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/frameworks/template/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/frameworks/template/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/frameworks/template/test_template_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/frameworks/template/yourframework_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/loomgraph_output.json +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/loomgraph_php_output.json +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/loomgraph_sample.php +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/loomgraph_sample.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/parse_integration_example.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/examples/print_env.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/hooks/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/hooks/templates/post-commit-update-logic.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/hooks/templates/post-commit-v4 +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/reports/swift-objc-support-analysis.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/reports/swift-poc-summary.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/reports/tech-debt-codeindex-v2.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/reports/tech-debt-codeindex.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/reports/tech-debt-loomgraph-v2.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/reports/tech-debt-loomgraph.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/reports/workflow-comparison.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/bump_version.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/check_docs_release.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/check_version_consistency.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/close-epic9-issues.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/diagnose_ai_failures.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/hooks/hook-common.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/hooks/pre-push +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/legacy/PROJECT_INDEX.json +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/legacy/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/legacy/hierarchical_strategy.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/pre_release_check.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/release.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/test_hook_e2e.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/scripts/validate_php_project.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/skills/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/skills/create.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/skills/install.sh +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/skills/src/mo-arch/SKILL.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/skills/src/mo-index/SKILL.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/adaptive_config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/adaptive_selector.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/ai_helper.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/claude_md.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli_claude_md.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli_common.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli_config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli_config_commands.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli_docs.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli_parse.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli_symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/cli_tech_debt.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/config_help.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/directory_tree.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/docstring_processor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/doctor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/errors.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/extractors/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/extractors/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/extractors/spring.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/extractors/thinkphp.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/file_classifier.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/framework_detect.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/hierarchical.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/hooks.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/incremental.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/invoker.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/objc_association.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parallel.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parser.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/base.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/java/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/java/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/java/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/java/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/java/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/java/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/java_parser.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/objc/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/objc/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/objc/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/objc/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/objc/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/objc/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/php/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/php/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/php/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/php/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/php/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/php/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/python/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/python/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/python/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/python/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/python/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/python/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/swift/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/swift/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/swift/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/swift/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/swift/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/swift/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/typescript/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/typescript/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/typescript/calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/typescript/imports.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/typescript/inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/typescript/symbols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/parsers/utils.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/route_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/route_registry.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/scanner.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/semantic_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/skill_helpers.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/smart_writer.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/symbol_index.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/symbol_scorer.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/tech_debt.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/tech_debt_formatters.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/templates/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/templates/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/templates/claude_md_core.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/test_smells.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/writer.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/writers/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/writers/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/writers/core.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/writers/detailed_generator.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/writers/navigation_generator.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/writers/overview_generator.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/src/codeindex/writers/utils.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/test_generator/generator.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/test_generator/scripts/analyze_legacy_tests.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/test_generator/scripts/compare_coverage.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/test_generator/scripts/compare_test_results.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/test_generator/specs/java.yaml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/test_generator/specs/php.yaml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/test_generator/specs/python.yaml +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/test_generator/templates/inheritance_test.py.j2 +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/conftest.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/extractors/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/extractors/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/extractors/test_spring.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/extractors/test_thinkphp.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/extractors/test_thinkphp_description.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/features/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/features/cli_scan_defaults.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/features/help_system.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/features/init_wizard.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/features/symbol_overload_detection.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/features/tech_debt_detection.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/features/tech_debt_reporting.feature +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/cli_parse/Controller.php +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/cli_parse/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/cli_parse/Service.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/cli_parse/Simple.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/cli_parse/broken.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/cli_parse/complete.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/cli_parse/service.ts +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/cli_parse/simple.php +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/cli_parse/simple.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/cli_parse/unsupported.txt +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/enum.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/generics.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/imports.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/interface.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/record.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/sealed_class.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/simple_class.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/spring/Application.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/spring/User.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/spring/UserController.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/spring/UserRepository.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/spring/UserService.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/java/spring_controller.java +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/typescript/app.js +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/typescript/component.tsx +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/fixtures/typescript/service.ts +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/legacy/README.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/legacy/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/legacy/test_hierarchical_test/level1/file1.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/legacy/test_hierarchical_test/level1/level2a/file2.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/legacy/test_hierarchical_test/level1/level2a/level3/file4.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/legacy/test_hierarchical_test/level1/level2b/file3.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/legacy/test_hierarchy_simple.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_adaptive_config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_adaptive_selector.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_ai_helper.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_backward_compatibility.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_call_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_claude_md.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_claude_md_injection.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_cli_config_gitignore.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_cli_debt_scan.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_cli_docstring_options.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_cli_json.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_cli_parse.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_cli_scan_defaults_bdd.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_cli_tech_debt.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_config_adaptive.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_dataclass_structure.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_directory_tree.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_docstring_config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_docstring_processor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_doctor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_enricher_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_error_handling.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_file_classifier.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_help_system_bdd.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_hook_post_commit.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_hooks.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_hooks_config.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_hooks_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_init_minimal_scope.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_init_wizard_bdd.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_integration_swift_objc.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_annotations.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_edge_cases.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_error_recovery.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_generic_bounds.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_lambda.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_lombok.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_module.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_parser.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_spring.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_java_throws.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_json_output.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_lazy_loading.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_list_dirs_diagnostic.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_loomgraph_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_objc_association_utils.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parallel_scan.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_objc_association.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_objc_basic.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_objc_bridging.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_objc_categories.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_swift_docstrings.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_swift_extensions.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_swift_generics.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_swift_inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_swift_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_swift_poc.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_swift_properties.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_swift_property_wrappers.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_swift_protocols.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_parser_swift_signatures.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_php_calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_php_comment_extraction.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_php_docstring_extraction.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_php_import_alias.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_php_inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_php_loomgraph_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_project_index_semantic.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_python_calls.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_python_docstring_description.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_python_import_alias.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_python_inheritance.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_route_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_route_info.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_route_registry.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_route_table_description.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_route_table_display.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_scanall_auto_ai.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_scanner_passthrough.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_semantic_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_skill_helpers.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_smart_writer.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_smart_writer_adaptive.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_smart_writer_docstring.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_smart_writer_enriched.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_smart_writer_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_smart_writer_semantic.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_story_4_4_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_symbol_overload.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_symbol_scorer.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_tech_debt_bdd.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_tech_debt_detector.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_tech_debt_formatters.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_tech_debt_ios.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_tech_debt_java.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_tech_debt_reporter.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_test_smells.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_thinkphp_route_extractor.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_typescript_integration.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_typescript_parser.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_windows_path_optimization.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/test_writer_preserves_enrichment.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/writers/README_AI.md +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/writers/__init__.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/writers/test_generators.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/tests/writers/test_utils.py +0 -0
- {ai_codeindex-0.26.0 → ai_codeindex-0.26.1}/uv.lock +0 -0
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.26.1] - 2026-06-05
|
|
11
|
+
|
|
12
|
+
**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.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **`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.)
|
|
17
|
+
- **`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).
|
|
18
|
+
- **`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.
|
|
19
|
+
- **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`).
|
|
20
|
+
|
|
10
21
|
## [0.26.0] - 2026-06-01
|
|
11
22
|
|
|
12
23
|
**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,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-05T21:54:59.634399 -->
|
|
3
3
|
|
|
4
4
|
# codeindex
|
|
5
5
|
|
|
6
6
|
## Overview
|
|
7
7
|
|
|
8
8
|
- **Files**: 89
|
|
9
|
-
- **Symbols**:
|
|
9
|
+
- **Symbols**: 572
|
|
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.
|
|
@@ -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()
|
|
@@ -668,6 +668,7 @@ def _enrich_directories_with_ai(
|
|
|
668
668
|
build_safe_subdir_context,
|
|
669
669
|
extract_summary_from_readme,
|
|
670
670
|
inject_blockquote,
|
|
671
|
+
looks_like_refusal,
|
|
671
672
|
mark_enrichment_status,
|
|
672
673
|
should_enrich,
|
|
673
674
|
)
|
|
@@ -759,6 +760,20 @@ def _enrich_directories_with_ai(
|
|
|
759
760
|
failed_dirs.append(dir_path.name)
|
|
760
761
|
continue
|
|
761
762
|
|
|
763
|
+
# AI returned text, but is it an actual description or a refusal?
|
|
764
|
+
# Stamping refusal text with `enrichment: ok` poisons the cache forever
|
|
765
|
+
# because subsequent runs see the marker and skip re-enrichment (GH #85).
|
|
766
|
+
if looks_like_refusal(description):
|
|
767
|
+
if readme_path.exists():
|
|
768
|
+
mark_enrichment_status(readme_path, "failed", reason="ai-refused")
|
|
769
|
+
failed_dirs.append(dir_path.name)
|
|
770
|
+
if not quiet:
|
|
771
|
+
console.print(
|
|
772
|
+
f"[yellow]⚠[/yellow] {dir_path.name}: AI declined "
|
|
773
|
+
f"(refusal pattern) — will retry next `scan-all --ai`"
|
|
774
|
+
)
|
|
775
|
+
continue
|
|
776
|
+
|
|
762
777
|
# Inject into README_AI.md
|
|
763
778
|
if readme_path.exists():
|
|
764
779
|
inject_blockquote(readme_path, description)
|
|
@@ -18,6 +18,46 @@ _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
|
+
"no file",
|
|
40
|
+
"insufficient context",
|
|
41
|
+
"without more",
|
|
42
|
+
"sorry, i",
|
|
43
|
+
"as an ai",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def looks_like_refusal(text: str) -> bool:
|
|
48
|
+
"""Return True if the cleaned AI response looks like a refusal / inability.
|
|
49
|
+
|
|
50
|
+
Used by ``scan-all --ai`` Phase 2 to distinguish a usable one-line
|
|
51
|
+
description from boilerplate refusal text. The refusal text is never
|
|
52
|
+
project-information and stamping it with ``<!-- enrichment: ok -->``
|
|
53
|
+
pins it in the cache; the next run sees the marker and skips
|
|
54
|
+
re-enrichment, so the garbage description sticks indefinitely (GH #85).
|
|
55
|
+
"""
|
|
56
|
+
t = (text or "").strip().lower()
|
|
57
|
+
if not t:
|
|
58
|
+
return False
|
|
59
|
+
return any(t.startswith(p) for p in _REFUSAL_PREFIXES)
|
|
60
|
+
|
|
21
61
|
|
|
22
62
|
def extract_symbol_summary(parse_results: list[ParseResult]) -> str:
|
|
23
63
|
"""Extract a compact summary of file names + symbol names for AI prompt.
|
|
@@ -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-05T21:54:59.931951 -->
|
|
3
3
|
|
|
4
4
|
# tests
|
|
5
5
|
|
|
6
6
|
## Overview
|
|
7
7
|
|
|
8
8
|
- **Files**: 125
|
|
9
|
-
- **Symbols**:
|
|
9
|
+
- **Symbols**: 2164
|
|
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
|
|
@@ -14,6 +14,7 @@ from codeindex.enricher import (
|
|
|
14
14
|
extract_symbol_summary,
|
|
15
15
|
has_successful_enrichment,
|
|
16
16
|
inject_blockquote,
|
|
17
|
+
looks_like_refusal,
|
|
17
18
|
mark_enrichment_status,
|
|
18
19
|
should_enrich,
|
|
19
20
|
)
|
|
@@ -417,3 +418,75 @@ class TestMarkEnrichmentStatus:
|
|
|
417
418
|
line for line in content.split("\n") if line.startswith("<!-- enrichment:")
|
|
418
419
|
][0]
|
|
419
420
|
assert "line2" not in enrichment_line or "\n" not in enrichment_line
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
class TestLooksLikeRefusal:
|
|
424
|
+
"""Tests for the GH #85 refusal detector."""
|
|
425
|
+
|
|
426
|
+
def test_classic_refusal_patterns(self):
|
|
427
|
+
"""Phrases observed on fabricOS haiku enrichment failures."""
|
|
428
|
+
# The exact phrase that prompted the bug report:
|
|
429
|
+
assert looks_like_refusal(
|
|
430
|
+
"I don't see any file names or symbol names provided in the directory listing"
|
|
431
|
+
)
|
|
432
|
+
assert looks_like_refusal("I cannot provide a description without more context")
|
|
433
|
+
assert looks_like_refusal("I'm unable to summarise this module")
|
|
434
|
+
assert looks_like_refusal("I am unable to identify the purpose")
|
|
435
|
+
assert looks_like_refusal("I need more information to describe this")
|
|
436
|
+
assert looks_like_refusal("No file names were provided")
|
|
437
|
+
assert looks_like_refusal("Insufficient context to summarise")
|
|
438
|
+
assert looks_like_refusal("Sorry, I can't help with that")
|
|
439
|
+
assert looks_like_refusal("As an AI language model, I can't...")
|
|
440
|
+
|
|
441
|
+
def test_case_insensitive_and_whitespace_tolerant(self):
|
|
442
|
+
assert looks_like_refusal(" I DON'T see any files ")
|
|
443
|
+
assert looks_like_refusal("\n\ni cannot help\n")
|
|
444
|
+
assert looks_like_refusal("I Don't Have Enough Info")
|
|
445
|
+
|
|
446
|
+
def test_normal_descriptions_are_not_refusals(self):
|
|
447
|
+
"""Real one-line descriptions must pass through unmolested."""
|
|
448
|
+
assert not looks_like_refusal("会员等级管理、积分兑换、权益卡券")
|
|
449
|
+
assert not looks_like_refusal("Identity and authentication layer")
|
|
450
|
+
assert not looks_like_refusal("HTTP request handlers and middleware")
|
|
451
|
+
assert not looks_like_refusal("Data access layer (repositories + ORM)")
|
|
452
|
+
# English description that mentions "I" but isn't a refusal:
|
|
453
|
+
assert not looks_like_refusal("Implementation of OAuth2 flows")
|
|
454
|
+
|
|
455
|
+
def test_empty_and_whitespace_only(self):
|
|
456
|
+
# Empty / whitespace-only is handled by the existing "empty AI
|
|
457
|
+
# response" branch in cli_scan; the refusal check should NOT also
|
|
458
|
+
# claim it (avoid double-classification).
|
|
459
|
+
assert not looks_like_refusal("")
|
|
460
|
+
assert not looks_like_refusal(" ")
|
|
461
|
+
assert not looks_like_refusal("\n\n\t")
|
|
462
|
+
assert not looks_like_refusal(None) # type: ignore[arg-type]
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
class TestRefusalEndToEndMarker:
|
|
466
|
+
"""GH #85 — refusal text must end up as `failed (ai-refused)`, never `ok`.
|
|
467
|
+
|
|
468
|
+
Mirrors the cli_scan Phase 2 decision branch: after cleaning the AI
|
|
469
|
+
response, the loop chooses between (empty / refused / ok). This test
|
|
470
|
+
drives the same conditional with a refusal sample and asserts the
|
|
471
|
+
on-disk marker + blockquote state.
|
|
472
|
+
"""
|
|
473
|
+
|
|
474
|
+
def test_refusal_text_marks_failed_not_ok(self, tmp_path):
|
|
475
|
+
readme = tmp_path / "README_AI.md"
|
|
476
|
+
readme.write_text("# ui\n\n## Overview\n")
|
|
477
|
+
description = "I don't see any file names or symbol names provided"
|
|
478
|
+
|
|
479
|
+
# Same branch order as cli_scan._enrich_directories_with_ai:
|
|
480
|
+
if not description:
|
|
481
|
+
mark_enrichment_status(readme, "failed", reason="empty AI response")
|
|
482
|
+
elif looks_like_refusal(description):
|
|
483
|
+
mark_enrichment_status(readme, "failed", reason="ai-refused")
|
|
484
|
+
else:
|
|
485
|
+
inject_blockquote(readme, description)
|
|
486
|
+
mark_enrichment_status(readme, "ok")
|
|
487
|
+
|
|
488
|
+
content = readme.read_text()
|
|
489
|
+
assert "<!-- enrichment: failed (reason: ai-refused) -->" in content
|
|
490
|
+
assert "<!-- enrichment: ok -->" not in content
|
|
491
|
+
# Blockquote MUST NOT be injected — refusal text is not a description.
|
|
492
|
+
assert "I don't see" not in content
|
|
@@ -56,6 +56,71 @@ class TestParserInstallGuidance:
|
|
|
56
56
|
assert guidance["missing"] == []
|
|
57
57
|
assert guidance["installed"] == []
|
|
58
58
|
|
|
59
|
+
def test_typescript_javascript_are_known_to_parser_map(self):
|
|
60
|
+
"""Regression for GH #86 (4a).
|
|
61
|
+
|
|
62
|
+
``PARSER_PACKAGES`` used to enumerate only python/php/java, even
|
|
63
|
+
though scanner gained TS/JS parsers (#73) and the parser modules
|
|
64
|
+
exist under ``src/codeindex/parsers/typescript/`` and
|
|
65
|
+
``.../javascript/``. Result: ``init --yes`` on a TS project
|
|
66
|
+
reported ``Warning: Missing parsers for: javascript, typescript``
|
|
67
|
+
even though ``pipx inject ai-codeindex tree-sitter-{typescript,
|
|
68
|
+
javascript}`` confirmed the packages were already installed.
|
|
69
|
+
|
|
70
|
+
With the fix, TS/JS must be detected as installed in dev/CI
|
|
71
|
+
(where ``[all]`` extra is installed via ``pip install -e .[dev,all]``).
|
|
72
|
+
"""
|
|
73
|
+
assert check_parser_installed("typescript") is True
|
|
74
|
+
assert check_parser_installed("javascript") is True
|
|
75
|
+
|
|
76
|
+
guidance = get_parser_install_guidance(["typescript", "javascript"])
|
|
77
|
+
assert "typescript" in guidance["installed"]
|
|
78
|
+
assert "javascript" in guidance["installed"]
|
|
79
|
+
assert "typescript" not in guidance["missing"]
|
|
80
|
+
assert "javascript" not in guidance["missing"]
|
|
81
|
+
|
|
82
|
+
def test_install_command_uses_pipx_inject_not_pip_install(self):
|
|
83
|
+
"""Regression for GH #86 (4b).
|
|
84
|
+
|
|
85
|
+
The hint used to be ``pip install ai-codeindex[<langs>]`` — contradicts
|
|
86
|
+
the entire documented install path (``pipx install ai-codeindex`` is the
|
|
87
|
+
recommended path per CLAUDE.md / README / both hooks & index SKILL).
|
|
88
|
+
Worse: ``pip install`` into a pipx-managed env doesn't work cleanly,
|
|
89
|
+
so the hint actively misleads.
|
|
90
|
+
|
|
91
|
+
Force a missing parser by asking for an unknown language; assert the
|
|
92
|
+
hint now uses ``pipx inject``.
|
|
93
|
+
"""
|
|
94
|
+
guidance = get_parser_install_guidance(["fortran"])
|
|
95
|
+
assert "install_command" in guidance
|
|
96
|
+
cmd = guidance["install_command"]
|
|
97
|
+
assert cmd.startswith("pipx inject ai-codeindex"), (
|
|
98
|
+
f"Install hint must point to pipx (not pip install); got: {cmd!r}"
|
|
99
|
+
)
|
|
100
|
+
assert "pip install" not in cmd, (
|
|
101
|
+
f"Install hint still mentions `pip install` — contradicts pipx-based "
|
|
102
|
+
f"recommended path (GH #86 4b). Got: {cmd!r}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def test_parser_package_map_covers_scanner_supported_set(self):
|
|
106
|
+
"""Structural drift guard. ``PARSER_PACKAGES`` (used to validate
|
|
107
|
+
installed parsers + build install hints) must cover every language
|
|
108
|
+
``scanner.LANGUAGE_EXTENSIONS`` knows how to scan — otherwise a
|
|
109
|
+
language can be detected by ``init`` (#73) and scanned by the
|
|
110
|
+
runtime, while the parser-presence check silently fails for it,
|
|
111
|
+
re-introducing the GH #86 false-positive warning class."""
|
|
112
|
+
from codeindex.init_wizard import PARSER_PACKAGES
|
|
113
|
+
from codeindex.scanner import LANGUAGE_EXTENSIONS as SCAN_EXT
|
|
114
|
+
|
|
115
|
+
missing = set(SCAN_EXT.keys()) - set(PARSER_PACKAGES.keys())
|
|
116
|
+
assert not missing, (
|
|
117
|
+
f"init_wizard.PARSER_PACKAGES is missing languages that "
|
|
118
|
+
f"scanner.py knows how to scan: {sorted(missing)}. This is the "
|
|
119
|
+
f"drift class that caused GH #86 — the parser-installed check "
|
|
120
|
+
f"silently returns False for these and `init` warns about "
|
|
121
|
+
f"\"missing parsers\" even when they're installed."
|
|
122
|
+
)
|
|
123
|
+
|
|
59
124
|
|
|
60
125
|
class TestInitWizardPostMessage:
|
|
61
126
|
"""Tests for updated post-init messages (Story 19.2)."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|