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.
- codexa-0.4.0.dist-info/METADATA +650 -0
- codexa-0.4.0.dist-info/RECORD +189 -0
- codexa-0.4.0.dist-info/WHEEL +5 -0
- codexa-0.4.0.dist-info/entry_points.txt +2 -0
- codexa-0.4.0.dist-info/licenses/LICENSE +21 -0
- codexa-0.4.0.dist-info/top_level.txt +1 -0
- semantic_code_intelligence/__init__.py +5 -0
- semantic_code_intelligence/analysis/__init__.py +21 -0
- semantic_code_intelligence/analysis/ai_features.py +351 -0
- semantic_code_intelligence/bridge/__init__.py +28 -0
- semantic_code_intelligence/bridge/context_provider.py +245 -0
- semantic_code_intelligence/bridge/protocol.py +167 -0
- semantic_code_intelligence/bridge/server.py +348 -0
- semantic_code_intelligence/bridge/vscode.py +271 -0
- semantic_code_intelligence/ci/__init__.py +13 -0
- semantic_code_intelligence/ci/hooks.py +98 -0
- semantic_code_intelligence/ci/hotspots.py +272 -0
- semantic_code_intelligence/ci/impact.py +246 -0
- semantic_code_intelligence/ci/metrics.py +591 -0
- semantic_code_intelligence/ci/pr.py +412 -0
- semantic_code_intelligence/ci/quality.py +557 -0
- semantic_code_intelligence/ci/templates.py +164 -0
- semantic_code_intelligence/ci/trace.py +224 -0
- semantic_code_intelligence/cli/__init__.py +0 -0
- semantic_code_intelligence/cli/commands/__init__.py +0 -0
- semantic_code_intelligence/cli/commands/ask_cmd.py +153 -0
- semantic_code_intelligence/cli/commands/benchmark_cmd.py +303 -0
- semantic_code_intelligence/cli/commands/chat_cmd.py +252 -0
- semantic_code_intelligence/cli/commands/ci_gen_cmd.py +74 -0
- semantic_code_intelligence/cli/commands/context_cmd.py +120 -0
- semantic_code_intelligence/cli/commands/cross_refactor_cmd.py +113 -0
- semantic_code_intelligence/cli/commands/deps_cmd.py +91 -0
- semantic_code_intelligence/cli/commands/docs_cmd.py +101 -0
- semantic_code_intelligence/cli/commands/doctor_cmd.py +147 -0
- semantic_code_intelligence/cli/commands/evolve_cmd.py +171 -0
- semantic_code_intelligence/cli/commands/explain_cmd.py +112 -0
- semantic_code_intelligence/cli/commands/gate_cmd.py +135 -0
- semantic_code_intelligence/cli/commands/grep_cmd.py +234 -0
- semantic_code_intelligence/cli/commands/hotspots_cmd.py +119 -0
- semantic_code_intelligence/cli/commands/impact_cmd.py +131 -0
- semantic_code_intelligence/cli/commands/index_cmd.py +138 -0
- semantic_code_intelligence/cli/commands/init_cmd.py +152 -0
- semantic_code_intelligence/cli/commands/investigate_cmd.py +163 -0
- semantic_code_intelligence/cli/commands/languages_cmd.py +101 -0
- semantic_code_intelligence/cli/commands/lsp_cmd.py +49 -0
- semantic_code_intelligence/cli/commands/mcp_cmd.py +50 -0
- semantic_code_intelligence/cli/commands/metrics_cmd.py +264 -0
- semantic_code_intelligence/cli/commands/models_cmd.py +157 -0
- semantic_code_intelligence/cli/commands/plugin_cmd.py +275 -0
- semantic_code_intelligence/cli/commands/pr_summary_cmd.py +178 -0
- semantic_code_intelligence/cli/commands/quality_cmd.py +208 -0
- semantic_code_intelligence/cli/commands/refactor_cmd.py +103 -0
- semantic_code_intelligence/cli/commands/review_cmd.py +88 -0
- semantic_code_intelligence/cli/commands/search_cmd.py +236 -0
- semantic_code_intelligence/cli/commands/serve_cmd.py +117 -0
- semantic_code_intelligence/cli/commands/suggest_cmd.py +100 -0
- semantic_code_intelligence/cli/commands/summary_cmd.py +78 -0
- semantic_code_intelligence/cli/commands/tool_cmd.py +282 -0
- semantic_code_intelligence/cli/commands/trace_cmd.py +123 -0
- semantic_code_intelligence/cli/commands/tui_cmd.py +58 -0
- semantic_code_intelligence/cli/commands/viz_cmd.py +127 -0
- semantic_code_intelligence/cli/commands/watch_cmd.py +72 -0
- semantic_code_intelligence/cli/commands/web_cmd.py +61 -0
- semantic_code_intelligence/cli/commands/workspace_cmd.py +250 -0
- semantic_code_intelligence/cli/main.py +65 -0
- semantic_code_intelligence/cli/router.py +92 -0
- semantic_code_intelligence/config/__init__.py +0 -0
- semantic_code_intelligence/config/settings.py +260 -0
- semantic_code_intelligence/context/__init__.py +19 -0
- semantic_code_intelligence/context/engine.py +429 -0
- semantic_code_intelligence/context/memory.py +253 -0
- semantic_code_intelligence/daemon/__init__.py +1 -0
- semantic_code_intelligence/daemon/watcher.py +515 -0
- semantic_code_intelligence/docs/__init__.py +1080 -0
- semantic_code_intelligence/embeddings/__init__.py +0 -0
- semantic_code_intelligence/embeddings/enhanced.py +131 -0
- semantic_code_intelligence/embeddings/generator.py +149 -0
- semantic_code_intelligence/embeddings/model_registry.py +100 -0
- semantic_code_intelligence/evolution/__init__.py +1 -0
- semantic_code_intelligence/evolution/budget_guard.py +111 -0
- semantic_code_intelligence/evolution/commit_manager.py +88 -0
- semantic_code_intelligence/evolution/context_builder.py +131 -0
- semantic_code_intelligence/evolution/engine.py +249 -0
- semantic_code_intelligence/evolution/patch_generator.py +229 -0
- semantic_code_intelligence/evolution/task_selector.py +214 -0
- semantic_code_intelligence/evolution/test_runner.py +111 -0
- semantic_code_intelligence/indexing/__init__.py +0 -0
- semantic_code_intelligence/indexing/chunker.py +174 -0
- semantic_code_intelligence/indexing/parallel.py +86 -0
- semantic_code_intelligence/indexing/scanner.py +146 -0
- semantic_code_intelligence/indexing/semantic_chunker.py +337 -0
- semantic_code_intelligence/llm/__init__.py +62 -0
- semantic_code_intelligence/llm/cache.py +219 -0
- semantic_code_intelligence/llm/cached_provider.py +145 -0
- semantic_code_intelligence/llm/conversation.py +190 -0
- semantic_code_intelligence/llm/cross_refactor.py +272 -0
- semantic_code_intelligence/llm/investigation.py +274 -0
- semantic_code_intelligence/llm/mock_provider.py +77 -0
- semantic_code_intelligence/llm/ollama_provider.py +122 -0
- semantic_code_intelligence/llm/openai_provider.py +100 -0
- semantic_code_intelligence/llm/provider.py +92 -0
- semantic_code_intelligence/llm/rate_limiter.py +164 -0
- semantic_code_intelligence/llm/reasoning.py +438 -0
- semantic_code_intelligence/llm/safety.py +110 -0
- semantic_code_intelligence/llm/streaming.py +251 -0
- semantic_code_intelligence/lsp/__init__.py +609 -0
- semantic_code_intelligence/mcp/__init__.py +393 -0
- semantic_code_intelligence/parsing/__init__.py +19 -0
- semantic_code_intelligence/parsing/parser.py +375 -0
- semantic_code_intelligence/plugins/__init__.py +255 -0
- semantic_code_intelligence/plugins/examples/__init__.py +1 -0
- semantic_code_intelligence/plugins/examples/code_quality.py +73 -0
- semantic_code_intelligence/plugins/examples/search_annotator.py +56 -0
- semantic_code_intelligence/scalability/__init__.py +205 -0
- semantic_code_intelligence/search/__init__.py +0 -0
- semantic_code_intelligence/search/formatter.py +123 -0
- semantic_code_intelligence/search/grep.py +361 -0
- semantic_code_intelligence/search/hybrid_search.py +170 -0
- semantic_code_intelligence/search/keyword_search.py +311 -0
- semantic_code_intelligence/search/section_expander.py +103 -0
- semantic_code_intelligence/services/__init__.py +0 -0
- semantic_code_intelligence/services/indexing_service.py +630 -0
- semantic_code_intelligence/services/search_service.py +269 -0
- semantic_code_intelligence/storage/__init__.py +0 -0
- semantic_code_intelligence/storage/chunk_hash_store.py +86 -0
- semantic_code_intelligence/storage/hash_store.py +66 -0
- semantic_code_intelligence/storage/index_manifest.py +85 -0
- semantic_code_intelligence/storage/index_stats.py +138 -0
- semantic_code_intelligence/storage/query_history.py +160 -0
- semantic_code_intelligence/storage/symbol_registry.py +209 -0
- semantic_code_intelligence/storage/vector_store.py +297 -0
- semantic_code_intelligence/tests/__init__.py +0 -0
- semantic_code_intelligence/tests/test_ai_features.py +351 -0
- semantic_code_intelligence/tests/test_chunker.py +119 -0
- semantic_code_intelligence/tests/test_cli.py +188 -0
- semantic_code_intelligence/tests/test_config.py +154 -0
- semantic_code_intelligence/tests/test_context.py +381 -0
- semantic_code_intelligence/tests/test_embeddings.py +73 -0
- semantic_code_intelligence/tests/test_endtoend.py +1142 -0
- semantic_code_intelligence/tests/test_enhanced_embeddings.py +92 -0
- semantic_code_intelligence/tests/test_hash_store.py +79 -0
- semantic_code_intelligence/tests/test_logging.py +55 -0
- semantic_code_intelligence/tests/test_new_cli.py +138 -0
- semantic_code_intelligence/tests/test_parser.py +495 -0
- semantic_code_intelligence/tests/test_phase10.py +355 -0
- semantic_code_intelligence/tests/test_phase11.py +593 -0
- semantic_code_intelligence/tests/test_phase12.py +375 -0
- semantic_code_intelligence/tests/test_phase13.py +663 -0
- semantic_code_intelligence/tests/test_phase14.py +568 -0
- semantic_code_intelligence/tests/test_phase15.py +814 -0
- semantic_code_intelligence/tests/test_phase16.py +792 -0
- semantic_code_intelligence/tests/test_phase17.py +815 -0
- semantic_code_intelligence/tests/test_phase18.py +934 -0
- semantic_code_intelligence/tests/test_phase19.py +986 -0
- semantic_code_intelligence/tests/test_phase20.py +2753 -0
- semantic_code_intelligence/tests/test_phase20b.py +2058 -0
- semantic_code_intelligence/tests/test_phase20c.py +962 -0
- semantic_code_intelligence/tests/test_phase21.py +428 -0
- semantic_code_intelligence/tests/test_phase22.py +799 -0
- semantic_code_intelligence/tests/test_phase23.py +783 -0
- semantic_code_intelligence/tests/test_phase24.py +715 -0
- semantic_code_intelligence/tests/test_phase25.py +496 -0
- semantic_code_intelligence/tests/test_phase26.py +251 -0
- semantic_code_intelligence/tests/test_phase27.py +531 -0
- semantic_code_intelligence/tests/test_phase8.py +592 -0
- semantic_code_intelligence/tests/test_phase9.py +643 -0
- semantic_code_intelligence/tests/test_plugins.py +293 -0
- semantic_code_intelligence/tests/test_priority_features.py +727 -0
- semantic_code_intelligence/tests/test_router.py +41 -0
- semantic_code_intelligence/tests/test_scalability.py +138 -0
- semantic_code_intelligence/tests/test_scanner.py +125 -0
- semantic_code_intelligence/tests/test_search.py +160 -0
- semantic_code_intelligence/tests/test_semantic_chunker.py +255 -0
- semantic_code_intelligence/tests/test_tools.py +182 -0
- semantic_code_intelligence/tests/test_vector_store.py +151 -0
- semantic_code_intelligence/tests/test_watcher.py +211 -0
- semantic_code_intelligence/tools/__init__.py +442 -0
- semantic_code_intelligence/tools/executor.py +232 -0
- semantic_code_intelligence/tools/protocol.py +200 -0
- semantic_code_intelligence/tui/__init__.py +454 -0
- semantic_code_intelligence/utils/__init__.py +0 -0
- semantic_code_intelligence/utils/logging.py +112 -0
- semantic_code_intelligence/version.py +3 -0
- semantic_code_intelligence/web/__init__.py +11 -0
- semantic_code_intelligence/web/api.py +289 -0
- semantic_code_intelligence/web/server.py +397 -0
- semantic_code_intelligence/web/ui.py +659 -0
- semantic_code_intelligence/web/visualize.py +226 -0
- 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
|