code-analysis-client 1.0.2__tar.gz → 1.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/PKG-INFO +24 -1
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/README.md +23 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/__init__.py +14 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/client.py +7 -1
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/file_session.py +5 -18
- code_analysis_client-1.0.4/code_analysis_client/responses.py +45 -0
- code_analysis_client-1.0.4/code_analysis_client/server_api.py +113 -0
- code_analysis_client-1.0.4/code_analysis_client/universal_file.py +117 -0
- code_analysis_client-1.0.4/code_analysis_client/version.txt +1 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client.egg-info/PKG-INFO +24 -1
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client.egg-info/SOURCES.txt +3 -0
- code_analysis_client-1.0.2/code_analysis_client/version.txt +0 -1
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/commands_proxy.py +0 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/config.py +0 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/exceptions.py +0 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/py.typed +0 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/server_schema.py +0 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/validation.py +0 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client.egg-info/dependency_links.txt +0 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client.egg-info/requires.txt +0 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client.egg-info/top_level.txt +0 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/pyproject.toml +0 -0
- {code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-analysis-client
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Async JSON-RPC client for the code-analysis MCP server (mcp-proxy-adapter JsonRpcClient)
|
|
5
5
|
Author-email: Vasiliy Zdanovskiy <vasilyvz@gmail.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -75,6 +75,29 @@ async with CodeAnalysisAsyncClient(host="127.0.0.1", port=15001) as client:
|
|
|
75
75
|
|
|
76
76
|
Use `call_unified_validated` when you need queue polling. Pass `refresh_schema=True` on a single call to bypass the in-memory schema cache.
|
|
77
77
|
|
|
78
|
+
## High-level facades (aligned with server 1.0.3)
|
|
79
|
+
|
|
80
|
+
The client does **not** wrap CST commands (`cst_load_file`, …) or legacy file I/O
|
|
81
|
+
(`universal_file_read`, `read_project_text_file`, …). Those commands are removed
|
|
82
|
+
from the server registry. Use the facades below or generic `call` / `commands.*`.
|
|
83
|
+
|
|
84
|
+
| Facade | Property | Server commands |
|
|
85
|
+
|--------|----------|-----------------|
|
|
86
|
+
| Client DB sessions + transfer | `client.file_sessions` | `session_*`, `project_file_transfer_*`, `project_file_advisory_lock_batch` |
|
|
87
|
+
| Universal edit sessions | `client.universal_files` | `universal_file_open`, `edit`, `write`, `close`, `preview` |
|
|
88
|
+
| Any registered command | `client.call` / `client.commands.<name>` | schema from live `help()` |
|
|
89
|
+
|
|
90
|
+
Canonical command lists: `code_analysis_client.server_api` (also exported as
|
|
91
|
+
`REMOVED_COMMANDS`, `CLIENT_FACADE_COMMANDS`).
|
|
92
|
+
|
|
93
|
+
Sync check (in-process registry):
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pytest tests/test_client_server_api_sync.py
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Package version matches the **code-analysis** server project (currently **1.0.4**).
|
|
100
|
+
|
|
78
101
|
## Examples (this repository)
|
|
79
102
|
|
|
80
103
|
Runnable scripts live under `client/examples/`. **Long-form “man page” style
|
|
@@ -63,6 +63,29 @@ async with CodeAnalysisAsyncClient(host="127.0.0.1", port=15001) as client:
|
|
|
63
63
|
|
|
64
64
|
Use `call_unified_validated` when you need queue polling. Pass `refresh_schema=True` on a single call to bypass the in-memory schema cache.
|
|
65
65
|
|
|
66
|
+
## High-level facades (aligned with server 1.0.3)
|
|
67
|
+
|
|
68
|
+
The client does **not** wrap CST commands (`cst_load_file`, …) or legacy file I/O
|
|
69
|
+
(`universal_file_read`, `read_project_text_file`, …). Those commands are removed
|
|
70
|
+
from the server registry. Use the facades below or generic `call` / `commands.*`.
|
|
71
|
+
|
|
72
|
+
| Facade | Property | Server commands |
|
|
73
|
+
|--------|----------|-----------------|
|
|
74
|
+
| Client DB sessions + transfer | `client.file_sessions` | `session_*`, `project_file_transfer_*`, `project_file_advisory_lock_batch` |
|
|
75
|
+
| Universal edit sessions | `client.universal_files` | `universal_file_open`, `edit`, `write`, `close`, `preview` |
|
|
76
|
+
| Any registered command | `client.call` / `client.commands.<name>` | schema from live `help()` |
|
|
77
|
+
|
|
78
|
+
Canonical command lists: `code_analysis_client.server_api` (also exported as
|
|
79
|
+
`REMOVED_COMMANDS`, `CLIENT_FACADE_COMMANDS`).
|
|
80
|
+
|
|
81
|
+
Sync check (in-process registry):
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pytest tests/test_client_server_api_sync.py
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Package version matches the **code-analysis** server project (currently **1.0.4**).
|
|
88
|
+
|
|
66
89
|
## Examples (this repository)
|
|
67
90
|
|
|
68
91
|
Runnable scripts live under `client/examples/`. **Long-form “man page” style
|
|
@@ -18,6 +18,14 @@ from code_analysis_client.config import (
|
|
|
18
18
|
)
|
|
19
19
|
from code_analysis_client.exceptions import ClientValidationError
|
|
20
20
|
from code_analysis_client.file_session import FileSessionClient, SessionNotFoundError
|
|
21
|
+
from code_analysis_client.server_api import (
|
|
22
|
+
CLIENT_FACADE_COMMANDS,
|
|
23
|
+
CST_REMOVED_COMMANDS,
|
|
24
|
+
LEGACY_REMOVED_COMMANDS,
|
|
25
|
+
REMOVED_COMMANDS,
|
|
26
|
+
UNIVERSAL_FILE_COMMANDS,
|
|
27
|
+
)
|
|
28
|
+
from code_analysis_client.universal_file import UniversalFileClient
|
|
21
29
|
from code_analysis_client.server_schema import (
|
|
22
30
|
fetch_command_schema_from_server,
|
|
23
31
|
parse_schema_from_help_payload,
|
|
@@ -28,10 +36,16 @@ from code_analysis_client.validation import (
|
|
|
28
36
|
)
|
|
29
37
|
|
|
30
38
|
__all__ = [
|
|
39
|
+
"CLIENT_FACADE_COMMANDS",
|
|
40
|
+
"CST_REMOVED_COMMANDS",
|
|
31
41
|
"ClientValidationError",
|
|
32
42
|
"CodeAnalysisAsyncClient",
|
|
33
43
|
"FileSessionClient",
|
|
44
|
+
"LEGACY_REMOVED_COMMANDS",
|
|
45
|
+
"REMOVED_COMMANDS",
|
|
34
46
|
"SessionNotFoundError",
|
|
47
|
+
"UNIVERSAL_FILE_COMMANDS",
|
|
48
|
+
"UniversalFileClient",
|
|
35
49
|
"ValidatedCommandsProxy",
|
|
36
50
|
"adapter_settings_from_server_config",
|
|
37
51
|
"adapter_settings_to_jsonrpc_kwargs",
|
|
@@ -22,6 +22,7 @@ from code_analysis_client.config import (
|
|
|
22
22
|
load_server_config,
|
|
23
23
|
)
|
|
24
24
|
from code_analysis_client.file_session import FileSessionClient
|
|
25
|
+
from code_analysis_client.universal_file import UniversalFileClient
|
|
25
26
|
from code_analysis_client.server_schema import fetch_command_schema_from_server
|
|
26
27
|
from code_analysis_client.validation import (
|
|
27
28
|
prepare_params_for_schema,
|
|
@@ -122,9 +123,14 @@ class CodeAnalysisAsyncClient:
|
|
|
122
123
|
|
|
123
124
|
@property
|
|
124
125
|
def file_sessions(self) -> FileSessionClient:
|
|
125
|
-
"""Session-scoped download/upload and lock workflow (
|
|
126
|
+
"""Session-scoped download/upload and lock workflow (``session_*``, transfer)."""
|
|
126
127
|
return FileSessionClient(self)
|
|
127
128
|
|
|
129
|
+
@property
|
|
130
|
+
def universal_files(self) -> UniversalFileClient:
|
|
131
|
+
"""Universal edit-session workflow (``universal_file_*`` commands)."""
|
|
132
|
+
return UniversalFileClient(self)
|
|
133
|
+
|
|
128
134
|
async def get_command_schema(
|
|
129
135
|
self, command: str, *, refresh: bool = False
|
|
130
136
|
) -> Dict[str, Any]:
|
{code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/file_session.py
RENAMED
|
@@ -15,6 +15,7 @@ from pathlib import Path
|
|
|
15
15
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
|
|
16
16
|
|
|
17
17
|
from code_analysis_client.exceptions import ClientValidationError
|
|
18
|
+
from code_analysis_client.responses import unwrap_command_result
|
|
18
19
|
|
|
19
20
|
if TYPE_CHECKING:
|
|
20
21
|
from code_analysis_client.client import CodeAnalysisAsyncClient
|
|
@@ -25,24 +26,10 @@ class SessionNotFoundError(ClientValidationError):
|
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
def _unwrap(data: Dict[str, Any]) -> Dict[str, Any]:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
message = data.get("message")
|
|
33
|
-
err = data.get("error")
|
|
34
|
-
if code_raw is None and isinstance(err, dict):
|
|
35
|
-
code_raw = err.get("code")
|
|
36
|
-
if message is None:
|
|
37
|
-
message = err.get("message")
|
|
38
|
-
elif code_raw is None and isinstance(err, str):
|
|
39
|
-
code_raw = err
|
|
40
|
-
code = str(code_raw or "COMMAND_FAILED")
|
|
41
|
-
if message is None:
|
|
42
|
-
message = str(data)
|
|
43
|
-
if code == "SESSION_NOT_FOUND":
|
|
44
|
-
raise SessionNotFoundError(message, field="session_id", details=data)
|
|
45
|
-
raise ClientValidationError(message, field="command", details=data)
|
|
29
|
+
return unwrap_command_result(
|
|
30
|
+
data,
|
|
31
|
+
session_not_found_type=SessionNotFoundError,
|
|
32
|
+
)
|
|
46
33
|
|
|
47
34
|
|
|
48
35
|
class FileSessionClient:
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Parse JSON-RPC command envelopes from code-analysis-server."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict
|
|
6
|
+
|
|
7
|
+
from code_analysis_client.exceptions import ClientValidationError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def command_error_code(data: Dict[str, Any]) -> str:
|
|
11
|
+
"""Return domain or JSON-RPC error code from a failed command response."""
|
|
12
|
+
if data.get("success") is True:
|
|
13
|
+
return ""
|
|
14
|
+
top = data.get("code")
|
|
15
|
+
if top is not None and str(top).strip():
|
|
16
|
+
return str(top).strip()
|
|
17
|
+
err = data.get("error")
|
|
18
|
+
if isinstance(err, dict):
|
|
19
|
+
nested = err.get("code")
|
|
20
|
+
if nested is not None:
|
|
21
|
+
return str(nested).strip()
|
|
22
|
+
if isinstance(err, str) and err.strip():
|
|
23
|
+
return err.strip()
|
|
24
|
+
return ""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def unwrap_command_result(
|
|
28
|
+
data: Dict[str, Any],
|
|
29
|
+
*,
|
|
30
|
+
session_not_found_type: type[ClientValidationError] | None = None,
|
|
31
|
+
) -> Dict[str, Any]:
|
|
32
|
+
"""Return success ``data`` dict or raise :class:`ClientValidationError`."""
|
|
33
|
+
if data.get("success"):
|
|
34
|
+
inner = data.get("data")
|
|
35
|
+
return inner if isinstance(inner, dict) else data
|
|
36
|
+
code = command_error_code(data)
|
|
37
|
+
message = data.get("message")
|
|
38
|
+
err = data.get("error")
|
|
39
|
+
if message is None and isinstance(err, dict):
|
|
40
|
+
message = err.get("message")
|
|
41
|
+
if message is None:
|
|
42
|
+
message = str(data)
|
|
43
|
+
if code == "SESSION_NOT_FOUND" and session_not_found_type is not None:
|
|
44
|
+
raise session_not_found_type(message, field="session_id", details=data)
|
|
45
|
+
raise ClientValidationError(message, field="command", details=data)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Canonical command names for the high-level client API vs the live server registry.
|
|
3
|
+
|
|
4
|
+
The generic client (:class:`CodeAnalysisAsyncClient.call`) can invoke any command
|
|
5
|
+
returned by server ``help``. Facade modules (:mod:`file_session`, :mod:`universal_file`)
|
|
6
|
+
must only reference commands listed here — and every name in
|
|
7
|
+
:data:`CLIENT_FACADE_COMMANDS` must be registered on the server.
|
|
8
|
+
|
|
9
|
+
Author: Vasiliy Zdanovskiy
|
|
10
|
+
email: vasilyvz@gmail.com
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Callable, FrozenSet
|
|
16
|
+
|
|
17
|
+
# Removed from the public server surface — do not use in client facades or docs.
|
|
18
|
+
LEGACY_REMOVED_COMMANDS: FrozenSet[str] = frozenset(
|
|
19
|
+
{
|
|
20
|
+
"universal_file_read",
|
|
21
|
+
"universal_file_save",
|
|
22
|
+
"universal_file_replace",
|
|
23
|
+
"universal_file_delete",
|
|
24
|
+
"read_project_text_file",
|
|
25
|
+
"write_project_text_lines",
|
|
26
|
+
"create_text_file",
|
|
27
|
+
"replace_file_lines",
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# CST tree MCP workflow — modules may exist in the repo but commands are not registered.
|
|
32
|
+
CST_REMOVED_COMMANDS: FrozenSet[str] = frozenset(
|
|
33
|
+
{
|
|
34
|
+
"cst_load_file",
|
|
35
|
+
"cst_save_tree",
|
|
36
|
+
"cst_modify_tree",
|
|
37
|
+
"cst_create_file",
|
|
38
|
+
"cst_find_node",
|
|
39
|
+
"cst_get_node_info",
|
|
40
|
+
"cst_get_node_by_range",
|
|
41
|
+
"cst_get_node_at_line",
|
|
42
|
+
"cst_reload_tree",
|
|
43
|
+
"cst_convert_and_save",
|
|
44
|
+
"list_cst_blocks",
|
|
45
|
+
"query_cst",
|
|
46
|
+
"get_file_lines",
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
REMOVED_COMMANDS: FrozenSet[str] = LEGACY_REMOVED_COMMANDS | CST_REMOVED_COMMANDS
|
|
51
|
+
|
|
52
|
+
FILE_SESSION_COMMANDS: FrozenSet[str] = frozenset(
|
|
53
|
+
{
|
|
54
|
+
"session_create",
|
|
55
|
+
"session_delete",
|
|
56
|
+
"session_list",
|
|
57
|
+
"session_open_file",
|
|
58
|
+
"session_close_file",
|
|
59
|
+
"session_list_file_locks",
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
TRANSFER_AND_LOCK_COMMANDS: FrozenSet[str] = frozenset(
|
|
64
|
+
{
|
|
65
|
+
"project_file_transfer_download_begin",
|
|
66
|
+
"project_file_transfer_upload_save",
|
|
67
|
+
"project_file_advisory_lock_batch",
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
UNIVERSAL_FILE_COMMANDS: FrozenSet[str] = frozenset(
|
|
72
|
+
{
|
|
73
|
+
"universal_file_open",
|
|
74
|
+
"universal_file_edit",
|
|
75
|
+
"universal_file_write",
|
|
76
|
+
"universal_file_close",
|
|
77
|
+
"universal_file_preview",
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
CLIENT_FACADE_COMMANDS: FrozenSet[str] = (
|
|
82
|
+
FILE_SESSION_COMMANDS | TRANSFER_AND_LOCK_COMMANDS | UNIVERSAL_FILE_COMMANDS
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _command_registered(get_command: Callable[[str], object], name: str) -> bool:
|
|
87
|
+
try:
|
|
88
|
+
get_command(name)
|
|
89
|
+
return True
|
|
90
|
+
except KeyError:
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def assert_facade_commands_registered(get_command: Callable[[str], object]) -> None:
|
|
95
|
+
"""Raise ``KeyError`` if any facade command is missing from the server registry."""
|
|
96
|
+
missing = [
|
|
97
|
+
name
|
|
98
|
+
for name in sorted(CLIENT_FACADE_COMMANDS)
|
|
99
|
+
if not _command_registered(get_command, name)
|
|
100
|
+
]
|
|
101
|
+
if missing:
|
|
102
|
+
raise KeyError(f"Client facade commands not registered on server: {missing}")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def assert_removed_commands_absent(get_command: Callable[[str], object]) -> None:
|
|
106
|
+
"""Raise ``AssertionError`` if a removed command is still registered."""
|
|
107
|
+
present = [
|
|
108
|
+
name
|
|
109
|
+
for name in sorted(REMOVED_COMMANDS)
|
|
110
|
+
if _command_registered(get_command, name)
|
|
111
|
+
]
|
|
112
|
+
if present:
|
|
113
|
+
raise AssertionError(f"Removed commands still registered: {present}")
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Universal file edit-session workflow on top of :class:`CodeAnalysisAsyncClient`.
|
|
3
|
+
|
|
4
|
+
Wraps ``universal_file_open`` / ``edit`` / ``write`` / ``close`` / ``preview`` only.
|
|
5
|
+
Legacy ``universal_file_read`` / ``universal_file_save`` and CST commands are not
|
|
6
|
+
part of this API (see :mod:`server_api`).
|
|
7
|
+
|
|
8
|
+
Author: Vasiliy Zdanovskiy
|
|
9
|
+
email: vasilyvz@gmail.com
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
15
|
+
|
|
16
|
+
from code_analysis_client.responses import unwrap_command_result
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from code_analysis_client.client import CodeAnalysisAsyncClient
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class UniversalFileClient:
|
|
23
|
+
"""Edit-session workflow for project files (open → edit → write → close)."""
|
|
24
|
+
|
|
25
|
+
__slots__ = ("_client",)
|
|
26
|
+
|
|
27
|
+
def __init__(self, client: CodeAnalysisAsyncClient) -> None:
|
|
28
|
+
self._client = client
|
|
29
|
+
|
|
30
|
+
async def open(
|
|
31
|
+
self,
|
|
32
|
+
project_id: str,
|
|
33
|
+
file_path: str,
|
|
34
|
+
*,
|
|
35
|
+
create: bool = False,
|
|
36
|
+
initial_content: Optional[str] = None,
|
|
37
|
+
) -> Dict[str, Any]:
|
|
38
|
+
"""Start an edit session (``universal_file_open``)."""
|
|
39
|
+
params: Dict[str, Any] = {
|
|
40
|
+
"project_id": project_id,
|
|
41
|
+
"file_path": file_path,
|
|
42
|
+
"create": create,
|
|
43
|
+
}
|
|
44
|
+
if initial_content is not None:
|
|
45
|
+
params["initial_content"] = initial_content
|
|
46
|
+
return unwrap_command_result(
|
|
47
|
+
await self._client.call_validated("universal_file_open", params)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
async def edit(
|
|
51
|
+
self,
|
|
52
|
+
project_id: str,
|
|
53
|
+
session_id: str,
|
|
54
|
+
operations: List[Dict[str, Any]],
|
|
55
|
+
) -> Dict[str, Any]:
|
|
56
|
+
"""Apply draft mutations (``universal_file_edit``)."""
|
|
57
|
+
return unwrap_command_result(
|
|
58
|
+
await self._client.call_validated(
|
|
59
|
+
"universal_file_edit",
|
|
60
|
+
{
|
|
61
|
+
"project_id": project_id,
|
|
62
|
+
"session_id": session_id,
|
|
63
|
+
"operations": operations,
|
|
64
|
+
},
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
async def write(
|
|
69
|
+
self,
|
|
70
|
+
project_id: str,
|
|
71
|
+
session_id: str,
|
|
72
|
+
*,
|
|
73
|
+
write_mode: str = "commit",
|
|
74
|
+
) -> Dict[str, Any]:
|
|
75
|
+
"""Persist or preview draft (``universal_file_write``)."""
|
|
76
|
+
return unwrap_command_result(
|
|
77
|
+
await self._client.call_validated(
|
|
78
|
+
"universal_file_write",
|
|
79
|
+
{
|
|
80
|
+
"project_id": project_id,
|
|
81
|
+
"session_id": session_id,
|
|
82
|
+
"write_mode": write_mode,
|
|
83
|
+
},
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
async def close(
|
|
88
|
+
self,
|
|
89
|
+
project_id: str,
|
|
90
|
+
session_id: str,
|
|
91
|
+
) -> Dict[str, Any]:
|
|
92
|
+
"""End edit session (``universal_file_close``)."""
|
|
93
|
+
return unwrap_command_result(
|
|
94
|
+
await self._client.call_validated(
|
|
95
|
+
"universal_file_close",
|
|
96
|
+
{
|
|
97
|
+
"project_id": project_id,
|
|
98
|
+
"session_id": session_id,
|
|
99
|
+
},
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
async def preview(
|
|
104
|
+
self,
|
|
105
|
+
project_id: str,
|
|
106
|
+
file_path: str,
|
|
107
|
+
**kwargs: Any,
|
|
108
|
+
) -> Dict[str, Any]:
|
|
109
|
+
"""Structured read-only preview (``universal_file_preview``)."""
|
|
110
|
+
params: Dict[str, Any] = {
|
|
111
|
+
"project_id": project_id,
|
|
112
|
+
"file_path": file_path,
|
|
113
|
+
}
|
|
114
|
+
params.update(kwargs)
|
|
115
|
+
return unwrap_command_result(
|
|
116
|
+
await self._client.call_validated("universal_file_preview", params)
|
|
117
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.4
|
{code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-analysis-client
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Async JSON-RPC client for the code-analysis MCP server (mcp-proxy-adapter JsonRpcClient)
|
|
5
5
|
Author-email: Vasiliy Zdanovskiy <vasilyvz@gmail.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -75,6 +75,29 @@ async with CodeAnalysisAsyncClient(host="127.0.0.1", port=15001) as client:
|
|
|
75
75
|
|
|
76
76
|
Use `call_unified_validated` when you need queue polling. Pass `refresh_schema=True` on a single call to bypass the in-memory schema cache.
|
|
77
77
|
|
|
78
|
+
## High-level facades (aligned with server 1.0.3)
|
|
79
|
+
|
|
80
|
+
The client does **not** wrap CST commands (`cst_load_file`, …) or legacy file I/O
|
|
81
|
+
(`universal_file_read`, `read_project_text_file`, …). Those commands are removed
|
|
82
|
+
from the server registry. Use the facades below or generic `call` / `commands.*`.
|
|
83
|
+
|
|
84
|
+
| Facade | Property | Server commands |
|
|
85
|
+
|--------|----------|-----------------|
|
|
86
|
+
| Client DB sessions + transfer | `client.file_sessions` | `session_*`, `project_file_transfer_*`, `project_file_advisory_lock_batch` |
|
|
87
|
+
| Universal edit sessions | `client.universal_files` | `universal_file_open`, `edit`, `write`, `close`, `preview` |
|
|
88
|
+
| Any registered command | `client.call` / `client.commands.<name>` | schema from live `help()` |
|
|
89
|
+
|
|
90
|
+
Canonical command lists: `code_analysis_client.server_api` (also exported as
|
|
91
|
+
`REMOVED_COMMANDS`, `CLIENT_FACADE_COMMANDS`).
|
|
92
|
+
|
|
93
|
+
Sync check (in-process registry):
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pytest tests/test_client_server_api_sync.py
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Package version matches the **code-analysis** server project (currently **1.0.4**).
|
|
100
|
+
|
|
78
101
|
## Examples (this repository)
|
|
79
102
|
|
|
80
103
|
Runnable scripts live under `client/examples/`. **Long-form “man page” style
|
{code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client.egg-info/SOURCES.txt
RENAMED
|
@@ -7,7 +7,10 @@ code_analysis_client/config.py
|
|
|
7
7
|
code_analysis_client/exceptions.py
|
|
8
8
|
code_analysis_client/file_session.py
|
|
9
9
|
code_analysis_client/py.typed
|
|
10
|
+
code_analysis_client/responses.py
|
|
11
|
+
code_analysis_client/server_api.py
|
|
10
12
|
code_analysis_client/server_schema.py
|
|
13
|
+
code_analysis_client/universal_file.py
|
|
11
14
|
code_analysis_client/validation.py
|
|
12
15
|
code_analysis_client/version.txt
|
|
13
16
|
code_analysis_client.egg-info/PKG-INFO
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.0.2
|
{code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/commands_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/server_schema.py
RENAMED
|
File without changes
|
{code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client/validation.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_analysis_client-1.0.2 → code_analysis_client-1.0.4}/code_analysis_client.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|