codexa 0.4.0__py3-none-any.whl

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 (189) hide show
  1. codexa-0.4.0.dist-info/METADATA +650 -0
  2. codexa-0.4.0.dist-info/RECORD +189 -0
  3. codexa-0.4.0.dist-info/WHEEL +5 -0
  4. codexa-0.4.0.dist-info/entry_points.txt +2 -0
  5. codexa-0.4.0.dist-info/licenses/LICENSE +21 -0
  6. codexa-0.4.0.dist-info/top_level.txt +1 -0
  7. semantic_code_intelligence/__init__.py +5 -0
  8. semantic_code_intelligence/analysis/__init__.py +21 -0
  9. semantic_code_intelligence/analysis/ai_features.py +351 -0
  10. semantic_code_intelligence/bridge/__init__.py +28 -0
  11. semantic_code_intelligence/bridge/context_provider.py +245 -0
  12. semantic_code_intelligence/bridge/protocol.py +167 -0
  13. semantic_code_intelligence/bridge/server.py +348 -0
  14. semantic_code_intelligence/bridge/vscode.py +271 -0
  15. semantic_code_intelligence/ci/__init__.py +13 -0
  16. semantic_code_intelligence/ci/hooks.py +98 -0
  17. semantic_code_intelligence/ci/hotspots.py +272 -0
  18. semantic_code_intelligence/ci/impact.py +246 -0
  19. semantic_code_intelligence/ci/metrics.py +591 -0
  20. semantic_code_intelligence/ci/pr.py +412 -0
  21. semantic_code_intelligence/ci/quality.py +557 -0
  22. semantic_code_intelligence/ci/templates.py +164 -0
  23. semantic_code_intelligence/ci/trace.py +224 -0
  24. semantic_code_intelligence/cli/__init__.py +0 -0
  25. semantic_code_intelligence/cli/commands/__init__.py +0 -0
  26. semantic_code_intelligence/cli/commands/ask_cmd.py +153 -0
  27. semantic_code_intelligence/cli/commands/benchmark_cmd.py +303 -0
  28. semantic_code_intelligence/cli/commands/chat_cmd.py +252 -0
  29. semantic_code_intelligence/cli/commands/ci_gen_cmd.py +74 -0
  30. semantic_code_intelligence/cli/commands/context_cmd.py +120 -0
  31. semantic_code_intelligence/cli/commands/cross_refactor_cmd.py +113 -0
  32. semantic_code_intelligence/cli/commands/deps_cmd.py +91 -0
  33. semantic_code_intelligence/cli/commands/docs_cmd.py +101 -0
  34. semantic_code_intelligence/cli/commands/doctor_cmd.py +147 -0
  35. semantic_code_intelligence/cli/commands/evolve_cmd.py +171 -0
  36. semantic_code_intelligence/cli/commands/explain_cmd.py +112 -0
  37. semantic_code_intelligence/cli/commands/gate_cmd.py +135 -0
  38. semantic_code_intelligence/cli/commands/grep_cmd.py +234 -0
  39. semantic_code_intelligence/cli/commands/hotspots_cmd.py +119 -0
  40. semantic_code_intelligence/cli/commands/impact_cmd.py +131 -0
  41. semantic_code_intelligence/cli/commands/index_cmd.py +138 -0
  42. semantic_code_intelligence/cli/commands/init_cmd.py +152 -0
  43. semantic_code_intelligence/cli/commands/investigate_cmd.py +163 -0
  44. semantic_code_intelligence/cli/commands/languages_cmd.py +101 -0
  45. semantic_code_intelligence/cli/commands/lsp_cmd.py +49 -0
  46. semantic_code_intelligence/cli/commands/mcp_cmd.py +50 -0
  47. semantic_code_intelligence/cli/commands/metrics_cmd.py +264 -0
  48. semantic_code_intelligence/cli/commands/models_cmd.py +157 -0
  49. semantic_code_intelligence/cli/commands/plugin_cmd.py +275 -0
  50. semantic_code_intelligence/cli/commands/pr_summary_cmd.py +178 -0
  51. semantic_code_intelligence/cli/commands/quality_cmd.py +208 -0
  52. semantic_code_intelligence/cli/commands/refactor_cmd.py +103 -0
  53. semantic_code_intelligence/cli/commands/review_cmd.py +88 -0
  54. semantic_code_intelligence/cli/commands/search_cmd.py +236 -0
  55. semantic_code_intelligence/cli/commands/serve_cmd.py +117 -0
  56. semantic_code_intelligence/cli/commands/suggest_cmd.py +100 -0
  57. semantic_code_intelligence/cli/commands/summary_cmd.py +78 -0
  58. semantic_code_intelligence/cli/commands/tool_cmd.py +282 -0
  59. semantic_code_intelligence/cli/commands/trace_cmd.py +123 -0
  60. semantic_code_intelligence/cli/commands/tui_cmd.py +58 -0
  61. semantic_code_intelligence/cli/commands/viz_cmd.py +127 -0
  62. semantic_code_intelligence/cli/commands/watch_cmd.py +72 -0
  63. semantic_code_intelligence/cli/commands/web_cmd.py +61 -0
  64. semantic_code_intelligence/cli/commands/workspace_cmd.py +250 -0
  65. semantic_code_intelligence/cli/main.py +65 -0
  66. semantic_code_intelligence/cli/router.py +92 -0
  67. semantic_code_intelligence/config/__init__.py +0 -0
  68. semantic_code_intelligence/config/settings.py +260 -0
  69. semantic_code_intelligence/context/__init__.py +19 -0
  70. semantic_code_intelligence/context/engine.py +429 -0
  71. semantic_code_intelligence/context/memory.py +253 -0
  72. semantic_code_intelligence/daemon/__init__.py +1 -0
  73. semantic_code_intelligence/daemon/watcher.py +515 -0
  74. semantic_code_intelligence/docs/__init__.py +1080 -0
  75. semantic_code_intelligence/embeddings/__init__.py +0 -0
  76. semantic_code_intelligence/embeddings/enhanced.py +131 -0
  77. semantic_code_intelligence/embeddings/generator.py +149 -0
  78. semantic_code_intelligence/embeddings/model_registry.py +100 -0
  79. semantic_code_intelligence/evolution/__init__.py +1 -0
  80. semantic_code_intelligence/evolution/budget_guard.py +111 -0
  81. semantic_code_intelligence/evolution/commit_manager.py +88 -0
  82. semantic_code_intelligence/evolution/context_builder.py +131 -0
  83. semantic_code_intelligence/evolution/engine.py +249 -0
  84. semantic_code_intelligence/evolution/patch_generator.py +229 -0
  85. semantic_code_intelligence/evolution/task_selector.py +214 -0
  86. semantic_code_intelligence/evolution/test_runner.py +111 -0
  87. semantic_code_intelligence/indexing/__init__.py +0 -0
  88. semantic_code_intelligence/indexing/chunker.py +174 -0
  89. semantic_code_intelligence/indexing/parallel.py +86 -0
  90. semantic_code_intelligence/indexing/scanner.py +146 -0
  91. semantic_code_intelligence/indexing/semantic_chunker.py +337 -0
  92. semantic_code_intelligence/llm/__init__.py +62 -0
  93. semantic_code_intelligence/llm/cache.py +219 -0
  94. semantic_code_intelligence/llm/cached_provider.py +145 -0
  95. semantic_code_intelligence/llm/conversation.py +190 -0
  96. semantic_code_intelligence/llm/cross_refactor.py +272 -0
  97. semantic_code_intelligence/llm/investigation.py +274 -0
  98. semantic_code_intelligence/llm/mock_provider.py +77 -0
  99. semantic_code_intelligence/llm/ollama_provider.py +122 -0
  100. semantic_code_intelligence/llm/openai_provider.py +100 -0
  101. semantic_code_intelligence/llm/provider.py +92 -0
  102. semantic_code_intelligence/llm/rate_limiter.py +164 -0
  103. semantic_code_intelligence/llm/reasoning.py +438 -0
  104. semantic_code_intelligence/llm/safety.py +110 -0
  105. semantic_code_intelligence/llm/streaming.py +251 -0
  106. semantic_code_intelligence/lsp/__init__.py +609 -0
  107. semantic_code_intelligence/mcp/__init__.py +393 -0
  108. semantic_code_intelligence/parsing/__init__.py +19 -0
  109. semantic_code_intelligence/parsing/parser.py +375 -0
  110. semantic_code_intelligence/plugins/__init__.py +255 -0
  111. semantic_code_intelligence/plugins/examples/__init__.py +1 -0
  112. semantic_code_intelligence/plugins/examples/code_quality.py +73 -0
  113. semantic_code_intelligence/plugins/examples/search_annotator.py +56 -0
  114. semantic_code_intelligence/scalability/__init__.py +205 -0
  115. semantic_code_intelligence/search/__init__.py +0 -0
  116. semantic_code_intelligence/search/formatter.py +123 -0
  117. semantic_code_intelligence/search/grep.py +361 -0
  118. semantic_code_intelligence/search/hybrid_search.py +170 -0
  119. semantic_code_intelligence/search/keyword_search.py +311 -0
  120. semantic_code_intelligence/search/section_expander.py +103 -0
  121. semantic_code_intelligence/services/__init__.py +0 -0
  122. semantic_code_intelligence/services/indexing_service.py +630 -0
  123. semantic_code_intelligence/services/search_service.py +269 -0
  124. semantic_code_intelligence/storage/__init__.py +0 -0
  125. semantic_code_intelligence/storage/chunk_hash_store.py +86 -0
  126. semantic_code_intelligence/storage/hash_store.py +66 -0
  127. semantic_code_intelligence/storage/index_manifest.py +85 -0
  128. semantic_code_intelligence/storage/index_stats.py +138 -0
  129. semantic_code_intelligence/storage/query_history.py +160 -0
  130. semantic_code_intelligence/storage/symbol_registry.py +209 -0
  131. semantic_code_intelligence/storage/vector_store.py +297 -0
  132. semantic_code_intelligence/tests/__init__.py +0 -0
  133. semantic_code_intelligence/tests/test_ai_features.py +351 -0
  134. semantic_code_intelligence/tests/test_chunker.py +119 -0
  135. semantic_code_intelligence/tests/test_cli.py +188 -0
  136. semantic_code_intelligence/tests/test_config.py +154 -0
  137. semantic_code_intelligence/tests/test_context.py +381 -0
  138. semantic_code_intelligence/tests/test_embeddings.py +73 -0
  139. semantic_code_intelligence/tests/test_endtoend.py +1142 -0
  140. semantic_code_intelligence/tests/test_enhanced_embeddings.py +92 -0
  141. semantic_code_intelligence/tests/test_hash_store.py +79 -0
  142. semantic_code_intelligence/tests/test_logging.py +55 -0
  143. semantic_code_intelligence/tests/test_new_cli.py +138 -0
  144. semantic_code_intelligence/tests/test_parser.py +495 -0
  145. semantic_code_intelligence/tests/test_phase10.py +355 -0
  146. semantic_code_intelligence/tests/test_phase11.py +593 -0
  147. semantic_code_intelligence/tests/test_phase12.py +375 -0
  148. semantic_code_intelligence/tests/test_phase13.py +663 -0
  149. semantic_code_intelligence/tests/test_phase14.py +568 -0
  150. semantic_code_intelligence/tests/test_phase15.py +814 -0
  151. semantic_code_intelligence/tests/test_phase16.py +792 -0
  152. semantic_code_intelligence/tests/test_phase17.py +815 -0
  153. semantic_code_intelligence/tests/test_phase18.py +934 -0
  154. semantic_code_intelligence/tests/test_phase19.py +986 -0
  155. semantic_code_intelligence/tests/test_phase20.py +2753 -0
  156. semantic_code_intelligence/tests/test_phase20b.py +2058 -0
  157. semantic_code_intelligence/tests/test_phase20c.py +962 -0
  158. semantic_code_intelligence/tests/test_phase21.py +428 -0
  159. semantic_code_intelligence/tests/test_phase22.py +799 -0
  160. semantic_code_intelligence/tests/test_phase23.py +783 -0
  161. semantic_code_intelligence/tests/test_phase24.py +715 -0
  162. semantic_code_intelligence/tests/test_phase25.py +496 -0
  163. semantic_code_intelligence/tests/test_phase26.py +251 -0
  164. semantic_code_intelligence/tests/test_phase27.py +531 -0
  165. semantic_code_intelligence/tests/test_phase8.py +592 -0
  166. semantic_code_intelligence/tests/test_phase9.py +643 -0
  167. semantic_code_intelligence/tests/test_plugins.py +293 -0
  168. semantic_code_intelligence/tests/test_priority_features.py +727 -0
  169. semantic_code_intelligence/tests/test_router.py +41 -0
  170. semantic_code_intelligence/tests/test_scalability.py +138 -0
  171. semantic_code_intelligence/tests/test_scanner.py +125 -0
  172. semantic_code_intelligence/tests/test_search.py +160 -0
  173. semantic_code_intelligence/tests/test_semantic_chunker.py +255 -0
  174. semantic_code_intelligence/tests/test_tools.py +182 -0
  175. semantic_code_intelligence/tests/test_vector_store.py +151 -0
  176. semantic_code_intelligence/tests/test_watcher.py +211 -0
  177. semantic_code_intelligence/tools/__init__.py +442 -0
  178. semantic_code_intelligence/tools/executor.py +232 -0
  179. semantic_code_intelligence/tools/protocol.py +200 -0
  180. semantic_code_intelligence/tui/__init__.py +454 -0
  181. semantic_code_intelligence/utils/__init__.py +0 -0
  182. semantic_code_intelligence/utils/logging.py +112 -0
  183. semantic_code_intelligence/version.py +3 -0
  184. semantic_code_intelligence/web/__init__.py +11 -0
  185. semantic_code_intelligence/web/api.py +289 -0
  186. semantic_code_intelligence/web/server.py +397 -0
  187. semantic_code_intelligence/web/ui.py +659 -0
  188. semantic_code_intelligence/web/visualize.py +226 -0
  189. semantic_code_intelligence/workspace/__init__.py +427 -0
@@ -0,0 +1,120 @@
1
+ """CLI command: context — generate structured context for external tools."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json as json_mod
6
+ from pathlib import Path
7
+
8
+ import click
9
+
10
+ from semantic_code_intelligence.utils.logging import (
11
+ console,
12
+ get_logger,
13
+ print_error,
14
+ print_info,
15
+ )
16
+
17
+ logger = get_logger("cli.context")
18
+
19
+
20
+ @click.command("context")
21
+ @click.argument("mode", type=click.Choice(["query", "symbol", "file", "repo"]))
22
+ @click.argument("target", required=False, default=None)
23
+ @click.option(
24
+ "--top-k",
25
+ "-k",
26
+ default=5,
27
+ type=int,
28
+ help="Number of results for query mode.",
29
+ )
30
+ @click.option(
31
+ "--file-path",
32
+ "-f",
33
+ default=None,
34
+ type=str,
35
+ help="File path hint (for symbol mode).",
36
+ )
37
+ @click.option(
38
+ "--json-output",
39
+ "--json",
40
+ "json_mode",
41
+ is_flag=True,
42
+ default=False,
43
+ help="Output raw JSON (default is pretty-printed).",
44
+ )
45
+ @click.option(
46
+ "--path",
47
+ "-p",
48
+ default=".",
49
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
50
+ help="Project root path.",
51
+ )
52
+ @click.pass_context
53
+ def context_cmd(
54
+ ctx: click.Context,
55
+ mode: str,
56
+ target: str | None,
57
+ top_k: int,
58
+ file_path: str | None,
59
+ json_mode: bool,
60
+ path: str,
61
+ ) -> None:
62
+ """Generate structured context for external AI pipelines.
63
+
64
+ \b
65
+ Modes:
66
+ query — semantic search (TARGET = search query)
67
+ symbol — symbol context (TARGET = symbol name)
68
+ file — file context (TARGET = file path)
69
+ repo — repo summary (no TARGET needed)
70
+ """
71
+ from semantic_code_intelligence.bridge.context_provider import ContextProvider
72
+
73
+ project_root = Path(path)
74
+ provider = ContextProvider(project_root)
75
+
76
+ try:
77
+ if mode == "query":
78
+ if not target:
79
+ print_error("Query mode requires a TARGET argument (the search query).")
80
+ ctx.exit(1)
81
+ return
82
+ data = provider.context_for_query(query=target, top_k=top_k)
83
+
84
+ elif mode == "symbol":
85
+ if not target:
86
+ print_error("Symbol mode requires a TARGET argument (symbol name).")
87
+ ctx.exit(1)
88
+ return
89
+ data = provider.context_for_symbol(
90
+ symbol_name=target, file_path=file_path,
91
+ )
92
+
93
+ elif mode == "file":
94
+ if not target:
95
+ print_error("File mode requires a TARGET argument (file path).")
96
+ ctx.exit(1)
97
+ return
98
+ data = provider.context_for_file(file_path=target)
99
+
100
+ elif mode == "repo":
101
+ data = provider.context_for_repo()
102
+
103
+ else:
104
+ print_error(f"Unknown mode: {mode}")
105
+ ctx.exit(1)
106
+ return
107
+
108
+ except Exception as exc:
109
+ logger.exception("Context generation failed")
110
+ print_error(f"Error: {exc}")
111
+ ctx.exit(1)
112
+ return
113
+
114
+ if json_mode:
115
+ click.echo(json_mod.dumps(data, indent=2))
116
+ else:
117
+ from rich.syntax import Syntax
118
+
119
+ formatted = json_mod.dumps(data, indent=2)
120
+ console.print(Syntax(formatted, "json", theme="monokai"))
@@ -0,0 +1,113 @@
1
+ """CLI command: cross-refactor — cross-repository refactoring suggestions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json as json_mod
6
+ from pathlib import Path
7
+
8
+ import click
9
+
10
+ from semantic_code_intelligence.utils.logging import (
11
+ console,
12
+ get_logger,
13
+ print_error,
14
+ print_info,
15
+ )
16
+
17
+ logger = get_logger("cli.cross_refactor")
18
+
19
+
20
+ @click.command("cross-refactor")
21
+ @click.option(
22
+ "--json-output", "--json", "json_mode",
23
+ is_flag=True,
24
+ default=False,
25
+ help="Output in JSON format.",
26
+ )
27
+ @click.option(
28
+ "--threshold", "-t",
29
+ default=0.70,
30
+ type=float,
31
+ help="Similarity threshold for duplicate detection (0.0-1.0).",
32
+ )
33
+ @click.option(
34
+ "--path", "-p",
35
+ default=".",
36
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
37
+ help="Workspace root path.",
38
+ )
39
+ @click.option("--pipe", is_flag=True, default=False, hidden=True)
40
+ @click.pass_context
41
+ def cross_refactor_cmd(
42
+ ctx: click.Context,
43
+ json_mode: bool,
44
+ threshold: float,
45
+ path: str,
46
+ pipe: bool,
47
+ ) -> None:
48
+ """Analyse workspace repos for cross-repo refactoring opportunities.
49
+
50
+ Scans all registered repositories in the workspace for duplicate logic,
51
+ inconsistent patterns, and symbols that could be extracted into a shared
52
+ library. When an LLM is configured, generates actionable suggestions.
53
+ """
54
+ from semantic_code_intelligence.llm.cross_refactor import analyze_cross_repo
55
+
56
+ root = Path(path).resolve()
57
+ pipe = pipe or ctx.obj.get("pipe", False)
58
+
59
+ # Optionally get LLM provider for suggestions
60
+ provider = None
61
+ try:
62
+ from semantic_code_intelligence.config.settings import load_config
63
+
64
+ config = load_config(root)
65
+ if config.llm.provider != "none":
66
+ from semantic_code_intelligence.cli.commands.chat_cmd import _get_provider
67
+
68
+ provider = _get_provider(config)
69
+ except Exception:
70
+ logger.debug("LLM provider not available; running without AI suggestions")
71
+
72
+ result = analyze_cross_repo(root, provider=provider, threshold=threshold)
73
+
74
+ if json_mode:
75
+ click.echo(json_mod.dumps(result.to_dict(), indent=2))
76
+ elif pipe:
77
+ click.echo(f"Repos: {', '.join(result.repos_analyzed)}")
78
+ click.echo(f"Symbols: {result.total_symbols}")
79
+ click.echo(f"Matches: {len(result.matches)}")
80
+ for m in result.matches:
81
+ click.echo(f" {m.repo_a}/{m.symbol_a} <-> {m.repo_b}/{m.symbol_b} ({m.similarity_note})")
82
+ for s in result.suggestions:
83
+ click.echo(f" Suggestion: {s.get('title', 'N/A')}")
84
+ else:
85
+ from rich.table import Table
86
+ from rich.panel import Panel
87
+
88
+ if not result.repos_analyzed:
89
+ print_info("No workspace found. Use 'codexa workspace init' first.")
90
+ return
91
+
92
+ console.print(f"[bold]Cross-repo analysis[/] — {result.total_symbols} symbols across {len(result.repos_analyzed)} repos")
93
+
94
+ if result.matches:
95
+ table = Table(title="Cross-Repo Duplicates")
96
+ table.add_column("Repo A")
97
+ table.add_column("Symbol A")
98
+ table.add_column("Repo B")
99
+ table.add_column("Symbol B")
100
+ table.add_column("Similarity")
101
+ for m in result.matches[:20]:
102
+ table.add_row(m.repo_a, m.symbol_a, m.repo_b, m.symbol_b, m.similarity_note)
103
+ console.print(table)
104
+ else:
105
+ print_info("No cross-repo duplicates detected.")
106
+
107
+ if result.suggestions:
108
+ console.print()
109
+ for s in result.suggestions:
110
+ console.print(Panel(
111
+ f"{s.get('description', '')}",
112
+ title=f"[bold]{s.get('title', 'Suggestion')}[/] [{s.get('priority', 'medium')}]",
113
+ ))
@@ -0,0 +1,91 @@
1
+ """CLI command: deps — show file/project dependency map."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import click
8
+
9
+ from semantic_code_intelligence.config.settings import load_config
10
+ from semantic_code_intelligence.context.engine import DependencyMap
11
+ from semantic_code_intelligence.indexing.scanner import scan_repository
12
+ from semantic_code_intelligence.utils.logging import (
13
+ console,
14
+ get_logger,
15
+ print_error,
16
+ print_info,
17
+ )
18
+
19
+ logger = get_logger("cli.deps")
20
+
21
+
22
+ @click.command("deps")
23
+ @click.argument("target", type=str, default=".")
24
+ @click.option(
25
+ "--path",
26
+ "-p",
27
+ default=".",
28
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
29
+ help="Project root path.",
30
+ )
31
+ @click.option(
32
+ "--json-output",
33
+ "--json",
34
+ "json_mode",
35
+ is_flag=True,
36
+ default=False,
37
+ help="Output in JSON format.",
38
+ )
39
+ @click.pass_context
40
+ def deps_cmd(ctx: click.Context, target: str, path: str, json_mode: bool) -> None:
41
+ """Show the dependency/import map for a file or the whole project.
42
+
43
+ TARGET can be a specific file path or '.' for the whole project.
44
+
45
+ Examples:
46
+
47
+ codexa deps src/main.py
48
+
49
+ codexa deps .
50
+
51
+ codexa deps . --json
52
+ """
53
+ import json as json_mod
54
+
55
+ root = Path(path).resolve()
56
+ dep_map = DependencyMap()
57
+
58
+ if target != ".":
59
+ # Single file
60
+ fpath = (root / target).resolve()
61
+ if not fpath.exists():
62
+ print_error(f"File not found: {target}")
63
+ return
64
+ content = fpath.read_text(encoding="utf-8", errors="replace")
65
+ dep_map.add_file(str(fpath), content)
66
+ else:
67
+ # Whole project
68
+ config = load_config(root)
69
+ scanned = scan_repository(root, config.index)
70
+ if not json_mode:
71
+ print_info(f"Analyzing dependencies across {len(scanned)} files...")
72
+ for sf in scanned:
73
+ full_path = root / sf.relative_path
74
+ try:
75
+ content = full_path.read_text(encoding="utf-8", errors="replace")
76
+ dep_map.add_file(str(full_path), content)
77
+ except Exception:
78
+ logger.debug("Could not read %s", sf.relative_path)
79
+
80
+ data = dep_map.to_dict()
81
+
82
+ if json_mode:
83
+ click.echo(json_mod.dumps(data, indent=2))
84
+ else:
85
+ for file_path, deps_list in data.items():
86
+ console.print(f"\n[bold]{file_path}[/bold]")
87
+ if deps_list:
88
+ for dep in deps_list:
89
+ console.print(f" → {dep.get('import_text', dep)}")
90
+ else:
91
+ console.print(" (no imports)")
@@ -0,0 +1,101 @@
1
+ """CLI command: docs — generate project documentation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import click
8
+
9
+ from semantic_code_intelligence.utils.logging import (
10
+ get_logger,
11
+ print_error,
12
+ print_info,
13
+ print_success,
14
+ )
15
+
16
+ logger = get_logger("cli.docs")
17
+
18
+
19
+ @click.command("docs")
20
+ @click.option(
21
+ "--output",
22
+ "-o",
23
+ default="docs",
24
+ type=click.Path(file_okay=False),
25
+ help="Output directory for generated docs.",
26
+ )
27
+ @click.option(
28
+ "--section",
29
+ "-s",
30
+ type=click.Choice(["cli", "plugins", "bridge", "tools", "all"], case_sensitive=False),
31
+ default="all",
32
+ help="Which documentation section to generate.",
33
+ )
34
+ @click.option(
35
+ "--json-output",
36
+ "--json",
37
+ "json_mode",
38
+ is_flag=True,
39
+ default=False,
40
+ help="Output file list as JSON.",
41
+ )
42
+ def docs_cmd(output: str, section: str, json_mode: bool) -> None:
43
+ """Generate Markdown documentation for CodexA components.
44
+
45
+ Produces auto-generated reference docs for CLI commands, plugin hooks,
46
+ bridge protocol, and tool registry.
47
+
48
+ Examples:
49
+
50
+ codexa docs
51
+
52
+ codexa docs --section plugins -o reference/
53
+
54
+ codexa docs --json
55
+ """
56
+ import json
57
+
58
+ from semantic_code_intelligence.docs import (
59
+ generate_all_docs,
60
+ generate_bridge_reference,
61
+ generate_cli_reference,
62
+ generate_plugin_reference,
63
+ generate_tool_reference,
64
+ )
65
+
66
+ out_dir = Path(output).resolve()
67
+
68
+ if section == "all":
69
+ generated = generate_all_docs(out_dir)
70
+ else:
71
+ out_dir.mkdir(parents=True, exist_ok=True)
72
+ generated = []
73
+
74
+ if section == "cli":
75
+ from semantic_code_intelligence.cli.main import cli
76
+
77
+ md = generate_cli_reference(cli)
78
+ (out_dir / "CLI.md").write_text(md, encoding="utf-8")
79
+ generated.append("CLI.md")
80
+ elif section == "plugins":
81
+ md = generate_plugin_reference()
82
+ (out_dir / "PLUGINS.md").write_text(md, encoding="utf-8")
83
+ generated.append("PLUGINS.md")
84
+ elif section == "bridge":
85
+ md = generate_bridge_reference()
86
+ (out_dir / "BRIDGE.md").write_text(md, encoding="utf-8")
87
+ generated.append("BRIDGE.md")
88
+ elif section == "tools":
89
+ md = generate_tool_reference()
90
+ (out_dir / "TOOLS.md").write_text(md, encoding="utf-8")
91
+ generated.append("TOOLS.md")
92
+
93
+ if json_mode:
94
+ click.echo(json.dumps({"output_dir": str(out_dir), "files": generated}))
95
+ else:
96
+ if generated:
97
+ for f in generated:
98
+ print_success(f"Generated {out_dir / f}")
99
+ print_info(f"{len(generated)} doc(s) written to {out_dir}/")
100
+ else:
101
+ print_error("No documentation generated.")
@@ -0,0 +1,147 @@
1
+ """CLI command: doctor — check environment health and dependencies."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib
6
+ import json as json_mod
7
+ import platform
8
+ import sys
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ import click
13
+
14
+ from semantic_code_intelligence import __version__
15
+ from semantic_code_intelligence.utils.logging import (
16
+ console,
17
+ get_logger,
18
+ print_error,
19
+ print_info,
20
+ print_success,
21
+ print_warning,
22
+ )
23
+
24
+ logger = get_logger("cli.doctor")
25
+
26
+
27
+ def _check_python() -> dict[str, Any]:
28
+ """Check Python version."""
29
+ ver = platform.python_version()
30
+ ok = sys.version_info >= (3, 11)
31
+ return {
32
+ "name": "Python",
33
+ "version": ver,
34
+ "ok": ok,
35
+ "detail": f"Python {ver}" + ("" if ok else " (3.11+ required)"),
36
+ }
37
+
38
+
39
+ def _check_package(pkg_name: str, import_name: str | None = None) -> dict[str, Any]:
40
+ """Check if a Python package is importable."""
41
+ mod_name = import_name or pkg_name
42
+ try:
43
+ importlib.import_module(mod_name)
44
+ # Prefer importlib.metadata to avoid deprecated __version__ attributes
45
+ try:
46
+ from importlib.metadata import version as meta_version
47
+ ver = meta_version(pkg_name)
48
+ except Exception:
49
+ ver = "installed"
50
+ return {"name": pkg_name, "version": str(ver), "ok": True, "detail": f"{pkg_name} {ver}"}
51
+ except ImportError:
52
+ return {"name": pkg_name, "version": None, "ok": False, "detail": f"{pkg_name} not installed"}
53
+
54
+
55
+ def _check_project(path: Path) -> dict[str, Any]:
56
+ """Check if a CodexA project is initialized at the given path."""
57
+ config_dir = path / ".codexa"
58
+ if config_dir.is_dir():
59
+ index_dir = config_dir / "index"
60
+ has_index = index_dir.is_dir() and any(index_dir.iterdir()) if index_dir.is_dir() else False
61
+ return {
62
+ "name": "Project",
63
+ "version": None,
64
+ "ok": True,
65
+ "detail": f"Initialized at {path}" + (" (indexed)" if has_index else " (not indexed)"),
66
+ }
67
+ return {
68
+ "name": "Project",
69
+ "version": None,
70
+ "ok": False,
71
+ "detail": f"Not initialized at {path} — run 'codexa init'",
72
+ }
73
+
74
+
75
+ def run_checks(path: Path) -> list[dict[str, Any]]:
76
+ """Run all health checks and return results."""
77
+ checks = [
78
+ _check_python(),
79
+ {"name": "CodexA", "version": __version__, "ok": True, "detail": f"CodexA {__version__}"},
80
+ _check_package("click"),
81
+ _check_package("pydantic"),
82
+ _check_package("rich"),
83
+ _check_package("sentence_transformers", "sentence_transformers"),
84
+ _check_package("faiss", "faiss"),
85
+ _check_package("tree_sitter", "tree_sitter"),
86
+ _check_project(path),
87
+ ]
88
+ return checks
89
+
90
+
91
+ @click.command("doctor")
92
+ @click.option(
93
+ "--path",
94
+ "-p",
95
+ default=".",
96
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
97
+ help="Project root path.",
98
+ )
99
+ @click.option(
100
+ "--json-output",
101
+ "--json",
102
+ "json_mode",
103
+ is_flag=True,
104
+ default=False,
105
+ help="Output results in JSON format.",
106
+ )
107
+ def doctor_cmd(path: str, json_mode: bool) -> None:
108
+ """Check environment health, dependencies, and project status.
109
+
110
+ Useful for debugging installation issues or verifying that all
111
+ required packages are available.
112
+
113
+ Examples:
114
+
115
+ codexa doctor
116
+
117
+ codexa doctor --json
118
+
119
+ codexa doctor -p /path/to/project
120
+ """
121
+ checks = run_checks(Path(path))
122
+
123
+ if json_mode:
124
+ click.echo(json_mod.dumps({"checks": checks}, indent=2))
125
+ return
126
+
127
+ from rich.table import Table
128
+
129
+ table = Table(title="CodexA Health Check", show_lines=False)
130
+ table.add_column("Component", style="bold")
131
+ table.add_column("Status")
132
+ table.add_column("Detail")
133
+
134
+ all_ok = True
135
+ for c in checks:
136
+ status = "[green]OK[/green]" if c["ok"] else "[red]FAIL[/red]"
137
+ if not c["ok"]:
138
+ all_ok = False
139
+ table.add_row(c["name"], status, c["detail"])
140
+
141
+ console.print(table)
142
+ console.print()
143
+
144
+ if all_ok:
145
+ print_success("All checks passed.")
146
+ else:
147
+ print_warning("Some checks failed. See details above.")