code-analysis-client 1.0.9__tar.gz → 1.6.39__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.9 → code_analysis_client-1.6.39}/PKG-INFO +4 -4
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/README.md +2 -2
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/__init__.py +1 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/client.py +3 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/commands_proxy.py +3 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/config.py +3 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/exceptions.py +1 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/file_session.py +33 -24
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/server_api.py +111 -10
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/universal_file.py +17 -4
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/validation.py +3 -6
- code_analysis_client-1.6.39/code_analysis_client/version.txt +1 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client.egg-info/PKG-INFO +4 -4
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client.egg-info/requires.txt +1 -1
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/pyproject.toml +1 -1
- code_analysis_client-1.0.9/code_analysis_client/version.txt +0 -1
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/py.typed +0 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/responses.py +0 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/server_schema.py +0 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client.egg-info/SOURCES.txt +0 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client.egg-info/dependency_links.txt +0 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client.egg-info/top_level.txt +0 -0
- {code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/setup.cfg +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-analysis-client
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.39
|
|
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
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
|
-
Requires-Dist: mcp-proxy-adapter>=8.10.
|
|
8
|
+
Requires-Dist: mcp-proxy-adapter>=8.10.15
|
|
9
9
|
Provides-Extra: dev
|
|
10
10
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
11
11
|
Requires-Dist: pytest-asyncio>=0.25.0; extra == "dev"
|
|
@@ -97,8 +97,8 @@ Sync checks (in-process registry):
|
|
|
97
97
|
pytest tests/test_client_server_api_sync.py tests/test_code_analysis_client.py -k session
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
Package version is in ``
|
|
101
|
-
|
|
100
|
+
Package version is in the root ``pyproject.toml``; before a client wheel build run
|
|
101
|
+
``python scripts/sync_code_analysis_client_version.py`` (also done by ``release_build.sh``).
|
|
102
102
|
|
|
103
103
|
## Examples (this repository)
|
|
104
104
|
|
|
@@ -85,8 +85,8 @@ Sync checks (in-process registry):
|
|
|
85
85
|
pytest tests/test_client_server_api_sync.py tests/test_code_analysis_client.py -k session
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
Package version is in ``
|
|
89
|
-
|
|
88
|
+
Package version is in the root ``pyproject.toml``; before a client wheel build run
|
|
89
|
+
``python scripts/sync_code_analysis_client_version.py`` (also done by ``release_build.sh``).
|
|
90
90
|
|
|
91
91
|
## Examples (this repository)
|
|
92
92
|
|
|
@@ -228,10 +228,13 @@ class CodeAnalysisAsyncClient:
|
|
|
228
228
|
)
|
|
229
229
|
|
|
230
230
|
async def close(self) -> None:
|
|
231
|
+
"""Close the underlying JSON-RPC transport."""
|
|
231
232
|
await self._rpc.close()
|
|
232
233
|
|
|
233
234
|
async def __aenter__(self) -> CodeAnalysisAsyncClient:
|
|
235
|
+
"""Enter async context manager and return this client."""
|
|
234
236
|
return self
|
|
235
237
|
|
|
236
238
|
async def __aexit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
|
|
239
|
+
"""Close the client when leaving an async context manager block."""
|
|
237
240
|
await self.close()
|
{code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/commands_proxy.py
RENAMED
|
@@ -19,6 +19,7 @@ class ValidatedCommandsProxy:
|
|
|
19
19
|
__slots__ = ("_client",)
|
|
20
20
|
|
|
21
21
|
def __init__(self, client: CodeAnalysisAsyncClient) -> None:
|
|
22
|
+
"""Store the client used for schema lookup and validated command calls."""
|
|
22
23
|
object.__setattr__(self, "_client", client)
|
|
23
24
|
|
|
24
25
|
def clear_schema_cache(self) -> None:
|
|
@@ -47,10 +48,12 @@ class ValidatedCommandsProxy:
|
|
|
47
48
|
return cast(Dict[str, Any], await self._client.call_validated(command, merged))
|
|
48
49
|
|
|
49
50
|
def __getattr__(self, name: str) -> Any:
|
|
51
|
+
"""Return an async validated-call wrapper for an arbitrary command name."""
|
|
50
52
|
if name.startswith("_"):
|
|
51
53
|
raise AttributeError(name)
|
|
52
54
|
|
|
53
55
|
async def _bound(**kw: Any) -> Dict[str, Any]:
|
|
56
|
+
"""Execute the dynamically selected command with validated keyword params."""
|
|
54
57
|
return cast(Dict[str, Any], await self._client.call_validated(name, kw))
|
|
55
58
|
|
|
56
59
|
_bound.__name__ = name
|
|
@@ -13,12 +13,14 @@ from typing import Any, Mapping
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def _expand_path(value: Any) -> str | None:
|
|
16
|
+
"""Expand a non-empty filesystem path value to an absolute string."""
|
|
16
17
|
if value is None or value == "":
|
|
17
18
|
return None
|
|
18
19
|
return str(Path(str(value)).expanduser().resolve())
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def _ssl_paths_from_section(ssl_section: Any) -> dict[str, str]:
|
|
23
|
+
"""Extract and normalize TLS path fields from a config SSL section."""
|
|
22
24
|
if not isinstance(ssl_section, dict):
|
|
23
25
|
return {}
|
|
24
26
|
out: dict[str, str] = {}
|
|
@@ -38,6 +40,7 @@ def _ssl_paths_from_section(ssl_section: Any) -> dict[str, str]:
|
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
def _network_from_server_config(config: Mapping[str, Any]) -> dict[str, Any]:
|
|
43
|
+
"""Return host, port, and protocol settings from a server config dict."""
|
|
41
44
|
server = config.get("server", {})
|
|
42
45
|
if not isinstance(server, dict):
|
|
43
46
|
server = {}
|
{code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/exceptions.py
RENAMED
|
@@ -15,6 +15,7 @@ class ClientValidationError(ValueError):
|
|
|
15
15
|
field: Optional[str] = None,
|
|
16
16
|
details: Optional[Dict[str, Any]] = None,
|
|
17
17
|
) -> None:
|
|
18
|
+
"""Initialize validation error with optional field and details payload."""
|
|
18
19
|
super().__init__(message)
|
|
19
20
|
self.field = field
|
|
20
21
|
self.details = details or {}
|
{code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/file_session.py
RENAMED
|
@@ -40,6 +40,7 @@ class SessionNotFoundError(ClientValidationError):
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
def _unwrap(data: Dict[str, Any]) -> Dict[str, Any]:
|
|
43
|
+
"""Unwrap command result payloads and map missing sessions to SessionNotFoundError."""
|
|
43
44
|
return unwrap_command_result(
|
|
44
45
|
data,
|
|
45
46
|
session_not_found_type=SessionNotFoundError,
|
|
@@ -47,6 +48,7 @@ def _unwrap(data: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
def _require_non_empty(value: str, *, field: str) -> str:
|
|
51
|
+
"""Return stripped text or raise ClientValidationError for an empty field."""
|
|
50
52
|
text = str(value or "").strip()
|
|
51
53
|
if not text:
|
|
52
54
|
raise ClientValidationError(f"{field} is required", field=field)
|
|
@@ -90,6 +92,7 @@ def _validate_upload_selector(
|
|
|
90
92
|
|
|
91
93
|
|
|
92
94
|
def _lock_mode_from_flag(lock: bool) -> str:
|
|
95
|
+
"""Convert a boolean lock flag into the server lock_mode value."""
|
|
93
96
|
return "full" if lock else "none"
|
|
94
97
|
|
|
95
98
|
|
|
@@ -111,6 +114,7 @@ class FileSessionClient:
|
|
|
111
114
|
__slots__ = ("_client",)
|
|
112
115
|
|
|
113
116
|
def __init__(self, client: CodeAnalysisAsyncClient) -> None:
|
|
117
|
+
"""Store the underlying async client used to call session commands."""
|
|
114
118
|
self._client = client
|
|
115
119
|
|
|
116
120
|
async def create_session(
|
|
@@ -133,17 +137,19 @@ class FileSessionClient:
|
|
|
133
137
|
)
|
|
134
138
|
return sid
|
|
135
139
|
|
|
140
|
+
async def validate_session(
|
|
141
|
+
self, session_id: str, *, touch: bool = False
|
|
142
|
+
) -> Dict[str, Any]:
|
|
143
|
+
"""Confirm ``session_id`` exists (``session_validate``)."""
|
|
144
|
+
sid = _require_non_empty(session_id, field="session_id")
|
|
145
|
+
params: Dict[str, Any] = {"session_id": sid}
|
|
146
|
+
if touch:
|
|
147
|
+
params["touch"] = True
|
|
148
|
+
return _unwrap(await self._client.call_validated("session_validate", params))
|
|
149
|
+
|
|
136
150
|
async def assert_session_exists(self, session_id: str) -> None:
|
|
137
|
-
"""Verify ``session_id`` is registered (
|
|
138
|
-
|
|
139
|
-
if not sid:
|
|
140
|
-
raise ClientValidationError("session_id is required", field="session_id")
|
|
141
|
-
_unwrap(
|
|
142
|
-
await self._client.call_validated(
|
|
143
|
-
"session_list_file_locks",
|
|
144
|
-
{"session_id": sid},
|
|
145
|
-
)
|
|
146
|
-
)
|
|
151
|
+
"""Verify ``session_id`` is registered (``session_validate``)."""
|
|
152
|
+
await self.validate_session(session_id, touch=False)
|
|
147
153
|
|
|
148
154
|
async def delete_session(
|
|
149
155
|
self, session_id: str, *, force: bool = False
|
|
@@ -151,13 +157,14 @@ class FileSessionClient:
|
|
|
151
157
|
"""Delete a client session (``session_delete``).
|
|
152
158
|
|
|
153
159
|
``force`` defaults to false (omit on the wire when false). Safe delete
|
|
154
|
-
requires no ``session_file_locks
|
|
155
|
-
where this session is ``parent_session_id
|
|
156
|
-
subordinate
|
|
157
|
-
before the session row is
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
``
|
|
160
|
+
requires no ``session_file_locks``, no ``subordinate_sessions`` rows
|
|
161
|
+
where this session is ``parent_session_id``, and no advisory file-lock
|
|
162
|
+
leases. When ``force`` is true, subordinate link rows, DB file locks, and
|
|
163
|
+
advisory leases for this session are released before the session row is
|
|
164
|
+
deleted.
|
|
165
|
+
|
|
166
|
+
Returns ``session_id``, ``deleted``, ``released_lock_count``,
|
|
167
|
+
``released_subordinate_count``, and ``released_advisory_lease_count``.
|
|
161
168
|
"""
|
|
162
169
|
params: Dict[str, Any] = {"session_id": session_id}
|
|
163
170
|
if force:
|
|
@@ -174,7 +181,8 @@ class FileSessionClient:
|
|
|
174
181
|
|
|
175
182
|
Returns ``locked_files_by_project`` (file_id, file_path,
|
|
176
183
|
project_presentation per project) and ``subordinate_sessions``
|
|
177
|
-
(server_uuid, session_presentation, server_presentation,
|
|
184
|
+
(session_id, server_uuid, session_presentation, server_presentation,
|
|
185
|
+
link_comment).
|
|
178
186
|
"""
|
|
179
187
|
sid = _require_non_empty(session_id, field="session_id")
|
|
180
188
|
return _unwrap(
|
|
@@ -193,8 +201,9 @@ class FileSessionClient:
|
|
|
193
201
|
) -> Dict[str, Any]:
|
|
194
202
|
"""Register leading session on a subordinate server (``subordinate_session_create``).
|
|
195
203
|
|
|
196
|
-
|
|
197
|
-
defaults to the server's ``registration.instance_uuid``
|
|
204
|
+
Subordinate servers use ``parent_session_id`` as ``session_id``.
|
|
205
|
+
``server_uuid`` defaults to the server's ``registration.instance_uuid``
|
|
206
|
+
when omitted.
|
|
198
207
|
"""
|
|
199
208
|
params: Dict[str, Any] = {
|
|
200
209
|
"parent_session_id": _require_non_empty(
|
|
@@ -213,7 +222,7 @@ class FileSessionClient:
|
|
|
213
222
|
parent_session_id: str,
|
|
214
223
|
server_uuid: str,
|
|
215
224
|
) -> Dict[str, Any]:
|
|
216
|
-
"""Fetch one subordinate link (``subordinate_session_get``)."""
|
|
225
|
+
"""Fetch one subordinate server link (``subordinate_session_get``)."""
|
|
217
226
|
return _unwrap(
|
|
218
227
|
await self._client.call_validated(
|
|
219
228
|
"subordinate_session_get",
|
|
@@ -251,9 +260,9 @@ class FileSessionClient:
|
|
|
251
260
|
parent_session_id: str,
|
|
252
261
|
server_uuid: str,
|
|
253
262
|
) -> Dict[str, Any]:
|
|
254
|
-
"""Remove subordinate link
|
|
263
|
+
"""Remove subordinate server link (``subordinate_session_delete``).
|
|
255
264
|
|
|
256
|
-
Does not delete the ``client_sessions`` row
|
|
265
|
+
Does not delete the leading ``client_sessions`` row; use :meth:`delete_session`.
|
|
257
266
|
"""
|
|
258
267
|
return _unwrap(
|
|
259
268
|
await self._client.call_validated(
|
|
@@ -273,7 +282,7 @@ class FileSessionClient:
|
|
|
273
282
|
parent_session_id: Optional[str] = None,
|
|
274
283
|
server_uuid: Optional[str] = None,
|
|
275
284
|
) -> Dict[str, Any]:
|
|
276
|
-
"""List subordinate links (``subordinate_session_list``).
|
|
285
|
+
"""List subordinate server links (``subordinate_session_list``).
|
|
277
286
|
|
|
278
287
|
Returns ``links`` and ``count``. All filter parameters are optional.
|
|
279
288
|
"""
|
{code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/server_api.py
RENAMED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Canonical command names for the high-level client API vs the live server registry.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
**code-analysis-server** owns project trees, the index database, sessions, locks,
|
|
5
|
+
and editor ingress (chunked transfer). It does **not** expose in-server content
|
|
6
|
+
editing (``universal_file_open/edit/write/close``, CST/JSON tree modify/save,
|
|
7
|
+
``format_code``, legacy line writers).
|
|
8
|
+
|
|
9
|
+
**File content on CA** — read-only surface only:
|
|
10
|
+
|
|
11
|
+
- :data:`FILE_CONTENT_READ_COMMANDS` — preview and project search (``search`` /
|
|
12
|
+
``search_get_page``); on-disk grep is internal to ``search`` when enabled.
|
|
13
|
+
- :data:`FS_COMMANDS` — filesystem operations (copy/move/remove/list/grep); not
|
|
14
|
+
the structured edit workflow.
|
|
15
|
+
|
|
16
|
+
Editor clients use :data:`CLIENT_FACADE_COMMANDS` (sessions, transfer, locks,
|
|
17
|
+
``universal_file_preview``).
|
|
8
18
|
|
|
9
19
|
Author: Vasiliy Zdanovskiy
|
|
10
20
|
email: vasilyvz@gmail.com
|
|
@@ -25,10 +35,11 @@ LEGACY_REMOVED_COMMANDS: FrozenSet[str] = frozenset(
|
|
|
25
35
|
"write_project_text_lines",
|
|
26
36
|
"create_text_file",
|
|
27
37
|
"replace_file_lines",
|
|
38
|
+
"universal_file_search",
|
|
28
39
|
}
|
|
29
40
|
)
|
|
30
41
|
|
|
31
|
-
# CST tree MCP workflow — modules may exist in the repo but
|
|
42
|
+
# CST / JSON tree MCP workflow — modules may exist in the repo but are not registered.
|
|
32
43
|
CST_REMOVED_COMMANDS: FrozenSet[str] = frozenset(
|
|
33
44
|
{
|
|
34
45
|
"cst_load_file",
|
|
@@ -41,17 +52,85 @@ CST_REMOVED_COMMANDS: FrozenSet[str] = frozenset(
|
|
|
41
52
|
"cst_get_node_at_line",
|
|
42
53
|
"cst_reload_tree",
|
|
43
54
|
"cst_convert_and_save",
|
|
55
|
+
"cst_apply_buffer",
|
|
56
|
+
"cst_list_trees",
|
|
57
|
+
"cst_unload_tree",
|
|
44
58
|
"list_cst_blocks",
|
|
45
59
|
"query_cst",
|
|
60
|
+
"json_load_file",
|
|
61
|
+
"json_find_node",
|
|
62
|
+
"json_get_node_info",
|
|
63
|
+
"json_modify_tree",
|
|
64
|
+
"json_save_tree",
|
|
65
|
+
"json_reload_tree",
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Content editing on ai-editor-server only (not on code-analysis-server).
|
|
70
|
+
EDITING_REMOVED_COMMANDS: FrozenSet[str] = frozenset(
|
|
71
|
+
{
|
|
72
|
+
"universal_file_open",
|
|
73
|
+
"universal_file_edit",
|
|
74
|
+
"universal_file_write",
|
|
75
|
+
"universal_file_close",
|
|
76
|
+
"universal_file_move_nodes",
|
|
77
|
+
"session_git_log",
|
|
78
|
+
"session_git_diff",
|
|
79
|
+
"session_git_show",
|
|
80
|
+
"session_git_status",
|
|
81
|
+
"session_git_revert",
|
|
82
|
+
"session_undo",
|
|
83
|
+
"session_redo",
|
|
84
|
+
"session_write",
|
|
85
|
+
"delete_file",
|
|
86
|
+
"delete_files_by_mask",
|
|
87
|
+
"restore_deleted_files",
|
|
88
|
+
"unmark_deleted_file",
|
|
89
|
+
"cleanup_deleted_files",
|
|
90
|
+
"collapse_versions",
|
|
91
|
+
"restore_backup_file",
|
|
92
|
+
"delete_backup",
|
|
93
|
+
"clear_all_backups",
|
|
94
|
+
"split_class",
|
|
95
|
+
"extract_superclass",
|
|
96
|
+
"split_file_to_package",
|
|
97
|
+
"format_code",
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
REMOVED_COMMANDS: FrozenSet[str] = (
|
|
102
|
+
LEGACY_REMOVED_COMMANDS | CST_REMOVED_COMMANDS | EDITING_REMOVED_COMMANDS
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Read-only file **content** on CA (no mutate/edit workflow). Includes on-disk search
|
|
106
|
+
# (``fs_grep``, paginated ``search_*``) for paths not yet in the index.
|
|
107
|
+
FILE_CONTENT_READ_COMMANDS: FrozenSet[str] = frozenset(
|
|
108
|
+
{
|
|
109
|
+
"universal_file_preview",
|
|
46
110
|
"get_file_lines",
|
|
111
|
+
"search",
|
|
112
|
+
"search_get_page",
|
|
113
|
+
"search_get_status",
|
|
114
|
+
"search_cancel",
|
|
115
|
+
"search_close",
|
|
47
116
|
}
|
|
48
117
|
)
|
|
49
118
|
|
|
50
|
-
|
|
119
|
+
# Filesystem helpers — separate from structured content editing; may touch paths/bytes
|
|
120
|
+
# via copy/move/remove but are not universal_file_edit / CST / format_code.
|
|
121
|
+
FS_COMMANDS: FrozenSet[str] = frozenset(
|
|
122
|
+
{
|
|
123
|
+
"fs_copy",
|
|
124
|
+
"fs_move",
|
|
125
|
+
"fs_remove",
|
|
126
|
+
}
|
|
127
|
+
)
|
|
51
128
|
|
|
129
|
+
# Client sessions + DB file locks — persisted on this server for editor/terminal clients.
|
|
52
130
|
FILE_SESSION_COMMANDS: FrozenSet[str] = frozenset(
|
|
53
131
|
{
|
|
54
132
|
"session_create",
|
|
133
|
+
"session_validate",
|
|
55
134
|
"session_delete",
|
|
56
135
|
"session_list",
|
|
57
136
|
"session_view",
|
|
@@ -76,10 +155,6 @@ TRANSFER_AND_LOCK_COMMANDS: FrozenSet[str] = frozenset(
|
|
|
76
155
|
|
|
77
156
|
UNIVERSAL_FILE_COMMANDS: FrozenSet[str] = frozenset(
|
|
78
157
|
{
|
|
79
|
-
"universal_file_open",
|
|
80
|
-
"universal_file_edit",
|
|
81
|
-
"universal_file_write",
|
|
82
|
-
"universal_file_close",
|
|
83
158
|
"universal_file_preview",
|
|
84
159
|
}
|
|
85
160
|
)
|
|
@@ -92,6 +167,7 @@ CLIENT_FACADE_COMMANDS: FrozenSet[str] = (
|
|
|
92
167
|
# ``session_list_file_locks`` is also used by ``assert_session_exists``.
|
|
93
168
|
FILE_SESSION_FACADE_METHODS: Dict[str, str] = {
|
|
94
169
|
"session_create": "create_session",
|
|
170
|
+
"session_validate": "validate_session",
|
|
95
171
|
"session_delete": "delete_session",
|
|
96
172
|
"session_list": "list_sessions",
|
|
97
173
|
"session_view": "view_session",
|
|
@@ -155,6 +231,7 @@ def assert_transfer_facade_complete() -> None:
|
|
|
155
231
|
|
|
156
232
|
|
|
157
233
|
def _command_registered(get_command: Callable[[str], object], name: str) -> bool:
|
|
234
|
+
"""Return True when ``get_command`` can resolve a command name."""
|
|
158
235
|
try:
|
|
159
236
|
get_command(name)
|
|
160
237
|
return True
|
|
@@ -182,3 +259,27 @@ def assert_removed_commands_absent(get_command: Callable[[str], object]) -> None
|
|
|
182
259
|
]
|
|
183
260
|
if present:
|
|
184
261
|
raise AssertionError(f"Removed commands still registered: {present}")
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def assert_file_content_read_commands_registered(
|
|
265
|
+
get_command: Callable[[str], object],
|
|
266
|
+
) -> None:
|
|
267
|
+
"""Raise ``KeyError`` if a read-only content command is missing from the registry."""
|
|
268
|
+
missing = [
|
|
269
|
+
name
|
|
270
|
+
for name in sorted(FILE_CONTENT_READ_COMMANDS)
|
|
271
|
+
if not _command_registered(get_command, name)
|
|
272
|
+
]
|
|
273
|
+
if missing:
|
|
274
|
+
raise KeyError(f"File content read commands not registered: {missing}")
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def assert_fs_commands_registered(get_command: Callable[[str], object]) -> None:
|
|
278
|
+
"""Raise ``KeyError`` if a filesystem helper command is missing from the registry."""
|
|
279
|
+
missing = [
|
|
280
|
+
name
|
|
281
|
+
for name in sorted(FS_COMMANDS)
|
|
282
|
+
if not _command_registered(get_command, name)
|
|
283
|
+
]
|
|
284
|
+
if missing:
|
|
285
|
+
raise KeyError(f"Filesystem commands not registered: {missing}")
|
{code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/universal_file.py
RENAMED
|
@@ -20,11 +20,16 @@ if TYPE_CHECKING:
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class UniversalFileClient:
|
|
23
|
-
"""Edit-session workflow for project files (open → edit → write → close).
|
|
23
|
+
"""Edit-session workflow for project files (open → edit → write → close).
|
|
24
|
+
|
|
25
|
+
Uses ``session_id`` from ``universal_file_open`` only. Not related to
|
|
26
|
+
client ``session_*`` commands (``session_create``, ``session_open_file``, …).
|
|
27
|
+
"""
|
|
24
28
|
|
|
25
29
|
__slots__ = ("_client",)
|
|
26
30
|
|
|
27
31
|
def __init__(self, client: CodeAnalysisAsyncClient) -> None:
|
|
32
|
+
"""Store the async client used for universal file workflow commands."""
|
|
28
33
|
self._client = client
|
|
29
34
|
|
|
30
35
|
async def open(
|
|
@@ -35,7 +40,10 @@ class UniversalFileClient:
|
|
|
35
40
|
create: bool = False,
|
|
36
41
|
initial_content: Optional[str] = None,
|
|
37
42
|
) -> Dict[str, Any]:
|
|
38
|
-
"""Start an edit session (``universal_file_open``).
|
|
43
|
+
"""Start an edit session (``universal_file_open``).
|
|
44
|
+
|
|
45
|
+
Identifies the file by ``project_id`` + ``file_path`` (not ``file_id``).
|
|
46
|
+
"""
|
|
39
47
|
params: Dict[str, Any] = {
|
|
40
48
|
"project_id": project_id,
|
|
41
49
|
"file_path": file_path,
|
|
@@ -72,7 +80,12 @@ class UniversalFileClient:
|
|
|
72
80
|
*,
|
|
73
81
|
write_mode: str = "commit",
|
|
74
82
|
) -> Dict[str, Any]:
|
|
75
|
-
"""Persist or preview draft (``universal_file_write``).
|
|
83
|
+
"""Persist or preview draft (``universal_file_write``).
|
|
84
|
+
|
|
85
|
+
Default ``write_mode`` is ``commit`` in this client wrapper. The server
|
|
86
|
+
default when the parameter is omitted is ``preview``. Pass
|
|
87
|
+
``write_mode='preview'`` first to inspect the diff, then ``commit``.
|
|
88
|
+
"""
|
|
76
89
|
return unwrap_command_result(
|
|
77
90
|
await self._client.call_validated(
|
|
78
91
|
"universal_file_write",
|
|
@@ -89,7 +102,7 @@ class UniversalFileClient:
|
|
|
89
102
|
project_id: str,
|
|
90
103
|
session_id: str,
|
|
91
104
|
) -> Dict[str, Any]:
|
|
92
|
-
"""End edit session (``
|
|
105
|
+
"""End edit session (``universal_file_open`` session_id, not client ``session_*``)."""
|
|
93
106
|
return unwrap_command_result(
|
|
94
107
|
await self._client.call_validated(
|
|
95
108
|
"universal_file_close",
|
{code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/validation.py
RENAMED
|
@@ -13,12 +13,9 @@ from code_analysis_client.exceptions import ClientValidationError
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def prepare_params_for_schema(
|
|
16
|
-
params: Dict[str, Any], schema: Dict[str, Any]
|
|
16
|
+
params: Dict[str, Any], schema: Dict[str, Any] # noqa: ARG001
|
|
17
17
|
) -> Dict[str, Any]:
|
|
18
|
-
"""
|
|
19
|
-
props = schema.get("properties") or {}
|
|
20
|
-
if not schema.get("additionalProperties", True):
|
|
21
|
-
return {k: v for k, v in params.items() if k in props}
|
|
18
|
+
"""Return a shallow copy of params for validation and dispatch."""
|
|
22
19
|
return dict(params)
|
|
23
20
|
|
|
24
21
|
|
|
@@ -34,7 +31,7 @@ def validate_params_against_schema(
|
|
|
34
31
|
field="params",
|
|
35
32
|
)
|
|
36
33
|
props = schema.get("properties") or {}
|
|
37
|
-
additional_ok = schema.get("additionalProperties",
|
|
34
|
+
additional_ok = schema.get("additionalProperties", False)
|
|
38
35
|
required_set = set(schema.get("required") or [])
|
|
39
36
|
for key, value in params.items():
|
|
40
37
|
if key not in props:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.6.39
|
{code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client.egg-info/PKG-INFO
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-analysis-client
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.39
|
|
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
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
|
-
Requires-Dist: mcp-proxy-adapter>=8.10.
|
|
8
|
+
Requires-Dist: mcp-proxy-adapter>=8.10.15
|
|
9
9
|
Provides-Extra: dev
|
|
10
10
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
11
11
|
Requires-Dist: pytest-asyncio>=0.25.0; extra == "dev"
|
|
@@ -97,8 +97,8 @@ Sync checks (in-process registry):
|
|
|
97
97
|
pytest tests/test_client_server_api_sync.py tests/test_code_analysis_client.py -k session
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
Package version is in ``
|
|
101
|
-
|
|
100
|
+
Package version is in the root ``pyproject.toml``; before a client wheel build run
|
|
101
|
+
``python scripts/sync_code_analysis_client_version.py`` (also done by ``release_build.sh``).
|
|
102
102
|
|
|
103
103
|
## Examples (this repository)
|
|
104
104
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.0.9
|
|
File without changes
|
{code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/responses.py
RENAMED
|
File without changes
|
{code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client/server_schema.py
RENAMED
|
File without changes
|
{code_analysis_client-1.0.9 → code_analysis_client-1.6.39}/code_analysis_client.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|