code-analysis-client 1.6.240__tar.gz → 1.6.242__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.6.240 → code_analysis_client-1.6.242}/PKG-INFO +68 -37
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/README.md +66 -35
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/__init__.py +3 -11
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/check_chain.py +2 -2
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/client.py +111 -78
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/config.py +46 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/exceptions.py +16 -6
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/file_session.py +2 -2
- code_analysis_client-1.6.242/code_analysis_client/queue_wait.py +301 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/responses.py +44 -1
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/universal_file.py +2 -2
- code_analysis_client-1.6.242/code_analysis_client/version.txt +1 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/worktree.py +2 -2
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client.egg-info/PKG-INFO +68 -37
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client.egg-info/requires.txt +1 -1
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/pyproject.toml +1 -1
- code_analysis_client-1.6.240/code_analysis_client/queue_wait.py +0 -396
- code_analysis_client-1.6.240/code_analysis_client/version.txt +0 -1
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/commands_proxy.py +0 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/py.typed +0 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/schema_disk_cache.py +0 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/server_api.py +0 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/server_schema.py +0 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/validation.py +0 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/vectorizer_state.py +0 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client.egg-info/SOURCES.txt +0 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client.egg-info/dependency_links.txt +0 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client.egg-info/top_level.txt +0 -0
- {code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/setup.cfg +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-analysis-client
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.242
|
|
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.11.
|
|
8
|
+
Requires-Dist: mcp-proxy-adapter>=8.11.5
|
|
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"
|
|
@@ -54,58 +54,89 @@ from code_analysis_client import CodeAnalysisAsyncClient
|
|
|
54
54
|
client = CodeAnalysisAsyncClient.from_server_config(config_dict, timeout=60.0)
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
###
|
|
57
|
+
### Every call is the adapter's standard call
|
|
58
58
|
|
|
59
59
|
Every entry point — `call`, `call_validated`, `client.commands.<name>`, and the
|
|
60
|
-
`file_sessions` / `universal_files`
|
|
61
|
-
through one
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
`file_sessions` / `universal_files` / `worktrees` / `check_chains` facades built on
|
|
61
|
+
`call_validated` — goes through one core that uses `mcp-proxy-adapter`'s
|
|
62
|
+
`JsonRpcClient.execute_command_unified`: the command runs in a WebSocket command
|
|
63
|
+
session and the call returns when the terminal event arrives (no polling while the
|
|
64
|
+
socket is up). If `/ws` is unreachable the adapter falls back to RPC polling of
|
|
65
|
+
`queue_get_job_status` and logs one WARNING `WS_UNREACHABLE_RPC_POLLING_FALLBACK`;
|
|
66
|
+
the result is identical. The client has no polling loop of its own.
|
|
66
67
|
|
|
67
68
|
```python
|
|
68
|
-
#
|
|
69
|
+
# Queued or not, this waits and returns the command's own result envelope.
|
|
69
70
|
out = await client.call("some_long_running_command", {...})
|
|
70
71
|
```
|
|
71
72
|
|
|
72
73
|
Failures raise instead of returning an error envelope:
|
|
73
74
|
|
|
74
|
-
* `CommandFailedError` — the
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
* `CommandFailedError` — the command ran but its inner result is
|
|
76
|
+
`{"success": false}` (immediate and queued commands alike; a failing result is
|
|
77
|
+
never returned as a dict). Carries `.command`, `.job_id`, `.error` (the server's
|
|
78
|
+
error object, e.g. `.error["code"]`) and `.result` (the inner envelope).
|
|
79
|
+
* `JobFailedError` — the job failed/stopped/cancelled. Carries `.job_id`, `.status`
|
|
80
|
+
and `.error` (always a structured error dict).
|
|
81
|
+
* `JobTimeoutError` — only when a positive `timeout` elapses; the call detaches and
|
|
82
|
+
the job keeps running server-side (`websocket.on_timeout` is `detach`).
|
|
83
|
+
* `ClientValidationError` — the server refused the parameters (JSON-RPC `-32602`);
|
|
84
|
+
`details` carries the server's `violation` payload.
|
|
85
|
+
* `ValueError` — a negative `timeout` or a non-positive `poll_interval`, before
|
|
86
|
+
anything is sent.
|
|
82
87
|
|
|
83
88
|
Optional keyword args on `call` / `call_validated` (and their `call_unified*`
|
|
84
|
-
counterparts):
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
counterparts):
|
|
90
|
+
|
|
91
|
+
* `timeout` — total wait in seconds. `None` (default) uses the client config
|
|
92
|
+
`websocket.job_wait_timeout`, shipped as `0` = no time limit, so a long queued
|
|
93
|
+
command is never cut off. A value above 0 raises `JobTimeoutError` and detaches.
|
|
94
|
+
* `poll_interval` — safety-net status-poll cadence in seconds. `None` (default)
|
|
95
|
+
uses `websocket.terminal_poll_interval` (2 s); a value overrides it per call.
|
|
96
|
+
* `status_hook` — sync or async callable invoked with each adapter WebSocket event
|
|
97
|
+
(at least the accepted event first and the terminal completed event last). An
|
|
98
|
+
exception raised by the hook propagates.
|
|
99
|
+
|
|
100
|
+
`call` / `call_validated` also take `auto_poll` (default `True`). Pass
|
|
101
|
+
`auto_poll=False` to detach as soon as the job id is known: the call returns a
|
|
102
|
+
`QueuedJob` handle immediately — for every command, including ones that finish at
|
|
103
|
+
once — and `timeout`, `poll_interval` and `status_hook` are ignored.
|
|
93
104
|
|
|
94
105
|
```python
|
|
95
106
|
from code_analysis_client import QueuedJob
|
|
96
107
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
# `result` is now the same dict shape a default (auto_poll=True) call returns
|
|
108
|
+
job = await client.call("some_long_running_command", {...}, auto_poll=False)
|
|
109
|
+
assert isinstance(job, QueuedJob)
|
|
110
|
+
# do other work here, then block on it whenever you're ready
|
|
111
|
+
result = await job.wait() # same result / errors as the default path
|
|
102
112
|
```
|
|
103
113
|
|
|
104
|
-
`QueuedJob` exposes `.job_id`, `.envelope` (the
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
114
|
+
`QueuedJob` exposes `.job_id`, `.envelope` (the adapter's acceptance envelope) and two
|
|
115
|
+
async methods: `.wait(timeout=None, poll_interval=None, status_hook=None)` — reads the
|
|
116
|
+
job once and, if it is still running, uses the adapter's WebSocket wait for the job id
|
|
117
|
+
(public API `wait_for_job_via_websocket`), then returns/raises exactly like the default
|
|
118
|
+
path; there is no RPC-polling fallback for an existing job id (a WebSocket failure
|
|
119
|
+
propagates) — and `.status()` — a single `queue_get_job_status` fetch.
|
|
120
|
+
|
|
121
|
+
#### Explicit adapter timeout configuration
|
|
122
|
+
|
|
123
|
+
The client hands `JsonRpcClient(ws_config=...)` the explicit defaults
|
|
124
|
+
`code_analysis_client.DEFAULT_CLIENT_ADAPTER_CONFIG` (a `ws_config=` keyword you pass is
|
|
125
|
+
merged over them key by key), so none of the adapter's own 60 s / `cancel` defaults is
|
|
126
|
+
effective:
|
|
127
|
+
|
|
128
|
+
| `websocket` key | value | meaning |
|
|
129
|
+
|---|---|---|
|
|
130
|
+
| `job_wait_timeout` | 0 | no total bound on a call's wait |
|
|
131
|
+
| `on_timeout` | `detach` | a wait timeout leaves the job running |
|
|
132
|
+
| `receive_timeout` / `receive_timeout_buffer` | 60 / 5 | one receive cap (never limits the total wait) |
|
|
133
|
+
| `heartbeat_interval` | 30 | WebSocket heartbeat |
|
|
134
|
+
| `terminal_poll_interval` | 2 | safety-net poll cadence |
|
|
135
|
+
| `close_timeout` | 5 | socket close bound |
|
|
136
|
+
| `subscribe_settle_delay` / `cancel_grace_seconds` | 0.5 / 0.5 | settle delay, cancel grace |
|
|
137
|
+
|
|
138
|
+
`job_push`: `on_caller_loss` `detach` (a job survives a lost client), `poll_interval` `0.1`.
|
|
139
|
+
The server ships and applies the same values.
|
|
109
140
|
|
|
110
141
|
`call_unified` / `call_unified_validated` are kept as **deprecated aliases** of
|
|
111
142
|
`call` / `call_validated` for backward compatibility and emit
|
|
@@ -42,58 +42,89 @@ from code_analysis_client import CodeAnalysisAsyncClient
|
|
|
42
42
|
client = CodeAnalysisAsyncClient.from_server_config(config_dict, timeout=60.0)
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
###
|
|
45
|
+
### Every call is the adapter's standard call
|
|
46
46
|
|
|
47
47
|
Every entry point — `call`, `call_validated`, `client.commands.<name>`, and the
|
|
48
|
-
`file_sessions` / `universal_files`
|
|
49
|
-
through one
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
`file_sessions` / `universal_files` / `worktrees` / `check_chains` facades built on
|
|
49
|
+
`call_validated` — goes through one core that uses `mcp-proxy-adapter`'s
|
|
50
|
+
`JsonRpcClient.execute_command_unified`: the command runs in a WebSocket command
|
|
51
|
+
session and the call returns when the terminal event arrives (no polling while the
|
|
52
|
+
socket is up). If `/ws` is unreachable the adapter falls back to RPC polling of
|
|
53
|
+
`queue_get_job_status` and logs one WARNING `WS_UNREACHABLE_RPC_POLLING_FALLBACK`;
|
|
54
|
+
the result is identical. The client has no polling loop of its own.
|
|
54
55
|
|
|
55
56
|
```python
|
|
56
|
-
#
|
|
57
|
+
# Queued or not, this waits and returns the command's own result envelope.
|
|
57
58
|
out = await client.call("some_long_running_command", {...})
|
|
58
59
|
```
|
|
59
60
|
|
|
60
61
|
Failures raise instead of returning an error envelope:
|
|
61
62
|
|
|
62
|
-
* `CommandFailedError` — the
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
* `CommandFailedError` — the command ran but its inner result is
|
|
64
|
+
`{"success": false}` (immediate and queued commands alike; a failing result is
|
|
65
|
+
never returned as a dict). Carries `.command`, `.job_id`, `.error` (the server's
|
|
66
|
+
error object, e.g. `.error["code"]`) and `.result` (the inner envelope).
|
|
67
|
+
* `JobFailedError` — the job failed/stopped/cancelled. Carries `.job_id`, `.status`
|
|
68
|
+
and `.error` (always a structured error dict).
|
|
69
|
+
* `JobTimeoutError` — only when a positive `timeout` elapses; the call detaches and
|
|
70
|
+
the job keeps running server-side (`websocket.on_timeout` is `detach`).
|
|
71
|
+
* `ClientValidationError` — the server refused the parameters (JSON-RPC `-32602`);
|
|
72
|
+
`details` carries the server's `violation` payload.
|
|
73
|
+
* `ValueError` — a negative `timeout` or a non-positive `poll_interval`, before
|
|
74
|
+
anything is sent.
|
|
70
75
|
|
|
71
76
|
Optional keyword args on `call` / `call_validated` (and their `call_unified*`
|
|
72
|
-
counterparts):
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
counterparts):
|
|
78
|
+
|
|
79
|
+
* `timeout` — total wait in seconds. `None` (default) uses the client config
|
|
80
|
+
`websocket.job_wait_timeout`, shipped as `0` = no time limit, so a long queued
|
|
81
|
+
command is never cut off. A value above 0 raises `JobTimeoutError` and detaches.
|
|
82
|
+
* `poll_interval` — safety-net status-poll cadence in seconds. `None` (default)
|
|
83
|
+
uses `websocket.terminal_poll_interval` (2 s); a value overrides it per call.
|
|
84
|
+
* `status_hook` — sync or async callable invoked with each adapter WebSocket event
|
|
85
|
+
(at least the accepted event first and the terminal completed event last). An
|
|
86
|
+
exception raised by the hook propagates.
|
|
87
|
+
|
|
88
|
+
`call` / `call_validated` also take `auto_poll` (default `True`). Pass
|
|
89
|
+
`auto_poll=False` to detach as soon as the job id is known: the call returns a
|
|
90
|
+
`QueuedJob` handle immediately — for every command, including ones that finish at
|
|
91
|
+
once — and `timeout`, `poll_interval` and `status_hook` are ignored.
|
|
81
92
|
|
|
82
93
|
```python
|
|
83
94
|
from code_analysis_client import QueuedJob
|
|
84
95
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
# `result` is now the same dict shape a default (auto_poll=True) call returns
|
|
96
|
+
job = await client.call("some_long_running_command", {...}, auto_poll=False)
|
|
97
|
+
assert isinstance(job, QueuedJob)
|
|
98
|
+
# do other work here, then block on it whenever you're ready
|
|
99
|
+
result = await job.wait() # same result / errors as the default path
|
|
90
100
|
```
|
|
91
101
|
|
|
92
|
-
`QueuedJob` exposes `.job_id`, `.envelope` (the
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
`QueuedJob` exposes `.job_id`, `.envelope` (the adapter's acceptance envelope) and two
|
|
103
|
+
async methods: `.wait(timeout=None, poll_interval=None, status_hook=None)` — reads the
|
|
104
|
+
job once and, if it is still running, uses the adapter's WebSocket wait for the job id
|
|
105
|
+
(public API `wait_for_job_via_websocket`), then returns/raises exactly like the default
|
|
106
|
+
path; there is no RPC-polling fallback for an existing job id (a WebSocket failure
|
|
107
|
+
propagates) — and `.status()` — a single `queue_get_job_status` fetch.
|
|
108
|
+
|
|
109
|
+
#### Explicit adapter timeout configuration
|
|
110
|
+
|
|
111
|
+
The client hands `JsonRpcClient(ws_config=...)` the explicit defaults
|
|
112
|
+
`code_analysis_client.DEFAULT_CLIENT_ADAPTER_CONFIG` (a `ws_config=` keyword you pass is
|
|
113
|
+
merged over them key by key), so none of the adapter's own 60 s / `cancel` defaults is
|
|
114
|
+
effective:
|
|
115
|
+
|
|
116
|
+
| `websocket` key | value | meaning |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `job_wait_timeout` | 0 | no total bound on a call's wait |
|
|
119
|
+
| `on_timeout` | `detach` | a wait timeout leaves the job running |
|
|
120
|
+
| `receive_timeout` / `receive_timeout_buffer` | 60 / 5 | one receive cap (never limits the total wait) |
|
|
121
|
+
| `heartbeat_interval` | 30 | WebSocket heartbeat |
|
|
122
|
+
| `terminal_poll_interval` | 2 | safety-net poll cadence |
|
|
123
|
+
| `close_timeout` | 5 | socket close bound |
|
|
124
|
+
| `subscribe_settle_delay` / `cancel_grace_seconds` | 0.5 / 0.5 | settle delay, cancel grace |
|
|
125
|
+
|
|
126
|
+
`job_push`: `on_caller_loss` `detach` (a job survives a lost client), `poll_interval` `0.1`.
|
|
127
|
+
The server ships and applies the same values.
|
|
97
128
|
|
|
98
129
|
`call_unified` / `call_unified_validated` are kept as **deprecated aliases** of
|
|
99
130
|
`call` / `call_validated` for backward compatibility and emit
|
{code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/__init__.py
RENAMED
|
@@ -12,6 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
from code_analysis_client.client import CodeAnalysisAsyncClient
|
|
13
13
|
from code_analysis_client.commands_proxy import ValidatedCommandsProxy
|
|
14
14
|
from code_analysis_client.config import (
|
|
15
|
+
DEFAULT_CLIENT_ADAPTER_CONFIG,
|
|
15
16
|
adapter_settings_from_server_config,
|
|
16
17
|
adapter_settings_to_jsonrpc_kwargs,
|
|
17
18
|
load_server_config,
|
|
@@ -38,13 +39,7 @@ from code_analysis_client.check_chain import (
|
|
|
38
39
|
FileCheckAndPromoteResult,
|
|
39
40
|
)
|
|
40
41
|
from code_analysis_client.worktree import WorktreeClient, WorktreeConflictError
|
|
41
|
-
from code_analysis_client.queue_wait import
|
|
42
|
-
QueuedJob,
|
|
43
|
-
extract_job_id,
|
|
44
|
-
is_queued_envelope,
|
|
45
|
-
unwrap_job_result,
|
|
46
|
-
wait_for_job,
|
|
47
|
-
)
|
|
42
|
+
from code_analysis_client.queue_wait import QueuedJob
|
|
48
43
|
from code_analysis_client.server_api import (
|
|
49
44
|
CLIENT_FACADE_COMMANDS,
|
|
50
45
|
CST_REMOVED_COMMANDS,
|
|
@@ -76,6 +71,7 @@ from code_analysis_client.vectorizer_state import (
|
|
|
76
71
|
)
|
|
77
72
|
|
|
78
73
|
__all__ = [
|
|
74
|
+
"DEFAULT_CLIENT_ADAPTER_CONFIG",
|
|
79
75
|
"CLIENT_FACADE_COMMANDS",
|
|
80
76
|
"CST_REMOVED_COMMANDS",
|
|
81
77
|
"ClientValidationError",
|
|
@@ -114,19 +110,15 @@ __all__ = [
|
|
|
114
110
|
"WorktreeConflictError",
|
|
115
111
|
"adapter_settings_from_server_config",
|
|
116
112
|
"adapter_settings_to_jsonrpc_kwargs",
|
|
117
|
-
"extract_job_id",
|
|
118
113
|
"extract_vectorizer_state_from_response",
|
|
119
114
|
"fetch_command_schema_from_server",
|
|
120
|
-
"is_queued_envelope",
|
|
121
115
|
"load_server_config",
|
|
122
116
|
"parse_schema_from_help_payload",
|
|
123
117
|
"prepare_params_for_schema",
|
|
124
118
|
"safe_get_vectorizer_state",
|
|
125
119
|
"safe_get_warnings",
|
|
126
120
|
"safe_get_vectorization_worker",
|
|
127
|
-
"unwrap_job_result",
|
|
128
121
|
"validate_params_against_schema",
|
|
129
|
-
"wait_for_job",
|
|
130
122
|
]
|
|
131
123
|
|
|
132
124
|
|
{code_analysis_client-1.6.240 → code_analysis_client-1.6.242}/code_analysis_client/check_chain.py
RENAMED
|
@@ -17,7 +17,7 @@ from dataclasses import dataclass, field
|
|
|
17
17
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
18
18
|
|
|
19
19
|
from code_analysis_client.exceptions import ClientValidationError
|
|
20
|
-
from code_analysis_client.responses import command_error_code
|
|
20
|
+
from code_analysis_client.responses import command_error_code, FacadeCaller
|
|
21
21
|
from code_analysis_client.worktree import WorktreeConflictError
|
|
22
22
|
|
|
23
23
|
if TYPE_CHECKING:
|
|
@@ -252,7 +252,7 @@ class CheckChainClient:
|
|
|
252
252
|
|
|
253
253
|
def __init__(self, client: CodeAnalysisAsyncClient) -> None:
|
|
254
254
|
"""Store the underlying async client."""
|
|
255
|
-
self._client = client
|
|
255
|
+
self._client = FacadeCaller(client) # type: ignore[assignment]
|
|
256
256
|
|
|
257
257
|
async def list(self, project_id: str) -> CheckChainListResult:
|
|
258
258
|
"""Return the resolved chain of every configured extension.
|