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.
Files changed (418) hide show
  1. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.gitignore +1 -0
  2. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/CHANGELOG.md +28 -0
  3. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/PKG-INFO +2 -2
  4. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/README.md +1 -1
  5. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/planning/ROADMAP.md +2 -2
  6. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/pyproject.toml +1 -1
  7. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/README_AI.md +11 -11
  8. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_hooks.py +54 -2
  9. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_scan.py +68 -10
  10. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/enricher.py +81 -3
  11. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/init_wizard.py +16 -3
  12. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/README_AI.md +2 -2
  13. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_hooks.py +116 -0
  14. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_enricher.py +127 -0
  15. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_enricher_integration.py +30 -0
  16. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_detection.py +65 -0
  17. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.editorconfig +0 -0
  18. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/ISSUE_TEMPLATE/bug.md +0 -0
  19. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  20. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/ISSUE_TEMPLATE/enhancement.md +0 -0
  21. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/ISSUE_TEMPLATE/epic.md +0 -0
  22. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/ISSUE_TEMPLATE/feature.md +0 -0
  23. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/workflows/ci.yml +0 -0
  24. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.github/workflows/publish.yml +0 -0
  25. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/.gitignore +0 -0
  26. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/memories/design_philosophy.md +0 -0
  27. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/memories/development_workflow.md +0 -0
  28. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/memories/project_overview.md +0 -0
  29. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/memories/release_automation.md +0 -0
  30. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/.serena/memories/suggested_commands.md +0 -0
  31. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/CLAUDE.md +0 -0
  32. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/CODE_OF_CONDUCT.md +0 -0
  33. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/CONTRIBUTING.md +0 -0
  34. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/FOR_LOOMGRAPH.md +0 -0
  35. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/LICENSE +0 -0
  36. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/Makefile +0 -0
  37. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/PROJECT_SYMBOLS.md +0 -0
  38. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/README_AI.md +0 -0
  39. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/README_zh.md +0 -0
  40. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/SECURITY.md +0 -0
  41. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/.gitignore +0 -0
  42. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/Makefile +0 -0
  43. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/README.md +0 -0
  44. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/grade.py +0 -0
  45. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/questions.yaml.example +0 -0
  46. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/report.py +0 -0
  47. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/run_bench.py +0 -0
  48. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/bench/targets.yaml.example +0 -0
  49. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/README.md +0 -0
  50. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/001-use-tree-sitter-for-parsing.md +0 -0
  51. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/002-external-ai-cli-integration.md +0 -0
  52. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/003-add-swift-objc-support.md +0 -0
  53. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/004-automatic-claude-md-update.md +0 -0
  54. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/005-navigation-disclaimer-and-readme-size-cap.md +0 -0
  55. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/adr/006-distribution-architecture-split.md +0 -0
  56. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/design/document-aggregation.md +0 -0
  57. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/design/initial-design.md +0 -0
  58. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/design/kiss-universal-description.md +0 -0
  59. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/design/parallel-strategy.md +0 -0
  60. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/architecture/design-philosophy.md +0 -0
  61. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/benchmark/2026-05-readme-impact.md +0 -0
  62. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/QUICK_START_RELEASE.md +0 -0
  63. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/claude-code-adoption-guide.md +0 -0
  64. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/claude-code-adoption-guide.zh.md +0 -0
  65. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/gitflow-workflow.md +0 -0
  66. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/github-issue-quick-reference.md +0 -0
  67. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/package-naming.md +0 -0
  68. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/pre-release-checklist.md +0 -0
  69. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/setup.md +0 -0
  70. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/team-workflow-guide.md +0 -0
  71. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/development/test-architecture.md +0 -0
  72. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/evaluation/before-after/README.md +0 -0
  73. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/evaluation/case-studies/php-payment-project.md +0 -0
  74. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/evaluation/loomgraph-efficiency-comparison.md +0 -0
  75. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/advanced-usage.md +0 -0
  76. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/claude-code-integration.md +0 -0
  77. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/configuration.md +0 -0
  78. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/contributing.md +0 -0
  79. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/getting-started.md +0 -0
  80. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/git-hooks-integration.md +0 -0
  81. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/json-output-integration.md +0 -0
  82. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/guides/loomgraph-integration.md +0 -0
  83. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/planning/README.md +0 -0
  84. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/planning/executive-summary.md +0 -0
  85. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/README.md +0 -0
  86. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.10.0.md +0 -0
  87. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.12.0.md +0 -0
  88. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.12.1.md +0 -0
  89. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.14.0.md +0 -0
  90. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.15.0.md +0 -0
  91. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.17.0.md +0 -0
  92. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.17.2.md +0 -0
  93. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.17.3.md +0 -0
  94. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.18.0.md +0 -0
  95. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.19.0.md +0 -0
  96. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.2.0.md +0 -0
  97. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.20.0.md +0 -0
  98. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.23.1.md +0 -0
  99. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.23.2.md +0 -0
  100. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.24.0.md +0 -0
  101. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.25.0.md +0 -0
  102. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.3.0.md +0 -0
  103. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.3.1.md +0 -0
  104. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.3.2.md +0 -0
  105. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.4.0.md +0 -0
  106. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.5.0-beta1.md +0 -0
  107. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.7.0.md +0 -0
  108. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.8.0.md +0 -0
  109. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/docs/releases/RELEASE_NOTES_v0.9.0.md +0 -0
  110. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/CLAUDE.md.php-project +0 -0
  111. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/CLAUDE.md.template +0 -0
  112. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/README.md +0 -0
  113. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/README_AI.md +0 -0
  114. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/ai-integration-guide.md +0 -0
  115. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/frameworks/README_AI.md +0 -0
  116. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/frameworks/template/README.md +0 -0
  117. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/frameworks/template/README_AI.md +0 -0
  118. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/frameworks/template/test_template_extractor.py +0 -0
  119. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/frameworks/template/yourframework_extractor.py +0 -0
  120. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/loomgraph_output.json +0 -0
  121. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/loomgraph_php_output.json +0 -0
  122. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/loomgraph_sample.php +0 -0
  123. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/loomgraph_sample.py +0 -0
  124. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/parse_integration_example.sh +0 -0
  125. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/examples/print_env.py +0 -0
  126. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/hooks/README.md +0 -0
  127. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/hooks/templates/post-commit-update-logic.sh +0 -0
  128. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/hooks/templates/post-commit-v4 +0 -0
  129. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/swift-objc-support-analysis.md +0 -0
  130. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/swift-poc-summary.md +0 -0
  131. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/tech-debt-codeindex-v2.md +0 -0
  132. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/tech-debt-codeindex.md +0 -0
  133. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/tech-debt-loomgraph-v2.md +0 -0
  134. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/tech-debt-loomgraph.md +0 -0
  135. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/reports/workflow-comparison.md +0 -0
  136. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/README.md +0 -0
  137. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/README_AI.md +0 -0
  138. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/bump_version.sh +0 -0
  139. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/check_docs_release.py +0 -0
  140. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/check_version_consistency.py +0 -0
  141. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/close-epic9-issues.sh +0 -0
  142. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/diagnose_ai_failures.py +0 -0
  143. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/hooks/hook-common.sh +0 -0
  144. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/hooks/pre-push +0 -0
  145. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/legacy/PROJECT_INDEX.json +0 -0
  146. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/legacy/README.md +0 -0
  147. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/legacy/hierarchical_strategy.py +0 -0
  148. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/pre_release_check.sh +0 -0
  149. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/release.sh +0 -0
  150. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/test_hook_e2e.sh +0 -0
  151. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/scripts/validate_php_project.py +0 -0
  152. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/skills/README.md +0 -0
  153. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/skills/create.sh +0 -0
  154. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/skills/install.sh +0 -0
  155. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/skills/src/mo-arch/SKILL.md +0 -0
  156. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/skills/src/mo-index/SKILL.md +0 -0
  157. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/README_AI.md +0 -0
  158. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/__init__.py +0 -0
  159. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/adaptive_config.py +0 -0
  160. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/adaptive_selector.py +0 -0
  161. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/ai_helper.py +0 -0
  162. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/claude_md.py +0 -0
  163. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli.py +0 -0
  164. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_claude_md.py +0 -0
  165. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_common.py +0 -0
  166. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_config.py +0 -0
  167. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_config_commands.py +0 -0
  168. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_docs.py +0 -0
  169. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_parse.py +0 -0
  170. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_symbols.py +0 -0
  171. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/cli_tech_debt.py +0 -0
  172. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/config.py +0 -0
  173. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/config_help.py +0 -0
  174. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/directory_tree.py +0 -0
  175. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/docstring_processor.py +0 -0
  176. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/doctor.py +0 -0
  177. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/errors.py +0 -0
  178. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/extractors/README_AI.md +0 -0
  179. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/extractors/__init__.py +0 -0
  180. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/extractors/spring.py +0 -0
  181. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/extractors/thinkphp.py +0 -0
  182. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/file_classifier.py +0 -0
  183. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/framework_detect.py +0 -0
  184. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/hierarchical.py +0 -0
  185. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/hooks.py +0 -0
  186. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/incremental.py +0 -0
  187. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/invoker.py +0 -0
  188. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/objc_association.py +0 -0
  189. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parallel.py +0 -0
  190. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parser.py +0 -0
  191. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/README_AI.md +0 -0
  192. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/__init__.py +0 -0
  193. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/base.py +0 -0
  194. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/README_AI.md +0 -0
  195. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/__init__.py +0 -0
  196. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/calls.py +0 -0
  197. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/imports.py +0 -0
  198. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/inheritance.py +0 -0
  199. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java/symbols.py +0 -0
  200. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/java_parser.py +0 -0
  201. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/README_AI.md +0 -0
  202. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/__init__.py +0 -0
  203. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/calls.py +0 -0
  204. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/imports.py +0 -0
  205. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/inheritance.py +0 -0
  206. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/objc/symbols.py +0 -0
  207. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/README_AI.md +0 -0
  208. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/__init__.py +0 -0
  209. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/calls.py +0 -0
  210. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/imports.py +0 -0
  211. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/inheritance.py +0 -0
  212. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/php/symbols.py +0 -0
  213. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/README_AI.md +0 -0
  214. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/__init__.py +0 -0
  215. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/calls.py +0 -0
  216. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/imports.py +0 -0
  217. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/inheritance.py +0 -0
  218. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/python/symbols.py +0 -0
  219. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/README_AI.md +0 -0
  220. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/__init__.py +0 -0
  221. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/calls.py +0 -0
  222. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/imports.py +0 -0
  223. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/inheritance.py +0 -0
  224. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/swift/symbols.py +0 -0
  225. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/README_AI.md +0 -0
  226. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/__init__.py +0 -0
  227. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/calls.py +0 -0
  228. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/imports.py +0 -0
  229. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/inheritance.py +0 -0
  230. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/typescript/symbols.py +0 -0
  231. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/parsers/utils.py +0 -0
  232. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/route_extractor.py +0 -0
  233. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/route_registry.py +0 -0
  234. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/scanner.py +0 -0
  235. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/semantic_extractor.py +0 -0
  236. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/skill_helpers.py +0 -0
  237. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/smart_writer.py +0 -0
  238. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/symbol_index.py +0 -0
  239. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/symbol_scorer.py +0 -0
  240. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/tech_debt.py +0 -0
  241. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/tech_debt_formatters.py +0 -0
  242. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/templates/README_AI.md +0 -0
  243. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/templates/__init__.py +0 -0
  244. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/templates/claude_md_core.md +0 -0
  245. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/test_smells.py +0 -0
  246. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writer.py +0 -0
  247. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/README_AI.md +0 -0
  248. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/__init__.py +0 -0
  249. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/core.py +0 -0
  250. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/detailed_generator.py +0 -0
  251. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/navigation_generator.py +0 -0
  252. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/overview_generator.py +0 -0
  253. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/src/codeindex/writers/utils.py +0 -0
  254. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/generator.py +0 -0
  255. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/scripts/analyze_legacy_tests.py +0 -0
  256. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/scripts/compare_coverage.py +0 -0
  257. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/scripts/compare_test_results.py +0 -0
  258. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/specs/java.yaml +0 -0
  259. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/specs/php.yaml +0 -0
  260. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/specs/python.yaml +0 -0
  261. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/test_generator/templates/inheritance_test.py.j2 +0 -0
  262. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/__init__.py +0 -0
  263. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/conftest.py +0 -0
  264. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/extractors/README_AI.md +0 -0
  265. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/extractors/__init__.py +0 -0
  266. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/extractors/test_spring.py +0 -0
  267. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/extractors/test_thinkphp.py +0 -0
  268. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/extractors/test_thinkphp_description.py +0 -0
  269. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/README.md +0 -0
  270. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/cli_scan_defaults.feature +0 -0
  271. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/help_system.feature +0 -0
  272. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/init_wizard.feature +0 -0
  273. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/symbol_overload_detection.feature +0 -0
  274. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/tech_debt_detection.feature +0 -0
  275. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/features/tech_debt_reporting.feature +0 -0
  276. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/README_AI.md +0 -0
  277. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/Controller.php +0 -0
  278. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/README_AI.md +0 -0
  279. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/Service.java +0 -0
  280. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/Simple.java +0 -0
  281. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/broken.py +0 -0
  282. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/complete.py +0 -0
  283. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/service.ts +0 -0
  284. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/simple.php +0 -0
  285. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/simple.py +0 -0
  286. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/cli_parse/unsupported.txt +0 -0
  287. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/enum.java +0 -0
  288. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/generics.java +0 -0
  289. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/imports.java +0 -0
  290. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/interface.java +0 -0
  291. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/record.java +0 -0
  292. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/sealed_class.java +0 -0
  293. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/simple_class.java +0 -0
  294. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring/Application.java +0 -0
  295. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring/User.java +0 -0
  296. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring/UserController.java +0 -0
  297. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring/UserRepository.java +0 -0
  298. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring/UserService.java +0 -0
  299. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/java/spring_controller.java +0 -0
  300. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/typescript/app.js +0 -0
  301. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/typescript/component.tsx +0 -0
  302. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/fixtures/typescript/service.ts +0 -0
  303. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/README.md +0 -0
  304. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/README_AI.md +0 -0
  305. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/test_hierarchical_test/level1/file1.py +0 -0
  306. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/test_hierarchical_test/level1/level2a/file2.py +0 -0
  307. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/test_hierarchical_test/level1/level2a/level3/file4.py +0 -0
  308. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/test_hierarchical_test/level1/level2b/file3.py +0 -0
  309. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/legacy/test_hierarchy_simple.py +0 -0
  310. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_adaptive_config.py +0 -0
  311. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_adaptive_selector.py +0 -0
  312. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_ai_helper.py +0 -0
  313. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_backward_compatibility.py +0 -0
  314. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_call_integration.py +0 -0
  315. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_claude_md.py +0 -0
  316. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_claude_md_injection.py +0 -0
  317. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_config_gitignore.py +0 -0
  318. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_debt_scan.py +0 -0
  319. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_docstring_options.py +0 -0
  320. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_json.py +0 -0
  321. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_parse.py +0 -0
  322. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_scan_defaults_bdd.py +0 -0
  323. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_cli_tech_debt.py +0 -0
  324. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_config_adaptive.py +0 -0
  325. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_dataclass_structure.py +0 -0
  326. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_directory_tree.py +0 -0
  327. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_docstring_config.py +0 -0
  328. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_docstring_processor.py +0 -0
  329. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_doctor.py +0 -0
  330. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_error_handling.py +0 -0
  331. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_file_classifier.py +0 -0
  332. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_help_system_bdd.py +0 -0
  333. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_hook_post_commit.py +0 -0
  334. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_hooks.py +0 -0
  335. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_hooks_config.py +0 -0
  336. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_hooks_integration.py +0 -0
  337. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_init_minimal_scope.py +0 -0
  338. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_init_wizard_bdd.py +0 -0
  339. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_integration_swift_objc.py +0 -0
  340. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_annotations.py +0 -0
  341. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_calls.py +0 -0
  342. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_edge_cases.py +0 -0
  343. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_error_recovery.py +0 -0
  344. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_generic_bounds.py +0 -0
  345. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_inheritance.py +0 -0
  346. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_lambda.py +0 -0
  347. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_lombok.py +0 -0
  348. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_module.py +0 -0
  349. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_parser.py +0 -0
  350. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_spring.py +0 -0
  351. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_java_throws.py +0 -0
  352. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_json_output.py +0 -0
  353. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_lazy_loading.py +0 -0
  354. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_list_dirs_diagnostic.py +0 -0
  355. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_loomgraph_integration.py +0 -0
  356. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_objc_association_utils.py +0 -0
  357. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parallel_scan.py +0 -0
  358. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser.py +0 -0
  359. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_objc_association.py +0 -0
  360. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_objc_basic.py +0 -0
  361. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_objc_bridging.py +0 -0
  362. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_objc_categories.py +0 -0
  363. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_docstrings.py +0 -0
  364. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_extensions.py +0 -0
  365. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_generics.py +0 -0
  366. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_inheritance.py +0 -0
  367. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_integration.py +0 -0
  368. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_poc.py +0 -0
  369. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_properties.py +0 -0
  370. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_property_wrappers.py +0 -0
  371. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_protocols.py +0 -0
  372. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_parser_swift_signatures.py +0 -0
  373. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_calls.py +0 -0
  374. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_comment_extraction.py +0 -0
  375. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_docstring_extraction.py +0 -0
  376. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_import_alias.py +0 -0
  377. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_inheritance.py +0 -0
  378. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_php_loomgraph_integration.py +0 -0
  379. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_project_index_semantic.py +0 -0
  380. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_python_calls.py +0 -0
  381. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_python_docstring_description.py +0 -0
  382. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_python_import_alias.py +0 -0
  383. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_python_inheritance.py +0 -0
  384. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_route_extractor.py +0 -0
  385. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_route_info.py +0 -0
  386. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_route_registry.py +0 -0
  387. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_route_table_description.py +0 -0
  388. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_route_table_display.py +0 -0
  389. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_scanall_auto_ai.py +0 -0
  390. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_scanner_passthrough.py +0 -0
  391. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_semantic_extractor.py +0 -0
  392. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_skill_helpers.py +0 -0
  393. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer.py +0 -0
  394. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer_adaptive.py +0 -0
  395. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer_docstring.py +0 -0
  396. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer_enriched.py +0 -0
  397. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer_integration.py +0 -0
  398. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_smart_writer_semantic.py +0 -0
  399. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_story_4_4_integration.py +0 -0
  400. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_symbol_overload.py +0 -0
  401. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_symbol_scorer.py +0 -0
  402. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_bdd.py +0 -0
  403. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_detector.py +0 -0
  404. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_formatters.py +0 -0
  405. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_ios.py +0 -0
  406. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_java.py +0 -0
  407. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_tech_debt_reporter.py +0 -0
  408. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_test_smells.py +0 -0
  409. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_thinkphp_route_extractor.py +0 -0
  410. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_typescript_integration.py +0 -0
  411. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_typescript_parser.py +0 -0
  412. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_windows_path_optimization.py +0 -0
  413. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/test_writer_preserves_enrichment.py +0 -0
  414. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/writers/README_AI.md +0 -0
  415. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/writers/__init__.py +0 -0
  416. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/writers/test_generators.py +0 -0
  417. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/tests/writers/test_utils.py +0 -0
  418. {ai_codeindex-0.26.0 → ai_codeindex-0.26.2}/uv.lock +0 -0
@@ -36,3 +36,4 @@ htmlcov/
36
36
 
37
37
  # Validation reports (generated)
38
38
  scripts/validation/reports/*.md
39
+ *.code-workspace
@@ -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.0
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.25.0
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.25.0
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.25.0
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.25.0
537
+ **Current Version**: v0.26.2
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ai-codeindex"
3
- version = "0.26.0"
3
+ version = "0.26.2"
4
4
  description = "AI-native code indexing tool for large codebases"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -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-01T11:56:26.178371 -->
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**: 570
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 6 more symbols_
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 2 more symbols_
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, curr
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
- LAST_COMMIT_FILES=$(git diff-tree --no-commit-id --name-only -r HEAD)
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
- # Prefer tree-derived context (subdir names only) to avoid the
718
- # injection chain through markdown-embedded AI descriptions.
719
- # Fall back to README parsing only for dirs without indexed children
720
- # (rare for enrichable navigation/overview dirs).
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 = build_safe_subdir_context(child_dirs)
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 and symbol names above, write a concise "
152
- "functional description of this module (30 chars or less). "
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 symbol names."
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 package name
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
- extras = ",".join(missing)
150
- result["install_command"] = f"pip install ai-codeindex[{extras}]"
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-01T11:59:55.553144 -->
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**: 2148
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