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,72 @@
1
+ """CLI command: watch — run the background indexing daemon."""
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 AppConfig
10
+ from semantic_code_intelligence.daemon.watcher import IndexingDaemon
11
+ from semantic_code_intelligence.utils.logging import (
12
+ get_logger,
13
+ print_error,
14
+ print_info,
15
+ print_success,
16
+ )
17
+
18
+ logger = get_logger("cli.watch")
19
+
20
+
21
+ @click.command("watch")
22
+ @click.option(
23
+ "--path",
24
+ "-p",
25
+ default=".",
26
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
27
+ help="Project root path.",
28
+ )
29
+ @click.option(
30
+ "--interval",
31
+ "-i",
32
+ default=2.0,
33
+ type=float,
34
+ help="Polling interval in seconds.",
35
+ )
36
+ @click.pass_context
37
+ def watch_cmd(ctx: click.Context, path: str, interval: float) -> None:
38
+ """Watch the repository for changes and re-index automatically.
39
+
40
+ Starts a background daemon that polls for file changes and triggers
41
+ incremental re-indexing.
42
+
43
+ Press Ctrl+C to stop.
44
+
45
+ Examples:
46
+
47
+ codexa watch
48
+
49
+ codexa watch --interval 5
50
+ """
51
+ root = Path(path).resolve()
52
+ config_dir = AppConfig.config_dir(root)
53
+
54
+ if not config_dir.exists():
55
+ print_error("Project not initialized. Run 'codexa init' first.")
56
+ return
57
+
58
+ print_info(f"Starting watch daemon for {root} (poll every {interval}s)")
59
+ print_info("Press Ctrl+C to stop.")
60
+
61
+ daemon = IndexingDaemon(root, poll_interval=interval)
62
+ daemon.start()
63
+
64
+ try:
65
+ import time
66
+ while True:
67
+ time.sleep(1)
68
+ except KeyboardInterrupt:
69
+ pass
70
+ finally:
71
+ daemon.stop()
72
+ print_success("Watch daemon stopped.")
@@ -0,0 +1,61 @@
1
+ """CLI command: web — start the CodexA web interface and REST API."""
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 get_logger, print_info
10
+
11
+ logger = get_logger("cli.web")
12
+
13
+
14
+ @click.command("web")
15
+ @click.option(
16
+ "--host",
17
+ "-h",
18
+ default="127.0.0.1",
19
+ type=str,
20
+ help="Host to bind the web server to.",
21
+ )
22
+ @click.option(
23
+ "--port",
24
+ "-p",
25
+ default=8080,
26
+ type=int,
27
+ help="Port to bind the web server to.",
28
+ )
29
+ @click.option(
30
+ "--path",
31
+ default=".",
32
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
33
+ help="Project root path.",
34
+ )
35
+ @click.pass_context
36
+ def web_cmd(
37
+ ctx: click.Context,
38
+ host: str,
39
+ port: int,
40
+ path: str,
41
+ ) -> None:
42
+ """Start the CodexA web interface and REST API server.
43
+
44
+ Provides a browser-based search UI and JSON REST endpoints
45
+ for programmatic access. Uses only the Python standard library.
46
+
47
+ Examples:
48
+
49
+ codexa web
50
+
51
+ codexa web --port 9000
52
+
53
+ codexa web --host 0.0.0.0 --port 8080 --path /my/project
54
+ """
55
+ from semantic_code_intelligence.web.server import WebServer
56
+
57
+ project_root = Path(path)
58
+ server = WebServer(project_root, host=host, port=port)
59
+ print_info(f"Starting CodexA web server on {server.url}")
60
+ print_info("Press Ctrl+C to stop.")
61
+ server.start()
@@ -0,0 +1,250 @@
1
+ """CLI command: workspace — manage multi-repo workspaces."""
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
+ print_success,
16
+ print_warning,
17
+ )
18
+
19
+ logger = get_logger("cli.workspace")
20
+
21
+
22
+ @click.group("workspace")
23
+ def workspace_cmd() -> None:
24
+ """Manage multi-repository workspaces."""
25
+
26
+
27
+ @workspace_cmd.command("init")
28
+ @click.option(
29
+ "--path",
30
+ "-p",
31
+ default=".",
32
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
33
+ help="Workspace root directory.",
34
+ )
35
+ def workspace_init(path: str) -> None:
36
+ """Initialise a new workspace."""
37
+ from semantic_code_intelligence.workspace import Workspace
38
+
39
+ ws = Workspace.load_or_create(Path(path))
40
+ ws.save()
41
+ print_success(f"Workspace initialised at {ws.root}")
42
+
43
+
44
+ @workspace_cmd.command("add")
45
+ @click.argument("name")
46
+ @click.argument("repo_path", type=click.Path(exists=True, file_okay=False, resolve_path=True))
47
+ @click.option(
48
+ "--path",
49
+ "-p",
50
+ default=".",
51
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
52
+ help="Workspace root directory.",
53
+ )
54
+ def workspace_add(name: str, repo_path: str, path: str) -> None:
55
+ """Register a repository in the workspace."""
56
+ from semantic_code_intelligence.workspace import Workspace
57
+
58
+ try:
59
+ ws = Workspace.load(Path(path))
60
+ except FileNotFoundError:
61
+ print_error("Workspace not initialised. Run 'codexa workspace init' first.")
62
+ return
63
+
64
+ try:
65
+ ws.add_repo(name, Path(repo_path))
66
+ ws.save()
67
+ print_success(f"Added repository '{name}' → {repo_path}")
68
+ except (ValueError, FileNotFoundError) as exc:
69
+ print_error(str(exc))
70
+
71
+
72
+ @workspace_cmd.command("remove")
73
+ @click.argument("name")
74
+ @click.option(
75
+ "--path",
76
+ "-p",
77
+ default=".",
78
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
79
+ help="Workspace root directory.",
80
+ )
81
+ def workspace_remove(name: str, path: str) -> None:
82
+ """Unregister a repository from the workspace."""
83
+ from semantic_code_intelligence.workspace import Workspace
84
+
85
+ try:
86
+ ws = Workspace.load(Path(path))
87
+ except FileNotFoundError:
88
+ print_error("Workspace not initialised.")
89
+ return
90
+
91
+ if ws.remove_repo(name):
92
+ ws.save()
93
+ print_success(f"Removed repository '{name}'.")
94
+ else:
95
+ print_warning(f"Repository '{name}' not found in workspace.")
96
+
97
+
98
+ @workspace_cmd.command("list")
99
+ @click.option(
100
+ "--json-output",
101
+ "--json",
102
+ "json_mode",
103
+ is_flag=True,
104
+ default=False,
105
+ help="Output in JSON format.",
106
+ )
107
+ @click.option(
108
+ "--path",
109
+ "-p",
110
+ default=".",
111
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
112
+ help="Workspace root directory.",
113
+ )
114
+ def workspace_list(json_mode: bool, path: str) -> None:
115
+ """List all repositories in the workspace."""
116
+ from semantic_code_intelligence.workspace import Workspace
117
+
118
+ try:
119
+ ws = Workspace.load(Path(path))
120
+ except FileNotFoundError:
121
+ print_error("Workspace not initialised.")
122
+ return
123
+
124
+ if json_mode:
125
+ click.echo(json_mod.dumps(ws.summary(), indent=2))
126
+ else:
127
+ repos = ws.repos
128
+ if not repos:
129
+ print_info("No repositories registered.")
130
+ return
131
+ from rich.table import Table
132
+
133
+ table = Table(title=f"Workspace: {ws.root}")
134
+ table.add_column("Name", style="cyan")
135
+ table.add_column("Path")
136
+ table.add_column("Files", justify="right")
137
+ table.add_column("Vectors", justify="right")
138
+ for r in repos:
139
+ table.add_row(r.name, r.path, str(r.file_count), str(r.vector_count))
140
+ console.print(table)
141
+
142
+
143
+ @workspace_cmd.command("index")
144
+ @click.option(
145
+ "--repo",
146
+ "-r",
147
+ default=None,
148
+ help="Index only this repository (by name).",
149
+ )
150
+ @click.option(
151
+ "--force",
152
+ is_flag=True,
153
+ default=False,
154
+ help="Force full re-index.",
155
+ )
156
+ @click.option(
157
+ "--path",
158
+ "-p",
159
+ default=".",
160
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
161
+ help="Workspace root directory.",
162
+ )
163
+ def workspace_index(repo: str | None, force: bool, path: str) -> None:
164
+ """Index repositories in the workspace."""
165
+ from semantic_code_intelligence.workspace import Workspace
166
+
167
+ try:
168
+ ws = Workspace.load(Path(path))
169
+ except FileNotFoundError:
170
+ print_error("Workspace not initialised.")
171
+ return
172
+
173
+ if repo:
174
+ try:
175
+ result = ws.index_repo(repo, force=force)
176
+ ws.save()
177
+ print_success(
178
+ f"[{repo}] Indexed {result.files_indexed} files "
179
+ f"({result.chunks_created} chunks, {result.total_vectors} vectors)"
180
+ )
181
+ except KeyError:
182
+ print_error(f"Repository '{repo}' not registered.")
183
+ else:
184
+ results = ws.index_all(force=force)
185
+ for name, result in results.items():
186
+ print_success(
187
+ f"[{name}] Indexed {result.files_indexed} files "
188
+ f"({result.chunks_created} chunks, {result.total_vectors} vectors)"
189
+ )
190
+
191
+
192
+ @workspace_cmd.command("search")
193
+ @click.argument("query")
194
+ @click.option("--top-k", "-k", default=10, type=int, help="Number of results.")
195
+ @click.option("--threshold", "-t", default=0.3, type=float, help="Minimum score.")
196
+ @click.option(
197
+ "--repo",
198
+ "-r",
199
+ multiple=True,
200
+ help="Restrict to specific repos (repeatable).",
201
+ )
202
+ @click.option(
203
+ "--json-output",
204
+ "--json",
205
+ "json_mode",
206
+ is_flag=True,
207
+ default=False,
208
+ help="Output in JSON format.",
209
+ )
210
+ @click.option(
211
+ "--path",
212
+ "-p",
213
+ default=".",
214
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
215
+ help="Workspace root directory.",
216
+ )
217
+ def workspace_search(
218
+ query: str,
219
+ top_k: int,
220
+ threshold: float,
221
+ repo: tuple[str, ...],
222
+ json_mode: bool,
223
+ path: str,
224
+ ) -> None:
225
+ """Search across all workspace repositories."""
226
+ from semantic_code_intelligence.workspace import Workspace
227
+
228
+ try:
229
+ ws = Workspace.load(Path(path))
230
+ except FileNotFoundError:
231
+ print_error("Workspace not initialised.")
232
+ return
233
+
234
+ repos = list(repo) if repo else None
235
+ results = ws.search(query, top_k=top_k, threshold=threshold, repos=repos)
236
+
237
+ if json_mode:
238
+ click.echo(json_mod.dumps(results, indent=2))
239
+ else:
240
+ if not results:
241
+ print_info("No results found.")
242
+ return
243
+ from rich.panel import Panel
244
+ from rich.syntax import Syntax
245
+
246
+ for r in results:
247
+ lang = r.get("language", "text")
248
+ syn = Syntax(r["content"], lang, line_numbers=True, start_line=r["start_line"])
249
+ title = f"[{r['repo']}] {r['file_path']}:{r['start_line']}-{r['end_line']} (score: {r['score']})"
250
+ console.print(Panel(syn, title=title, border_style="green"))
@@ -0,0 +1,65 @@
1
+ """Main CLI entry point for Semantic Code Intelligence."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+
7
+ import click
8
+
9
+ from semantic_code_intelligence import __version__
10
+ from semantic_code_intelligence.cli.router import register_commands
11
+ from semantic_code_intelligence.utils.logging import setup_logging
12
+
13
+
14
+ @click.group()
15
+ @click.version_option(version=__version__, prog_name="codexa")
16
+ @click.option(
17
+ "--verbose",
18
+ "-v",
19
+ is_flag=True,
20
+ default=False,
21
+ help="Enable verbose output.",
22
+ )
23
+ @click.option(
24
+ "--pipe",
25
+ is_flag=True,
26
+ default=False,
27
+ help="Pipeline mode — plain text output, no colors or spinners.",
28
+ )
29
+ @click.pass_context
30
+ def cli(ctx: click.Context, verbose: bool, pipe: bool) -> None:
31
+ """CodexA - Local semantic code search and AI-assisted code understanding.
32
+
33
+ A CLI tool that indexes codebases, performs semantic search, and provides
34
+ structured code context for AI integration.
35
+ """
36
+ ctx.ensure_object(dict)
37
+ ctx.obj["verbose"] = verbose
38
+ ctx.obj["pipe"] = pipe
39
+ setup_logging(verbose=verbose)
40
+
41
+
42
+ # Register all commands via the router
43
+ register_commands(cli)
44
+
45
+
46
+ def main() -> None:
47
+ """Entry point for the CLI application."""
48
+ try:
49
+ cli()
50
+ except KeyboardInterrupt:
51
+ click.echo("\nInterrupted.", err=True)
52
+ sys.exit(130)
53
+ except Exception as exc: # noqa: BLE001
54
+ try:
55
+ from semantic_code_intelligence.utils.logging import error_console
56
+ error_console.print(f"[bold red]Fatal error:[/bold red] {exc}")
57
+ error_console.print("[dim]Run with --verbose for full traceback.[/dim]")
58
+ except (UnicodeEncodeError, OSError):
59
+ click.echo(f"Fatal error: {exc}", err=True)
60
+ click.echo("Run with --verbose for full traceback.", err=True)
61
+ sys.exit(1)
62
+
63
+
64
+ if __name__ == "__main__":
65
+ main()
@@ -0,0 +1,92 @@
1
+ """Command router - registers all CLI commands with the main group."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import click
6
+
7
+ from semantic_code_intelligence.cli.commands.init_cmd import init_cmd
8
+ from semantic_code_intelligence.cli.commands.index_cmd import index_cmd
9
+ from semantic_code_intelligence.cli.commands.search_cmd import search_cmd
10
+ from semantic_code_intelligence.cli.commands.explain_cmd import explain_cmd
11
+ from semantic_code_intelligence.cli.commands.summary_cmd import summary_cmd
12
+ from semantic_code_intelligence.cli.commands.watch_cmd import watch_cmd
13
+ from semantic_code_intelligence.cli.commands.deps_cmd import deps_cmd
14
+ from semantic_code_intelligence.cli.commands.ask_cmd import ask_cmd
15
+ from semantic_code_intelligence.cli.commands.review_cmd import review_cmd
16
+ from semantic_code_intelligence.cli.commands.refactor_cmd import refactor_cmd
17
+ from semantic_code_intelligence.cli.commands.suggest_cmd import suggest_cmd
18
+ from semantic_code_intelligence.cli.commands.serve_cmd import serve_cmd
19
+ from semantic_code_intelligence.cli.commands.context_cmd import context_cmd
20
+ from semantic_code_intelligence.cli.commands.workspace_cmd import workspace_cmd
21
+ from semantic_code_intelligence.cli.commands.docs_cmd import docs_cmd
22
+ from semantic_code_intelligence.cli.commands.doctor_cmd import doctor_cmd
23
+ from semantic_code_intelligence.cli.commands.plugin_cmd import plugin_cmd
24
+ from semantic_code_intelligence.cli.commands.web_cmd import web_cmd
25
+ from semantic_code_intelligence.cli.commands.viz_cmd import viz_cmd
26
+ from semantic_code_intelligence.cli.commands.quality_cmd import quality_cmd
27
+ from semantic_code_intelligence.cli.commands.pr_summary_cmd import pr_summary_cmd
28
+ from semantic_code_intelligence.cli.commands.ci_gen_cmd import ci_gen_cmd
29
+ from semantic_code_intelligence.cli.commands.chat_cmd import chat_cmd
30
+ from semantic_code_intelligence.cli.commands.investigate_cmd import investigate_cmd
31
+ from semantic_code_intelligence.cli.commands.cross_refactor_cmd import cross_refactor_cmd
32
+ from semantic_code_intelligence.cli.commands.metrics_cmd import metrics_cmd
33
+ from semantic_code_intelligence.cli.commands.gate_cmd import gate_cmd
34
+ from semantic_code_intelligence.cli.commands.hotspots_cmd import hotspots_cmd
35
+ from semantic_code_intelligence.cli.commands.impact_cmd import impact_cmd
36
+ from semantic_code_intelligence.cli.commands.trace_cmd import trace_cmd
37
+ from semantic_code_intelligence.cli.commands.tool_cmd import tool_cmd
38
+ from semantic_code_intelligence.cli.commands.evolve_cmd import evolve_cmd
39
+ from semantic_code_intelligence.cli.commands.tui_cmd import tui_cmd
40
+ from semantic_code_intelligence.cli.commands.mcp_cmd import mcp_cmd
41
+ from semantic_code_intelligence.cli.commands.lsp_cmd import lsp_cmd
42
+ from semantic_code_intelligence.cli.commands.models_cmd import models_cmd
43
+ from semantic_code_intelligence.cli.commands.benchmark_cmd import benchmark_cmd
44
+ from semantic_code_intelligence.cli.commands.grep_cmd import grep_cmd
45
+ from semantic_code_intelligence.cli.commands.languages_cmd import languages_cmd
46
+
47
+
48
+ def register_commands(cli: click.Group) -> None:
49
+ """Register all available CLI commands with the main click group.
50
+
51
+ Args:
52
+ cli: The root click.Group to attach commands to.
53
+ """
54
+ cli.add_command(init_cmd)
55
+ cli.add_command(index_cmd)
56
+ cli.add_command(search_cmd)
57
+ cli.add_command(explain_cmd)
58
+ cli.add_command(summary_cmd)
59
+ cli.add_command(watch_cmd)
60
+ cli.add_command(deps_cmd)
61
+ cli.add_command(ask_cmd)
62
+ cli.add_command(review_cmd)
63
+ cli.add_command(refactor_cmd)
64
+ cli.add_command(suggest_cmd)
65
+ cli.add_command(serve_cmd)
66
+ cli.add_command(context_cmd)
67
+ cli.add_command(workspace_cmd)
68
+ cli.add_command(docs_cmd)
69
+ cli.add_command(doctor_cmd)
70
+ cli.add_command(plugin_cmd)
71
+ cli.add_command(web_cmd)
72
+ cli.add_command(viz_cmd)
73
+ cli.add_command(quality_cmd)
74
+ cli.add_command(pr_summary_cmd)
75
+ cli.add_command(ci_gen_cmd)
76
+ cli.add_command(chat_cmd)
77
+ cli.add_command(investigate_cmd)
78
+ cli.add_command(cross_refactor_cmd)
79
+ cli.add_command(metrics_cmd)
80
+ cli.add_command(gate_cmd)
81
+ cli.add_command(hotspots_cmd)
82
+ cli.add_command(impact_cmd)
83
+ cli.add_command(trace_cmd)
84
+ cli.add_command(tool_cmd)
85
+ cli.add_command(evolve_cmd)
86
+ cli.add_command(tui_cmd)
87
+ cli.add_command(mcp_cmd)
88
+ cli.add_command(lsp_cmd)
89
+ cli.add_command(models_cmd)
90
+ cli.add_command(benchmark_cmd)
91
+ cli.add_command(grep_cmd)
92
+ cli.add_command(languages_cmd)
File without changes