cortexcode 0.8.1__tar.gz → 0.9.0__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 (179) hide show
  1. {cortexcode-0.8.1 → cortexcode-0.9.0}/PKG-INFO +18 -1
  2. {cortexcode-0.8.1 → cortexcode-0.9.0}/README.md +16 -0
  3. cortexcode-0.9.0/cortexcode/cli/cli_index.py +609 -0
  4. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_servers.py +100 -37
  5. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/context/context_query.py +35 -7
  6. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexer.py +45 -1
  7. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/main.py +5 -1
  8. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/mcp/mcp_registry.py +1 -1
  9. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode.egg-info/PKG-INFO +18 -1
  10. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode.egg-info/requires.txt +1 -0
  11. {cortexcode-0.8.1 → cortexcode-0.9.0}/pyproject.toml +2 -2
  12. cortexcode-0.8.1/cortexcode/cli/cli_index.py +0 -110
  13. {cortexcode-0.8.1 → cortexcode-0.9.0}/LICENSE +0 -0
  14. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/__init__.py +0 -0
  15. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/advanced_analysis/__init__.py +0 -0
  16. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/advanced_analysis/advanced_analysis.py +0 -0
  17. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/advanced_analysis/advanced_analysis_cycles.py +0 -0
  18. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/advanced_analysis/advanced_analysis_docs.py +0 -0
  19. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/advanced_analysis/advanced_analysis_duplicates.py +0 -0
  20. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/advanced_analysis/advanced_analysis_endpoints.py +0 -0
  21. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/advanced_analysis/advanced_analysis_search.py +0 -0
  22. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/advanced_analysis/advanced_analysis_security.py +0 -0
  23. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/advanced_analysis.py +0 -0
  24. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/__init__.py +0 -0
  25. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/config.py +0 -0
  26. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/doc_cache.py +0 -0
  27. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/doc_generator.py +0 -0
  28. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/doc_lookup.py +0 -0
  29. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/doc_models.py +0 -0
  30. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/explainer.py +0 -0
  31. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/llm_client.py +0 -0
  32. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/page_generator.py +0 -0
  33. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/prompts.py +0 -0
  34. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/ai_docs/report_runner.py +0 -0
  35. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/analysis/__init__.py +0 -0
  36. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/analysis/analysis_complexity.py +0 -0
  37. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/analysis/analysis_dead_code.py +0 -0
  38. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/analysis/analysis_impact.py +0 -0
  39. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/analysis.py +0 -0
  40. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/__init__.py +0 -0
  41. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_ai_docs.py +0 -0
  42. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_bundle.py +0 -0
  43. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_complexity.py +0 -0
  44. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_config.py +0 -0
  45. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_context.py +0 -0
  46. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_dashboard.py +0 -0
  47. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_dead_code.py +0 -0
  48. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_diagrams.py +0 -0
  49. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_diff.py +0 -0
  50. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_docs.py +0 -0
  51. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_explain.py +0 -0
  52. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_find.py +0 -0
  53. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_githook.py +0 -0
  54. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_impact.py +0 -0
  55. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_jobs.py +0 -0
  56. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_package.py +0 -0
  57. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_report.py +0 -0
  58. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_scan.py +0 -0
  59. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_search.py +0 -0
  60. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_shell.py +0 -0
  61. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_stats.py +0 -0
  62. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_support.py +0 -0
  63. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_trace.py +0 -0
  64. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_watch.py +0 -0
  65. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_wiki.py +0 -0
  66. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/cli/cli_workspace.py +0 -0
  67. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/config.py +0 -0
  68. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/context/__init__.py +0 -0
  69. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/context/context_format.py +0 -0
  70. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/context/context_tokens.py +0 -0
  71. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/context.py +0 -0
  72. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/dashboard.py +0 -0
  73. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/__init__.py +0 -0
  74. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/architecture.py +0 -0
  75. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/call_graph.py +0 -0
  76. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/class_diagram.py +0 -0
  77. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/dependencies.py +0 -0
  78. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/directory_tree.py +0 -0
  79. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/entities.py +0 -0
  80. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/file_tree.py +0 -0
  81. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/imports.py +0 -0
  82. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/save.py +0 -0
  83. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/sequence.py +0 -0
  84. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/state.py +0 -0
  85. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/diagrams/utils.py +0 -0
  86. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/docs/__init__.py +0 -0
  87. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/docs/diagrams.py +0 -0
  88. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/docs/generator.py +0 -0
  89. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/docs/html_generators.py +0 -0
  90. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/docs/javascript.py +0 -0
  91. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/docs/javascript_sections.py +0 -0
  92. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/docs/templates.py +0 -0
  93. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/docs.py +0 -0
  94. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/git_diff.py +0 -0
  95. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/__init__.py +0 -0
  96. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/build.py +0 -0
  97. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/calls.py +0 -0
  98. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/config.py +0 -0
  99. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/defaults.py +0 -0
  100. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/dispatch.py +0 -0
  101. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/entities.py +0 -0
  102. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/extensions.py +0 -0
  103. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/extractor_mixin.py +0 -0
  104. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/extractors/__init__.py +0 -0
  105. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/extractors/csharp.py +0 -0
  106. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/extractors/dart.py +0 -0
  107. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/extractors/generic.py +0 -0
  108. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/extractors/java.py +0 -0
  109. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/extractors/javascript.py +0 -0
  110. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/extractors/kotlin.py +0 -0
  111. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/extractors/swift.py +0 -0
  112. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/filtering.py +0 -0
  113. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/frameworks.py +0 -0
  114. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/gitignore.py +0 -0
  115. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/imports_exports.py +0 -0
  116. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/incremental.py +0 -0
  117. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/languages.py +0 -0
  118. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/metadata.py +0 -0
  119. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/nodes.py +0 -0
  120. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/output.py +0 -0
  121. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/params.py +0 -0
  122. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/parsers.py +0 -0
  123. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/pipeline.py +0 -0
  124. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/profile.py +0 -0
  125. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/resolution.py +0 -0
  126. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/routes.py +0 -0
  127. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/session.py +0 -0
  128. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/storage.py +0 -0
  129. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/indexing/walk.py +0 -0
  130. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/knowledge/__init__.py +0 -0
  131. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/knowledge/build.py +0 -0
  132. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/knowledge/citations.py +0 -0
  133. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/knowledge/concepts.py +0 -0
  134. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/knowledge/models.py +0 -0
  135. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/knowledge/snippets.py +0 -0
  136. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/knowledge/usage.py +0 -0
  137. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/lsp_server.py +0 -0
  138. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/mcp/__init__.py +0 -0
  139. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/mcp/mcp_protocol.py +0 -0
  140. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/mcp/mcp_server.py +0 -0
  141. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/mcp/mcp_tool_handlers.py +0 -0
  142. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/mcp/mcp_transport.py +0 -0
  143. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/performance/__init__.py +0 -0
  144. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/performance/performance_config.py +0 -0
  145. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/performance/performance_index_storage.py +0 -0
  146. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/performance/performance_preview.py +0 -0
  147. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/performance.py +0 -0
  148. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/plugins.py +0 -0
  149. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/__init__.py +0 -0
  150. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/html/__init__.py +0 -0
  151. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/html/dashboard.py +0 -0
  152. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/html/dashboard_fragments.py +0 -0
  153. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/html/view_model.py +0 -0
  154. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/markdown/__init__.py +0 -0
  155. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/markdown/api.py +0 -0
  156. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/markdown/flows.py +0 -0
  157. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/markdown/insights.py +0 -0
  158. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/markdown/readme.py +0 -0
  159. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/markdown/structure.py +0 -0
  160. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/markdown/tech.py +0 -0
  161. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/site/__init__.py +0 -0
  162. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/site/generator.py +0 -0
  163. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/reports/site/viz.py +0 -0
  164. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/semantic_search.py +0 -0
  165. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/terminal/__init__.py +0 -0
  166. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/terminal/analysis.py +0 -0
  167. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/terminal/completion.py +0 -0
  168. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/terminal/headers.py +0 -0
  169. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/terminal/prompts.py +0 -0
  170. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/terminal/reports.py +0 -0
  171. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/terminal/stats.py +0 -0
  172. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/vuln_scan.py +0 -0
  173. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/watcher.py +0 -0
  174. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode/workspace.py +0 -0
  175. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode.egg-info/SOURCES.txt +0 -0
  176. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode.egg-info/dependency_links.txt +0 -0
  177. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode.egg-info/entry_points.txt +0 -0
  178. {cortexcode-0.8.1 → cortexcode-0.9.0}/cortexcode.egg-info/top_level.txt +0 -0
  179. {cortexcode-0.8.1 → cortexcode-0.9.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cortexcode
3
- Version: 0.8.1
3
+ Version: 0.9.0
4
4
  Summary: Lightweight code indexing for AI assistants — save 90%+ tokens with structured context
5
5
  Author-email: Naveen <naveen_joshi07@outlook.com>
6
6
  License: MIT
@@ -32,6 +32,7 @@ Requires-Dist: tree-sitter-rust>=0.23.0
32
32
  Requires-Dist: tree-sitter-java>=0.23.0
33
33
  Requires-Dist: tree-sitter-c-sharp>=0.23.0
34
34
  Requires-Dist: click>=8.1.0
35
+ Requires-Dist: questionary>=2.0.1
35
36
  Requires-Dist: watchdog>=4.0.0
36
37
  Requires-Dist: rich>=13.0.0
37
38
  Requires-Dist: pyyaml>=6.0.0
@@ -117,6 +118,22 @@ cortexcode context "handleAuth"
117
118
  cortexcode docs --open
118
119
  ```
119
120
 
121
+ ### Post-Index Wizard
122
+
123
+ After running `cortexcode index`, an interactive wizard can guide you through generating outputs:
124
+
125
+ ```bash
126
+ cortexcode index # Run index, then wizard prompts
127
+ cortexcode index --force-wizard # Force wizard in non-TTY mode
128
+ cortexcode index --no-post-index-wizard # Skip wizard
129
+ ```
130
+
131
+ **Wizard features:**
132
+ - Multi-select checkbox for docs, diagrams, AI docs, CodeWiki, reports, visualization, dashboard, MCP setup
133
+ - Smart recommendations based on detected project shape
134
+ - Follow-up prompts for diagram types, AI doc types, wiki options
135
+ - Preference persistence — saves your choices for future runs
136
+
120
137
  ## Features
121
138
 
122
139
  ### Multi-Language AST Indexing
@@ -65,6 +65,22 @@ cortexcode context "handleAuth"
65
65
  cortexcode docs --open
66
66
  ```
67
67
 
68
+ ### Post-Index Wizard
69
+
70
+ After running `cortexcode index`, an interactive wizard can guide you through generating outputs:
71
+
72
+ ```bash
73
+ cortexcode index # Run index, then wizard prompts
74
+ cortexcode index --force-wizard # Force wizard in non-TTY mode
75
+ cortexcode index --no-post-index-wizard # Skip wizard
76
+ ```
77
+
78
+ **Wizard features:**
79
+ - Multi-select checkbox for docs, diagrams, AI docs, CodeWiki, reports, visualization, dashboard, MCP setup
80
+ - Smart recommendations based on detected project shape
81
+ - Follow-up prompts for diagram types, AI doc types, wiki options
82
+ - Preference persistence — saves your choices for future runs
83
+
68
84
  ## Features
69
85
 
70
86
  ### Multi-Language AST Indexing
@@ -0,0 +1,609 @@
1
+ import json
2
+ import time
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ import click
7
+ from rich import box
8
+ from rich.console import Console
9
+ from rich.panel import Panel
10
+ from rich.progress import BarColumn, Progress, SpinnerColumn, TaskProgressColumn, TextColumn, TimeRemainingColumn
11
+ from rich.table import Table
12
+
13
+
14
+ def _load_questionary():
15
+ try:
16
+ import questionary
17
+ except ImportError:
18
+ return None
19
+ return questionary
20
+
21
+
22
+ def _load_user_config() -> dict:
23
+ config_path = Path.home() / ".cortexcode" / "config.json"
24
+ if not config_path.exists():
25
+ return {}
26
+ try:
27
+ return json.loads(config_path.read_text(encoding="utf-8"))
28
+ except Exception:
29
+ return {}
30
+
31
+
32
+ def _save_user_config(config: dict) -> None:
33
+ config_path = Path.home() / ".cortexcode" / "config.json"
34
+ config_path.parent.mkdir(parents=True, exist_ok=True)
35
+ config_path.write_text(json.dumps(config, indent=2), encoding="utf-8")
36
+
37
+
38
+ def _load_post_index_preferences() -> dict:
39
+ config = _load_user_config()
40
+ prefs = config.get("post_index_wizard", {})
41
+ if isinstance(prefs, dict):
42
+ return prefs
43
+ return {}
44
+
45
+
46
+ def _save_post_index_preferences(preferences: dict) -> None:
47
+ config = _load_user_config()
48
+ config["post_index_wizard"] = preferences
49
+ _save_user_config(config)
50
+
51
+
52
+ def _should_show_post_index_wizard(watch: bool, disabled: bool, force: bool) -> bool:
53
+ if force:
54
+ return True
55
+ preferences = _load_post_index_preferences()
56
+ return not disabled and preferences.get("enabled", True) and not watch and sys.stdin.isatty() and sys.stdout.isatty()
57
+
58
+
59
+ def _prompt_generate_now() -> bool:
60
+ questionary = _load_questionary()
61
+ if questionary:
62
+ answer = questionary.confirm("Generate docs, diagrams, reports, or setup now?", default=False).ask()
63
+ return bool(answer)
64
+ return click.confirm("Generate docs, diagrams, reports, or setup now?", default=False)
65
+
66
+
67
+ def _get_recommended_targets(index_data: dict, preferences: dict) -> list[str]:
68
+ saved_targets = preferences.get("targets")
69
+ if isinstance(saved_targets, list) and saved_targets:
70
+ return saved_targets
71
+
72
+ recommended = ["docs", "diagrams", "report"]
73
+ profile = index_data.get("project_profile", {}) if isinstance(index_data, dict) else {}
74
+ route_count = profile.get("route_count", 0)
75
+ entity_count = profile.get("entity_count", 0)
76
+ files = index_data.get("files", {}) if isinstance(index_data, dict) else {}
77
+ symbol_count = sum(
78
+ len(file_data.get("symbols", [])) if isinstance(file_data, dict) else len(file_data)
79
+ for file_data in files.values()
80
+ )
81
+
82
+ if route_count or entity_count:
83
+ recommended.append("dashboard")
84
+ if 0 < symbol_count <= 500:
85
+ recommended.append("viz")
86
+
87
+ seen = []
88
+ for item in recommended:
89
+ if item not in seen:
90
+ seen.append(item)
91
+ return seen
92
+
93
+
94
+ def _prompt_generation_targets(console: Console, defaults: list[str] | None = None, recommended: list[str] | None = None) -> list[str]:
95
+ core_options = [
96
+ ("docs", "Project docs"),
97
+ ("diagrams", "Mermaid diagrams"),
98
+ ("report", "Interactive terminal report"),
99
+ ("viz", "Interactive graph visualization"),
100
+ ("dashboard", "Live dashboard"),
101
+ ]
102
+ ai_options = [
103
+ ("ai_docs", "AI docs"),
104
+ ("wiki", "CodeWiki"),
105
+ ]
106
+ setup_options = [
107
+ ("mcp_setup", "Configure MCP for your editor"),
108
+ ]
109
+ options = core_options + ai_options + setup_options
110
+ defaults = defaults or []
111
+ recommended = recommended or []
112
+ questionary = _load_questionary()
113
+ if questionary:
114
+ choices = [questionary.Separator("══ Core outputs ══")]
115
+ choices.extend(
116
+ questionary.Choice(
117
+ title=f"{label}{' [recommended]' if value in recommended else ''}",
118
+ value=value,
119
+ checked=value in defaults,
120
+ )
121
+ for value, label in core_options
122
+ )
123
+ choices.append(questionary.Separator("══ AI-powered ══"))
124
+ choices.extend(
125
+ questionary.Choice(
126
+ title=f"{label}{' [recommended]' if value in recommended else ''}",
127
+ value=value,
128
+ checked=value in defaults,
129
+ )
130
+ for value, label in ai_options
131
+ )
132
+ choices.append(questionary.Separator("══ Setup ══"))
133
+ choices.extend(
134
+ questionary.Choice(
135
+ title=f"{label}{' [recommended]' if value in recommended else ''}",
136
+ value=value,
137
+ checked=value in defaults,
138
+ )
139
+ for value, label in setup_options
140
+ )
141
+ selections = questionary.checkbox(
142
+ "Select what to generate",
143
+ choices=choices,
144
+ validate=lambda items: True if items else "Select at least one option.",
145
+ ).ask()
146
+ return selections or []
147
+
148
+ console.print("\n[bold]Select what to generate:[/bold]")
149
+ for idx, (_, label) in enumerate(options, 1):
150
+ suffix = " [recommended]" if options[idx - 1][0] in recommended else ""
151
+ console.print(f" {idx}. {label}{suffix}")
152
+ default_indexes = [str(idx) for idx, (value, _) in enumerate(options, 1) if value in defaults]
153
+ raw_value = click.prompt(
154
+ "Enter choices as comma-separated numbers",
155
+ default=",".join(default_indexes) if default_indexes else "1,2",
156
+ show_default=True,
157
+ )
158
+ selected = []
159
+ for part in raw_value.split(","):
160
+ part = part.strip()
161
+ if not part.isdigit():
162
+ continue
163
+ index = int(part) - 1
164
+ if 0 <= index < len(options):
165
+ selected.append(options[index][0])
166
+ seen = []
167
+ for item in selected:
168
+ if item not in seen:
169
+ seen.append(item)
170
+ return seen
171
+
172
+
173
+ def _prompt_provider(default: str | None = None) -> str:
174
+ from cortexcode.ai_docs.config import get_config
175
+
176
+ provider = default or get_config().provider or "google"
177
+ choices = ["google", "openai", "anthropic", "ollama"]
178
+ questionary = _load_questionary()
179
+ if questionary:
180
+ answer = questionary.select("Choose provider", choices=choices, default=provider).ask()
181
+ return answer or provider
182
+ return click.prompt("Choose provider", type=click.Choice(choices), default=provider, show_choices=True)
183
+
184
+
185
+ def _ensure_provider_access(console: Console, provider: str) -> bool:
186
+ from cortexcode.ai_docs.config import AIConfig, get_api_key, get_config, set_api_key, set_config
187
+
188
+ config = get_config()
189
+ set_config(AIConfig(provider=provider, model=config.model, temperature=config.temperature, max_tokens=config.max_tokens))
190
+
191
+ if provider == "ollama":
192
+ return True
193
+
194
+ if get_api_key(provider):
195
+ return True
196
+
197
+ provider_labels = {
198
+ "google": ("Gemini", "https://aistudio.google.com/apikey"),
199
+ "openai": ("OpenAI", "https://platform.openai.com/api-keys"),
200
+ "anthropic": ("Anthropic", "https://console.anthropic.com/settings/keys"),
201
+ }
202
+ label, url = provider_labels.get(provider, (provider, ""))
203
+ console.print(
204
+ f"\n[yellow]No API key found for {label}.[/yellow]\n"
205
+ f"[dim]Get your key at:[/dim] [cyan]{url}[/cyan]\n"
206
+ )
207
+
208
+ questionary = _load_questionary()
209
+ if questionary:
210
+ api_key = questionary.password(f"Enter your {label} API key (leave blank to skip)").ask() or ""
211
+ else:
212
+ api_key = click.prompt(
213
+ f"Enter your {label} API key (leave blank to skip)",
214
+ default="",
215
+ show_default=False,
216
+ hide_input=True,
217
+ ).strip()
218
+
219
+ if not api_key:
220
+ console.print(f"[dim]Skipped. You can set it later with:[/dim] [cyan]cortexcode config set {provider}_api_key YOUR_KEY[/cyan]\n")
221
+ return False
222
+
223
+ set_api_key(provider, api_key)
224
+ console.print(f"[green]✓[/green] API key saved for {label}.\n")
225
+ return True
226
+
227
+
228
+ def _prompt_report_type(available_reports: list[str], default: str | None = None) -> str:
229
+ questionary = _load_questionary()
230
+ selected_default = default if default in available_reports else (available_reports[0] if available_reports else "overview")
231
+ if questionary:
232
+ answer = questionary.select("Choose report type", choices=available_reports, default=selected_default).ask()
233
+ return answer or selected_default
234
+ return click.prompt(
235
+ "Choose report type",
236
+ type=click.Choice(available_reports),
237
+ default=selected_default,
238
+ show_choices=True,
239
+ )
240
+
241
+
242
+ def _prompt_dashboard_port(default: int) -> int:
243
+ questionary = _load_questionary()
244
+ if questionary:
245
+ answer = questionary.text("Dashboard port", default=str(default), validate=lambda value: value.isdigit() or "Enter a valid port").ask()
246
+ return int(answer or default)
247
+ return int(click.prompt("Dashboard port", default=default, type=int, show_default=True))
248
+
249
+
250
+ def _prompt_diagram_types(defaults: list[str]) -> list[str]:
251
+ diagram_types = ["call_graph", "class", "sequence", "architecture", "imports", "dependencies", "entities", "file_tree"]
252
+ questionary = _load_questionary()
253
+ if questionary:
254
+ selections = questionary.checkbox(
255
+ "Choose diagram types",
256
+ choices=[questionary.Choice(title=item, value=item, checked=item in defaults) for item in diagram_types],
257
+ validate=lambda items: True if items else "Select at least one diagram type.",
258
+ ).ask()
259
+ return selections or defaults
260
+
261
+ raw_value = click.prompt(
262
+ "Choose diagram types (comma-separated)",
263
+ default=",".join(defaults),
264
+ show_default=True,
265
+ )
266
+ values = [item.strip() for item in raw_value.split(",") if item.strip() in diagram_types]
267
+ return values or defaults
268
+
269
+
270
+ def _prompt_ai_doc_types(defaults: list[str]) -> list[str]:
271
+ doc_types = ["overview", "api", "architecture", "flows"]
272
+ questionary = _load_questionary()
273
+ if questionary:
274
+ selections = questionary.checkbox(
275
+ "Choose AI doc types",
276
+ choices=[questionary.Choice(title=item, value=item, checked=item in defaults) for item in doc_types],
277
+ validate=lambda items: True if items else "Select at least one AI doc type.",
278
+ ).ask()
279
+ return selections or defaults
280
+
281
+ raw_value = click.prompt(
282
+ "Choose AI doc types (comma-separated)",
283
+ default=",".join(defaults),
284
+ show_default=True,
285
+ )
286
+ values = [item.strip() for item in raw_value.split(",") if item.strip() in doc_types]
287
+ return values or defaults
288
+
289
+
290
+ def _prompt_confirm(message: str, default: bool) -> bool:
291
+ questionary = _load_questionary()
292
+ if questionary:
293
+ answer = questionary.confirm(message, default=default).ask()
294
+ return bool(answer)
295
+ return click.confirm(message, default=default)
296
+
297
+
298
+ def _prompt_max_modules(default: int) -> int:
299
+ questionary = _load_questionary()
300
+ if questionary:
301
+ answer = questionary.text("Max module pages", default=str(default), validate=lambda value: value.isdigit() or "Enter a valid number").ask()
302
+ return int(answer or default)
303
+ return int(click.prompt("Max module pages", default=default, type=int, show_default=True))
304
+
305
+
306
+ def _prompt_save_preferences() -> bool:
307
+ questionary = _load_questionary()
308
+ if questionary:
309
+ answer = questionary.confirm("Save these choices as defaults for future index runs?", default=True).ask()
310
+ return bool(answer)
311
+ return click.confirm("Save these choices as defaults for future index runs?", default=True)
312
+
313
+
314
+ def _prompt_show_wizard_next_time(default: bool) -> bool:
315
+ questionary = _load_questionary()
316
+ if questionary:
317
+ answer = questionary.confirm("Show this wizard automatically after future index runs?", default=default).ask()
318
+ return bool(answer)
319
+ return click.confirm("Show this wizard automatically after future index runs?", default=default)
320
+
321
+
322
+ def _run_post_index_wizard(console: Console, path: Path, index_data: dict) -> None:
323
+ import webbrowser
324
+
325
+ from cortexcode import indexer
326
+ from cortexcode.cli import handle_ai_docs_command, handle_dashboard_command, handle_diagrams_command, handle_docs_command, handle_wiki_command
327
+ from cortexcode.cli.cli_servers import handle_mcp_setup
328
+ from cortexcode.cli.cli_support import require_ai_doc_generator, require_index_path
329
+ from cortexcode.docs import generate_all_docs
330
+ from cortexcode.docs.diagrams import save_diagrams
331
+ from cortexcode.dashboard import DashboardServer
332
+ from cortexcode.reports.site.viz import generate_viz_html
333
+ from cortexcode.terminal.completion import print_ai_docs_complete, print_diagrams_complete, print_docs_complete
334
+ from cortexcode.terminal.headers import print_ai_docs_header, print_diagrams_header, print_docs_header
335
+ from cortexcode.terminal.reports import get_available_reports, print_terminal_report
336
+
337
+ preferences = _load_post_index_preferences()
338
+ if not _prompt_generate_now():
339
+ return
340
+
341
+ recommended_targets = _get_recommended_targets(index_data, preferences)
342
+ default_targets = preferences.get("targets") or recommended_targets
343
+ targets = _prompt_generation_targets(console, default_targets, recommended_targets)
344
+ if not targets:
345
+ return
346
+
347
+ provider = preferences.get("provider")
348
+ if any(target in {"ai_docs", "wiki"} for target in targets):
349
+ provider = _prompt_provider(provider)
350
+ if not _ensure_provider_access(console, provider):
351
+ targets = [target for target in targets if target not in {"ai_docs", "wiki"}]
352
+ if not targets:
353
+ return
354
+
355
+ report_type = preferences.get("report_type")
356
+ if "report" in targets:
357
+ available_reports = get_available_reports(index_data, ["overview", "tech", "hotspots", "routes", "entities", "frontend", "cli"])
358
+ report_type = _prompt_report_type(available_reports, report_type)
359
+
360
+ dashboard_port = int(preferences.get("dashboard_port", 8787))
361
+ if "dashboard" in targets:
362
+ dashboard_port = _prompt_dashboard_port(dashboard_port)
363
+
364
+ docs_open_browser = bool(preferences.get("open_docs_browser", False))
365
+ if "docs" in targets:
366
+ docs_open_browser = _prompt_confirm("Open generated docs in browser?", docs_open_browser)
367
+
368
+ recommended_diagrams = index_data.get("project_profile", {}).get("recommendations", {}).get("diagrams", [])
369
+ diagram_defaults = preferences.get("diagram_types") or [item for item in recommended_diagrams if item in ["call_graph", "class", "sequence", "architecture", "imports", "dependencies", "entities", "file_tree"]] or ["architecture", "call_graph"]
370
+ selected_diagram_types = diagram_defaults
371
+ if "diagrams" in targets:
372
+ selected_diagram_types = _prompt_diagram_types(diagram_defaults)
373
+
374
+ ai_doc_defaults = preferences.get("ai_doc_types") or ["overview", "api", "architecture", "flows"]
375
+ selected_ai_doc_types = ai_doc_defaults
376
+ if "ai_docs" in targets:
377
+ selected_ai_doc_types = _prompt_ai_doc_types(ai_doc_defaults)
378
+
379
+ wiki_open_browser = bool(preferences.get("open_wiki_browser", False))
380
+ wiki_include_modules = bool(preferences.get("wiki_include_modules", True))
381
+ wiki_max_modules = int(preferences.get("wiki_max_modules", 15))
382
+ if "wiki" in targets:
383
+ wiki_open_browser = _prompt_confirm("Open generated CodeWiki in browser?", wiki_open_browser)
384
+ wiki_include_modules = _prompt_confirm("Include per-module wiki pages?", wiki_include_modules)
385
+ if wiki_include_modules:
386
+ wiki_max_modules = _prompt_max_modules(wiki_max_modules)
387
+
388
+ viz_open_browser = bool(preferences.get("open_viz_browser", True))
389
+ if "viz" in targets:
390
+ viz_open_browser = _prompt_confirm("Open graph visualization in browser?", viz_open_browser)
391
+
392
+ wizard_enabled = _prompt_show_wizard_next_time(bool(preferences.get("enabled", True)))
393
+
394
+ if _prompt_save_preferences():
395
+ _save_post_index_preferences(
396
+ {
397
+ "targets": targets,
398
+ "provider": provider,
399
+ "report_type": report_type,
400
+ "dashboard_port": dashboard_port,
401
+ "diagram_types": selected_diagram_types,
402
+ "ai_doc_types": selected_ai_doc_types,
403
+ "open_docs_browser": docs_open_browser,
404
+ "open_wiki_browser": wiki_open_browser,
405
+ "wiki_include_modules": wiki_include_modules,
406
+ "wiki_max_modules": wiki_max_modules,
407
+ "open_viz_browser": viz_open_browser,
408
+ "enabled": wizard_enabled,
409
+ }
410
+ )
411
+
412
+ if "docs" in targets:
413
+ handle_docs_command(
414
+ console,
415
+ path,
416
+ path / ".cortexcode" / "docs",
417
+ docs_open_browser,
418
+ require_index_path,
419
+ print_docs_header,
420
+ generate_all_docs,
421
+ print_docs_complete,
422
+ )
423
+
424
+ if "diagrams" in targets:
425
+ output_dir = path / ".cortexcode" / "diagrams"
426
+ diagram_types = ["call_graph", "class", "sequence", "architecture", "imports", "dependencies", "entities", "file_tree"]
427
+ if len(selected_diagram_types) == 1:
428
+ handle_diagrams_command(
429
+ console,
430
+ path,
431
+ output_dir,
432
+ selected_diagram_types[0],
433
+ require_index_path,
434
+ print_diagrams_header,
435
+ save_diagrams,
436
+ diagram_types,
437
+ print_diagrams_complete,
438
+ )
439
+ elif len(selected_diagram_types) == len(diagram_types):
440
+ handle_diagrams_command(
441
+ console,
442
+ path,
443
+ output_dir,
444
+ None,
445
+ require_index_path,
446
+ print_diagrams_header,
447
+ save_diagrams,
448
+ diagram_types,
449
+ print_diagrams_complete,
450
+ )
451
+ else:
452
+ _, index_path = require_index_path(console, path)
453
+ print_diagrams_header(console, path)
454
+ for diagram_type in selected_diagram_types:
455
+ save_diagrams(index_path, output_dir, diagram_type=diagram_type)
456
+ generated_files = ["DIAGRAMS.md", *[f"{item}.mmd" for item in selected_diagram_types]]
457
+ print_diagrams_complete(console, output_dir, generated_files)
458
+
459
+ if "ai_docs" in targets:
460
+ handle_ai_docs_command(
461
+ console,
462
+ path,
463
+ path / ".cortexcode" / "ai-docs",
464
+ provider,
465
+ None,
466
+ tuple(selected_ai_doc_types),
467
+ require_ai_doc_generator,
468
+ require_index_path,
469
+ print_ai_docs_header,
470
+ print_ai_docs_complete,
471
+ )
472
+
473
+ if "wiki" in targets:
474
+ handle_wiki_command(
475
+ console,
476
+ path,
477
+ path / ".cortexcode" / "wiki",
478
+ provider,
479
+ None,
480
+ None,
481
+ not wiki_include_modules,
482
+ wiki_max_modules,
483
+ wiki_open_browser,
484
+ )
485
+
486
+ if "report" in targets:
487
+ print_terminal_report(console, report_type or "overview", index_data, path)
488
+
489
+ if "viz" in targets:
490
+ viz_path = path / ".cortexcode" / "graph.html"
491
+ generate_viz_html(index_data, viz_path)
492
+ if viz_open_browser:
493
+ console.print(f"[cyan]Opening visualization:[/cyan] {viz_path}")
494
+ webbrowser.open(viz_path.as_uri())
495
+ else:
496
+ console.print(f"[green]✓[/green] Visualization generated: {viz_path}")
497
+
498
+ if "mcp_setup" in targets:
499
+ handle_mcp_setup(console)
500
+
501
+ if "dashboard" in targets:
502
+ handle_dashboard_command(console, path, dashboard_port, indexer, DashboardServer)
503
+
504
+
505
+ def handle_index_command(
506
+ console: Console,
507
+ path: str | Path,
508
+ output: str | Path,
509
+ verbose: bool,
510
+ watch: bool,
511
+ incremental: bool,
512
+ include_tests,
513
+ exclude,
514
+ include,
515
+ root,
516
+ dry_run: bool,
517
+ no_post_index_wizard: bool,
518
+ force_wizard: bool,
519
+ indexer_module,
520
+ print_index_header,
521
+ print_project_profile_summary,
522
+ show_index_summary,
523
+ start_watcher,
524
+ ) -> None:
525
+ path = Path(path).resolve()
526
+ output = Path(output)
527
+
528
+ from cortexcode.config import get_filter_opts_from_config
529
+
530
+ print_index_header(console, path, incremental)
531
+
532
+ config_filter_opts = get_filter_opts_from_config(path)
533
+ filter_opts = {
534
+ "include_tests": include_tests if include_tests is not None else config_filter_opts.get("include_tests", False),
535
+ "max_file_size": config_filter_opts.get("max_file_size", 1024 * 1024),
536
+ "exclude_patterns": list(exclude) if exclude else config_filter_opts.get("exclude_patterns", []),
537
+ "include_patterns": list(include) if include else config_filter_opts.get("include_patterns", []),
538
+ "monorepo_root": root or config_filter_opts.get("monorepo_root"),
539
+ }
540
+
541
+ if dry_run:
542
+ from cortexcode.performance import preview_indexing
543
+
544
+ preview = preview_indexing(path, filter_opts)
545
+ console.print(Panel(
546
+ f"[bold]Files to index:[/bold] {preview['files_to_index']}\n"
547
+ f"[bold]Files to skip:[/bold] {preview['files_to_skip']}\n\n"
548
+ f"[dim]Skip reasons:[/dim]\n"
549
+ f" - File too large: {preview['skip_reasons']['file_too_large']}\n"
550
+ f" - Ignored: {preview['skip_reasons']['ignored']}\n\n"
551
+ f"[bold]Sample files that would be indexed:[/bold]\n" +
552
+ "\n".join(f" - {f}" for f in preview['sample_files'][:10]),
553
+ title="[bold]Dry Run Preview[/bold]",
554
+ border_style="yellow",
555
+ ))
556
+ return
557
+
558
+ with Progress(
559
+ SpinnerColumn(),
560
+ TextColumn("[progress.description]{task.description}"),
561
+ BarColumn(bar_width=40),
562
+ TaskProgressColumn(),
563
+ TimeRemainingColumn(),
564
+ console=console,
565
+ ) as progress:
566
+ task = progress.add_task("[cyan]Indexing files...", total=None)
567
+
568
+ start_time = time.time()
569
+ index_data = indexer_module.index_directory(path, incremental=incremental, filter_opts=filter_opts)
570
+ elapsed = time.time() - start_time
571
+
572
+ progress.update(task, completed=True)
573
+
574
+ indexer_module.save_index(index_data, output)
575
+
576
+ file_count = len(index_data.get("files", {}))
577
+ symbol_count = sum(len(s.get("symbols", [])) if isinstance(s, dict) else len(s) for s in index_data.get("files", {}).values())
578
+ languages = index_data.get("languages", [])
579
+
580
+ table = Table(box=box.ROUNDED, show_header=False)
581
+ table.add_column("Key", style="cyan")
582
+ table.add_column("Value", style="white")
583
+
584
+ table.add_row("Files", f"[bold]{file_count}[/bold]")
585
+ table.add_row("Symbols", f"[bold]{symbol_count}[/bold]")
586
+ table.add_row("Languages", ", ".join(languages) if languages else "N/A")
587
+ table.add_row("Time", f"{elapsed:.2f}s")
588
+ table.add_row("Output", str(output))
589
+ if incremental:
590
+ table.add_row("Mode", "[yellow]Incremental[/yellow]")
591
+
592
+ console.print()
593
+ console.print(Panel(
594
+ table,
595
+ title="[bold green]✓ Indexing Complete[/bold green]",
596
+ border_style="green",
597
+ ))
598
+ print_project_profile_summary(console, index_data)
599
+
600
+ if verbose:
601
+ show_index_summary(console, index_data)
602
+
603
+ if _should_show_post_index_wizard(watch, no_post_index_wizard, force_wizard):
604
+ _run_post_index_wizard(console, path, index_data)
605
+
606
+ if watch:
607
+ console.print("\n[yellow]Starting watcher...[/yellow]")
608
+ console.print("[dim]Press Ctrl+C to stop[/dim]")
609
+ start_watcher(path, verbose=verbose)