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,78 @@
1
+ """CLI command: summary — generate structured repository summary."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import click
8
+
9
+ from semantic_code_intelligence.analysis.ai_features import summarize_repository
10
+ from semantic_code_intelligence.config.settings import load_config
11
+ from semantic_code_intelligence.context.engine import ContextBuilder
12
+ from semantic_code_intelligence.indexing.scanner import scan_repository
13
+ from semantic_code_intelligence.utils.logging import (
14
+ console,
15
+ get_logger,
16
+ print_error,
17
+ print_info,
18
+ print_success,
19
+ )
20
+
21
+ logger = get_logger("cli.summary")
22
+
23
+
24
+ @click.command("summary")
25
+ @click.option(
26
+ "--path",
27
+ "-p",
28
+ default=".",
29
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
30
+ help="Project root path.",
31
+ )
32
+ @click.option(
33
+ "--json-output",
34
+ "--json",
35
+ "json_mode",
36
+ is_flag=True,
37
+ default=False,
38
+ help="Output in JSON format.",
39
+ )
40
+ @click.pass_context
41
+ def summary_cmd(ctx: click.Context, path: str, json_mode: bool) -> None:
42
+ """Generate a structured summary of the repository.
43
+
44
+ Shows language breakdown, symbol counts, and top functions/classes.
45
+
46
+ Examples:
47
+
48
+ codexa summary
49
+
50
+ codexa summary --json
51
+
52
+ codexa summary -p /path/to/project
53
+ """
54
+ root = Path(path).resolve()
55
+ config = load_config(root)
56
+ scanned = scan_repository(root, config.index)
57
+
58
+ if not scanned:
59
+ print_error("No source files found in the project.")
60
+ return
61
+
62
+ if not json_mode:
63
+ print_info(f"Analyzing {len(scanned)} files...")
64
+ builder = ContextBuilder()
65
+ for sf in scanned:
66
+ full_path = str(root / sf.relative_path)
67
+ try:
68
+ builder.index_file(full_path)
69
+ except Exception:
70
+ logger.debug("Could not parse %s", sf.relative_path)
71
+
72
+ summary = summarize_repository(builder)
73
+
74
+ if json_mode:
75
+ click.echo(summary.to_json())
76
+ else:
77
+ console.print(summary.render(), markup=False)
78
+ print_success(f"Summary generated for {summary.total_files} files.")
@@ -0,0 +1,282 @@
1
+ """CLI command: tool — invoke and manage AI agent 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_header,
15
+ print_separator,
16
+ print_success,
17
+ print_warning,
18
+ )
19
+
20
+ logger = get_logger("cli.tool")
21
+
22
+
23
+ @click.group("tool")
24
+ def tool_cmd() -> None:
25
+ """AI Agent Tooling Protocol — invoke and inspect tools.
26
+
27
+ Provides a CLI interface to the same tool execution engine that
28
+ AI coding agents use over the Bridge HTTP API.
29
+
30
+ Examples:
31
+
32
+ codexa tool list
33
+ codexa tool run semantic_search --arg query="parse file"
34
+ codexa tool schema semantic_search
35
+ """
36
+
37
+
38
+ @tool_cmd.command("list")
39
+ @click.option(
40
+ "--json-output", "--json", "json_mode",
41
+ is_flag=True, default=False,
42
+ help="Output in JSON format.",
43
+ )
44
+ def tool_list(json_mode: bool) -> None:
45
+ """List all available tools with their descriptions."""
46
+ from semantic_code_intelligence.tools import TOOL_DEFINITIONS
47
+ from semantic_code_intelligence.tools.executor import ToolExecutor
48
+
49
+ from rich.table import Table
50
+
51
+ executor = ToolExecutor(Path(".").resolve())
52
+ tools = executor.available_tools
53
+
54
+ if json_mode:
55
+ click.echo(json_mod.dumps({"tools": tools, "count": len(tools)}, indent=2))
56
+ return
57
+
58
+ print_header("Available Tools", f"{len(tools)} registered")
59
+ table = Table(show_header=True, header_style="bold cyan", box=None, padding=(0, 2))
60
+ table.add_column("Tool", style="bold")
61
+ table.add_column("Source", style="dim")
62
+ table.add_column("Parameters", style="yellow")
63
+ table.add_column("Description")
64
+
65
+ for t in tools:
66
+ source = t.get("source", "built-in")
67
+ params = t.get("parameters", {})
68
+ param_names = ", ".join(params.keys()) if params else "-"
69
+ desc = t.get("description", "No description")
70
+ if len(desc) > 60:
71
+ desc = desc[:57] + "..."
72
+ table.add_row(t["name"], source, param_names, desc)
73
+
74
+ console.print(table)
75
+ print_separator()
76
+
77
+
78
+ @tool_cmd.command("run")
79
+ @click.argument("tool_name")
80
+ @click.option(
81
+ "--arg", "-a",
82
+ multiple=True,
83
+ help="Tool argument as key=value (repeatable).",
84
+ )
85
+ @click.option(
86
+ "--path", "-p",
87
+ default=".",
88
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
89
+ help="Project root path.",
90
+ )
91
+ @click.option(
92
+ "--json-output", "--json", "json_mode",
93
+ is_flag=True, default=False,
94
+ help="Output in JSON format.",
95
+ )
96
+ @click.option(
97
+ "--pipe",
98
+ is_flag=True, default=False,
99
+ help="Plain text output for piping / CI.",
100
+ )
101
+ @click.pass_context
102
+ def tool_run(
103
+ ctx: click.Context,
104
+ tool_name: str,
105
+ arg: tuple[str, ...],
106
+ path: str,
107
+ json_mode: bool,
108
+ pipe: bool,
109
+ ) -> None:
110
+ """Run TOOL_NAME with the given arguments.
111
+
112
+ Arguments are passed as --arg key=value pairs.
113
+
114
+ Examples:
115
+
116
+ codexa tool run semantic_search --arg query="parse file"
117
+ codexa tool run explain_symbol --arg symbol_name=ToolRegistry
118
+ codexa tool run summarize_repo --json
119
+ """
120
+ from semantic_code_intelligence.tools.executor import ToolExecutor
121
+ from semantic_code_intelligence.tools.protocol import ToolInvocation
122
+
123
+ project_root = Path(path).resolve()
124
+
125
+ # Parse arguments
126
+ arguments: dict[str, str] = {}
127
+ for a in arg:
128
+ if "=" not in a:
129
+ print_error(f"Invalid argument format: {a!r} (expected key=value)")
130
+ ctx.exit(1)
131
+ return
132
+ key, value = a.split("=", 1)
133
+ arguments[key.strip()] = value.strip()
134
+
135
+ executor = ToolExecutor(project_root)
136
+ invocation = ToolInvocation(tool_name=tool_name, arguments=arguments)
137
+
138
+ if not (json_mode or pipe):
139
+ print_separator(f"Running: {tool_name}")
140
+
141
+ result = executor.execute(invocation)
142
+
143
+ if json_mode or pipe:
144
+ click.echo(result.to_json(indent=2 if json_mode else None))
145
+ return
146
+
147
+ if result.success:
148
+ print_success(f"Tool '{tool_name}' completed in {result.execution_time_ms:.1f}ms")
149
+ print_separator()
150
+ payload = result.result_payload
151
+ if payload:
152
+ _render_tool_result(tool_name, payload)
153
+ else:
154
+ print_error(f"Tool '{tool_name}' failed")
155
+ if result.error:
156
+ console.print(f" [red]Error code:[/red] {result.error.error_code}")
157
+ console.print(f" [red]Message:[/red] {result.error.error_message}")
158
+ print_separator()
159
+
160
+
161
+ def _render_tool_result(tool_name: str, payload: dict) -> None:
162
+ """Render a tool result payload with rich formatting."""
163
+ from rich.panel import Panel
164
+ from rich.syntax import Syntax
165
+ from rich.table import Table
166
+
167
+ # explanation results (explain_symbol, explain_file, get_context)
168
+ if "explanation" in payload:
169
+ console.print(Panel(payload["explanation"], title="Explanation", border_style="cyan"))
170
+ if payload.get("code_snippet"):
171
+ lang = payload.get("language", "python")
172
+ console.print(Syntax(payload["code_snippet"], lang, theme="monokai", line_numbers=True))
173
+ return
174
+
175
+ # search results
176
+ if "results" in payload and isinstance(payload["results"], list):
177
+ results = payload["results"]
178
+ console.print(f" [bold]{len(results)} result(s)[/bold]\n")
179
+ for i, r in enumerate(results[:20], 1):
180
+ score = r.get("score", r.get("similarity", 0))
181
+ path = r.get("file_path", r.get("path", "?"))
182
+ console.print(f" [cyan]{i}.[/cyan] [bold]{path}[/bold] [dim](score: {score:.3f})[/dim]")
183
+ snippet = r.get("content", r.get("snippet", ""))
184
+ if snippet:
185
+ preview = snippet.strip()[:120].replace("\n", " ")
186
+ console.print(f" [dim]{preview}[/dim]")
187
+ return
188
+
189
+ # call graph
190
+ if "call_graph" in payload or "callers" in payload or "callees" in payload:
191
+ if payload.get("callers"):
192
+ console.print(" [bold]Callers:[/bold]")
193
+ for c in payload["callers"]:
194
+ console.print(f" [green]←[/green] {c}")
195
+ if payload.get("callees"):
196
+ console.print(" [bold]Callees:[/bold]")
197
+ for c in payload["callees"]:
198
+ console.print(f" [magenta]→[/magenta] {c}")
199
+ return
200
+
201
+ # references
202
+ if "references" in payload:
203
+ refs = payload["references"]
204
+ console.print(f" [bold]{len(refs)} reference(s)[/bold]\n")
205
+ for ref in refs[:30]:
206
+ path = ref.get("file_path", ref.get("path", "?"))
207
+ line = ref.get("line", "?")
208
+ console.print(f" [cyan]{path}[/cyan]:[yellow]{line}[/yellow]")
209
+ return
210
+
211
+ # dependencies
212
+ if "dependencies" in payload or "imports" in payload:
213
+ deps = payload.get("dependencies", payload.get("imports", []))
214
+ console.print(f" [bold]{len(deps)} dependenc(ies)[/bold]\n")
215
+ for d in deps:
216
+ if isinstance(d, str):
217
+ console.print(f" [dim]→[/dim] {d}")
218
+ elif isinstance(d, dict):
219
+ console.print(f" [dim]→[/dim] {d.get('name', d.get('module', str(d)))}")
220
+ return
221
+
222
+ # summary
223
+ if "summary" in payload:
224
+ console.print(Panel(payload["summary"], title="Summary", border_style="green"))
225
+ return
226
+
227
+ # fallback: pretty-print JSON
228
+ console.print(Syntax(json_mod.dumps(payload, indent=2), "json", theme="monokai"))
229
+
230
+
231
+ @tool_cmd.command("schema")
232
+ @click.argument("tool_name")
233
+ @click.option(
234
+ "--json-output", "--json", "json_mode",
235
+ is_flag=True, default=False,
236
+ help="Output in JSON format.",
237
+ )
238
+ def tool_schema(tool_name: str, json_mode: bool) -> None:
239
+ """Show the schema definition for TOOL_NAME.
240
+
241
+ Examples:
242
+
243
+ codexa tool schema semantic_search
244
+ codexa tool schema explain_symbol --json
245
+ """
246
+ from semantic_code_intelligence.tools.executor import ToolExecutor
247
+
248
+ executor = ToolExecutor(Path(".").resolve())
249
+ schema = executor.get_tool_schema(tool_name)
250
+
251
+ if schema is None:
252
+ print_error(f"Unknown tool: {tool_name}")
253
+ available = [t["name"] for t in ToolExecutor(Path(".").resolve()).available_tools]
254
+ if available:
255
+ print_warning(f"Available tools: {', '.join(available)}")
256
+ return
257
+
258
+ if json_mode:
259
+ click.echo(json_mod.dumps(schema, indent=2))
260
+ return
261
+
262
+ from rich.table import Table
263
+
264
+ print_header(schema["name"], schema.get("description", ""))
265
+ params = schema.get("parameters", {})
266
+ if params:
267
+ table = Table(show_header=True, header_style="bold", box=None, padding=(0, 2))
268
+ table.add_column("Parameter", style="cyan")
269
+ table.add_column("Type", style="yellow")
270
+ table.add_column("Required", style="red")
271
+ table.add_column("Default", style="dim")
272
+ table.add_column("Description")
273
+ for pname, pdef in params.items():
274
+ req = "yes" if pdef.get("required") else ""
275
+ ptype = pdef.get("type", "any")
276
+ desc = pdef.get("description", "")
277
+ default = str(pdef["default"]) if "default" in pdef and pdef["default"] is not None else ""
278
+ table.add_row(pname, ptype, req, default, desc)
279
+ console.print(table)
280
+ else:
281
+ console.print(" [dim]No parameters[/dim]")
282
+ print_separator()
@@ -0,0 +1,123 @@
1
+ """CLI command: trace — trace execution relationships of a symbol."""
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_success,
15
+ )
16
+
17
+ logger = get_logger("cli.trace")
18
+
19
+
20
+ @click.command("trace")
21
+ @click.argument("symbol")
22
+ @click.option(
23
+ "--path", "-p",
24
+ default=".",
25
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
26
+ help="Project root path.",
27
+ )
28
+ @click.option(
29
+ "--json-output", "--json", "json_mode",
30
+ is_flag=True, default=False,
31
+ help="Output in JSON format.",
32
+ )
33
+ @click.option(
34
+ "--pipe",
35
+ is_flag=True, default=False,
36
+ help="Plain text output for piping / CI.",
37
+ )
38
+ @click.option(
39
+ "--max-depth", "-d",
40
+ type=int, default=5,
41
+ help="Maximum traversal depth (default: 5).",
42
+ )
43
+ @click.pass_context
44
+ def trace_cmd(
45
+ ctx: click.Context,
46
+ symbol: str,
47
+ path: str,
48
+ json_mode: bool,
49
+ pipe: bool,
50
+ max_depth: int,
51
+ ) -> None:
52
+ """Trace execution relationships for SYMBOL.
53
+
54
+ Shows upstream callers and downstream callees to map the flow of
55
+ execution through the codebase.
56
+
57
+ Examples:
58
+
59
+ codexa trace parse_file
60
+
61
+ codexa trace MyClass.process --json
62
+
63
+ codexa trace build_context --max-depth 3 --pipe
64
+ """
65
+ from semantic_code_intelligence.ci.trace import trace_symbol
66
+ from semantic_code_intelligence.context.engine import CallGraph, ContextBuilder
67
+
68
+ root = Path(path).resolve()
69
+ builder = ContextBuilder()
70
+
71
+ py_files = sorted(root.rglob("*.py"))
72
+ py_files = [f for f in py_files if ".venv" not in f.parts and "__pycache__" not in f.parts]
73
+
74
+ for fp in py_files:
75
+ try:
76
+ content = fp.read_text(encoding="utf-8", errors="replace")
77
+ builder.index_file(str(fp), content)
78
+ except Exception:
79
+ logger.debug("Failed to index %s", fp)
80
+ continue
81
+
82
+ symbols = builder.get_all_symbols()
83
+ call_graph = CallGraph()
84
+ call_graph.build(symbols)
85
+ call_graph.build(symbols)
86
+
87
+ result = trace_symbol(symbol, symbols, call_graph, max_depth=max_depth)
88
+
89
+ if not result.target_file:
90
+ if json_mode:
91
+ click.echo(json_mod.dumps({"error": f"Symbol '{symbol}' not found"}, indent=2))
92
+ elif pipe:
93
+ click.echo(f"ERROR symbol_not_found {symbol}")
94
+ else:
95
+ print_error(f"Symbol '{symbol}' not found in the project.")
96
+ return
97
+
98
+ if json_mode:
99
+ click.echo(json_mod.dumps(result.to_dict(), indent=2))
100
+ elif pipe:
101
+ click.echo(f"target={result.target} file={result.target_file} up={len(result.upstream)} down={len(result.downstream)}")
102
+ for n in result.upstream:
103
+ click.echo(f" UP depth={n.depth} {n.kind:<10} {n.file_path}:{n.name}")
104
+ for n in result.downstream:
105
+ click.echo(f" DOWN depth={n.depth} {n.kind:<10} {n.file_path}:{n.name}")
106
+ else:
107
+ console.print(f"\n[bold]Symbol Trace[/bold] — [cyan]{result.target}[/cyan] ({result.target_file})\n")
108
+ if not result.upstream and not result.downstream:
109
+ print_success("No execution relationships found.")
110
+ return
111
+
112
+ if result.upstream:
113
+ console.print(f"[bold]Upstream callers[/bold] (max depth {result.max_upstream_depth}):")
114
+ for n in result.upstream:
115
+ console.print(f" [yellow]{n.name}[/yellow] depth={n.depth} ({n.kind}) [dim]{n.file_path}[/dim]")
116
+
117
+ if result.downstream:
118
+ console.print(f"\n[bold]Downstream callees[/bold] (max depth {result.max_downstream_depth}):")
119
+ for n in result.downstream:
120
+ console.print(f" [green]{n.name}[/green] depth={n.depth} ({n.kind}) [dim]{n.file_path}[/dim]")
121
+
122
+ console.print(f"\n[bold]Edges:[/bold] {len(result.edges)} | [bold]Total nodes:[/bold] {result.total_nodes}")
123
+ console.print()
@@ -0,0 +1,58 @@
1
+ """CLI command: tui - Launch interactive terminal search interface."""
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.utils.logging import get_logger, print_error
11
+
12
+ logger = get_logger("cli.tui")
13
+
14
+
15
+ @click.command("tui")
16
+ @click.option(
17
+ "--path",
18
+ "-p",
19
+ default=".",
20
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
21
+ help="Project root path.",
22
+ )
23
+ @click.option(
24
+ "--mode",
25
+ "-m",
26
+ type=click.Choice(["semantic", "keyword", "regex", "hybrid"], case_sensitive=False),
27
+ default="hybrid",
28
+ help="Default search mode.",
29
+ )
30
+ @click.option(
31
+ "--top-k",
32
+ "-k",
33
+ default=10,
34
+ type=int,
35
+ help="Results per query.",
36
+ )
37
+ @click.pass_context
38
+ def tui_cmd(ctx: click.Context, path: str, mode: str, top_k: int) -> None:
39
+ """Launch the interactive terminal search interface.
40
+
41
+ Provides a live search REPL with mode switching and result preview.
42
+
43
+ Examples:
44
+
45
+ \b
46
+ codexa tui
47
+ codexa tui --mode hybrid -k 20
48
+ """
49
+ root = Path(path).resolve()
50
+ config_dir = AppConfig.config_dir(root)
51
+
52
+ if not config_dir.exists():
53
+ print_error(f"Project not initialized at {root}. Run 'codexa init' first.")
54
+ ctx.exit(1)
55
+ return
56
+
57
+ from semantic_code_intelligence.tui import run_tui
58
+ run_tui(root, mode=mode, top_k=top_k) # type: ignore[arg-type]
@@ -0,0 +1,127 @@
1
+ """CLI command: viz — generate Mermaid-compatible visualizations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+
8
+ import click
9
+
10
+ from semantic_code_intelligence.utils.logging import (
11
+ get_logger,
12
+ print_error,
13
+ print_info,
14
+ console,
15
+ )
16
+
17
+ logger = get_logger("cli.viz")
18
+
19
+
20
+ @click.command("viz")
21
+ @click.argument(
22
+ "kind",
23
+ type=click.Choice(["callgraph", "deps", "symbols", "workspace"], case_sensitive=False),
24
+ )
25
+ @click.option(
26
+ "--target",
27
+ "-t",
28
+ default="",
29
+ type=str,
30
+ help="Symbol name or file path to visualize.",
31
+ )
32
+ @click.option(
33
+ "--output",
34
+ "-o",
35
+ default=None,
36
+ type=click.Path(dir_okay=False, resolve_path=True),
37
+ help="Write Mermaid output to a file instead of stdout.",
38
+ )
39
+ @click.option(
40
+ "--json-output",
41
+ "--json",
42
+ "json_mode",
43
+ is_flag=True,
44
+ default=False,
45
+ help="Output as JSON with a 'mermaid' field.",
46
+ )
47
+ @click.option(
48
+ "--path",
49
+ "-p",
50
+ default=".",
51
+ type=click.Path(exists=True, file_okay=False, resolve_path=True),
52
+ help="Project root path.",
53
+ )
54
+ @click.pass_context
55
+ def viz_cmd(
56
+ ctx: click.Context,
57
+ kind: str,
58
+ target: str,
59
+ output: str | None,
60
+ json_mode: bool,
61
+ path: str,
62
+ ) -> None:
63
+ """Generate Mermaid-compatible diagrams from codebase analysis.
64
+
65
+ KIND is one of: callgraph, deps, symbols, workspace.
66
+
67
+ Examples:
68
+
69
+ codexa viz callgraph
70
+
71
+ codexa viz deps --target src/main.py
72
+
73
+ codexa viz symbols --target auth.py -o symbols.mmd
74
+
75
+ codexa viz callgraph --json
76
+ """
77
+ from semantic_code_intelligence.bridge.context_provider import ContextProvider
78
+ from semantic_code_intelligence.web.visualize import (
79
+ render_call_graph,
80
+ render_dependency_graph,
81
+ render_symbol_map,
82
+ render_workspace_graph,
83
+ )
84
+
85
+ project_root = Path(path)
86
+ provider = ContextProvider(project_root)
87
+
88
+ kind_lower = kind.lower()
89
+
90
+ try:
91
+ if kind_lower == "callgraph":
92
+ data = provider.get_call_graph(symbol_name=target)
93
+ mermaid = render_call_graph(data.get("edges", []))
94
+ elif kind_lower == "deps":
95
+ data = provider.get_dependencies(file_path=target)
96
+ mermaid = render_dependency_graph(data)
97
+ elif kind_lower == "symbols":
98
+ builder = provider._ensure_indexed()
99
+ symbols = builder.get_all_symbols()
100
+ if target:
101
+ symbols = [s for s in symbols if target in s.file_path]
102
+ sym_dicts = [s.to_dict() for s in symbols[:100]]
103
+ mermaid = render_symbol_map(sym_dicts, file_path=target)
104
+ elif kind_lower == "workspace":
105
+ # Try to load workspace repos
106
+ try:
107
+ from semantic_code_intelligence.workspace import Workspace
108
+ ws = Workspace.load(project_root)
109
+ repos = [r.to_dict() for r in ws.repos] if ws.repos else []
110
+ except Exception:
111
+ repos = []
112
+ mermaid = render_workspace_graph(repos)
113
+ else:
114
+ print_error(f"Unknown visualization kind: {kind}")
115
+ return
116
+ except Exception as exc:
117
+ print_error(f"Visualization error: {exc}")
118
+ return
119
+
120
+ # Output
121
+ if json_mode:
122
+ click.echo(json.dumps({"kind": kind_lower, "mermaid": mermaid}, indent=2))
123
+ elif output:
124
+ Path(output).write_text(mermaid, encoding="utf-8")
125
+ print_info(f"Written to {output}")
126
+ else:
127
+ console.print(mermaid)