code-analysis-client 1.6.173__tar.gz → 1.6.176__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.173 → code_analysis_client-1.6.176}/PKG-INFO +1 -1
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/__init__.py +3 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/client.py +6 -0
- code_analysis_client-1.6.176/code_analysis_client/version.txt +1 -0
- code_analysis_client-1.6.176/code_analysis_client/worktree.py +539 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client.egg-info/PKG-INFO +1 -1
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client.egg-info/SOURCES.txt +1 -0
- code_analysis_client-1.6.173/code_analysis_client/version.txt +0 -1
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/README.md +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/commands_proxy.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/config.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/exceptions.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/file_session.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/py.typed +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/queue_wait.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/responses.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/schema_disk_cache.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/server_api.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/server_schema.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/universal_file.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/validation.py +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client.egg-info/dependency_links.txt +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client.egg-info/requires.txt +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client.egg-info/top_level.txt +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/pyproject.toml +0 -0
- {code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-analysis-client
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.176
|
|
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
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/__init__.py
RENAMED
|
@@ -24,6 +24,7 @@ from code_analysis_client.exceptions import (
|
|
|
24
24
|
QueueJobError,
|
|
25
25
|
)
|
|
26
26
|
from code_analysis_client.file_session import FileSessionClient, SessionNotFoundError
|
|
27
|
+
from code_analysis_client.worktree import WorktreeClient, WorktreeConflictError
|
|
27
28
|
from code_analysis_client.queue_wait import (
|
|
28
29
|
QueuedJob,
|
|
29
30
|
extract_job_id,
|
|
@@ -71,6 +72,8 @@ __all__ = [
|
|
|
71
72
|
"UNIVERSAL_FILE_COMMANDS",
|
|
72
73
|
"UniversalFileClient",
|
|
73
74
|
"ValidatedCommandsProxy",
|
|
75
|
+
"WorktreeClient",
|
|
76
|
+
"WorktreeConflictError",
|
|
74
77
|
"adapter_settings_from_server_config",
|
|
75
78
|
"adapter_settings_to_jsonrpc_kwargs",
|
|
76
79
|
"extract_job_id",
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/client.py
RENAMED
|
@@ -23,6 +23,7 @@ from code_analysis_client.config import (
|
|
|
23
23
|
load_server_config,
|
|
24
24
|
)
|
|
25
25
|
from code_analysis_client.file_session import FileSessionClient
|
|
26
|
+
from code_analysis_client.worktree import WorktreeClient
|
|
26
27
|
from code_analysis_client.queue_wait import (
|
|
27
28
|
QueuedJob,
|
|
28
29
|
StatusHook,
|
|
@@ -147,6 +148,11 @@ class CodeAnalysisAsyncClient:
|
|
|
147
148
|
"""Session workflow: ``session_*``, ``subordinate_session_*``, transfer, advisory locks."""
|
|
148
149
|
return FileSessionClient(self)
|
|
149
150
|
|
|
151
|
+
@property
|
|
152
|
+
def worktrees(self) -> WorktreeClient:
|
|
153
|
+
"""Worktree management: ``worktree_*`` commands."""
|
|
154
|
+
return WorktreeClient(self)
|
|
155
|
+
|
|
150
156
|
@property
|
|
151
157
|
def universal_files(self) -> UniversalFileClient:
|
|
152
158
|
"""Read-only structured preview (``universal_file_preview`` command)."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.6.176
|
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Worktree management on top of CodeAnalysisAsyncClient.
|
|
3
|
+
|
|
4
|
+
Wraps ``worktree_*`` MCP commands with typed client methods, queued and synchronous,
|
|
5
|
+
following the FileSessionClient pattern.
|
|
6
|
+
|
|
7
|
+
Author: Vasiliy Zdanovskiy
|
|
8
|
+
email: vasilyvz@gmail.com
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
14
|
+
|
|
15
|
+
from code_analysis_client.exceptions import ClientValidationError
|
|
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 WorktreeConflictError(ClientValidationError):
|
|
23
|
+
"""Raised when worktree_sync encounters WORKTREE_SYNC_CONFLICT."""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
message: str,
|
|
28
|
+
*,
|
|
29
|
+
conflicts: Optional[List[Dict[str, Any]]] = None,
|
|
30
|
+
preserved_locked_files: Optional[List[str]] = None,
|
|
31
|
+
) -> None:
|
|
32
|
+
"""Initialize with conflict details."""
|
|
33
|
+
super().__init__(message, field="worktree_sync")
|
|
34
|
+
self.conflicts = conflicts or []
|
|
35
|
+
self.preserved_locked_files = preserved_locked_files or []
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _unwrap(data: Dict[str, Any]) -> Dict[str, Any]:
|
|
39
|
+
"""Unwrap command result payloads."""
|
|
40
|
+
return unwrap_command_result(data)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _require_non_empty(value: Any, *, field: str) -> str:
|
|
44
|
+
"""Return stripped text or raise ClientValidationError for an empty field."""
|
|
45
|
+
text = str(value or "").strip()
|
|
46
|
+
if not text:
|
|
47
|
+
raise ClientValidationError(f"{field} is required", field=field)
|
|
48
|
+
return text
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class WorktreeClient:
|
|
52
|
+
"""Worktree lifecycle and sync management commands."""
|
|
53
|
+
|
|
54
|
+
__slots__ = ("_client",)
|
|
55
|
+
|
|
56
|
+
def __init__(self, client: CodeAnalysisAsyncClient) -> None:
|
|
57
|
+
"""Store the underlying async client used to call worktree commands."""
|
|
58
|
+
self._client = client
|
|
59
|
+
|
|
60
|
+
def __getattr__(self, name: str) -> Any:
|
|
61
|
+
"""Map reserved keyword 'continue' to 'continue_' method."""
|
|
62
|
+
if name == "continue":
|
|
63
|
+
return self.continue_
|
|
64
|
+
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'")
|
|
65
|
+
|
|
66
|
+
# === Lifecycle commands ===
|
|
67
|
+
|
|
68
|
+
async def ensure(
|
|
69
|
+
self,
|
|
70
|
+
project_id: str,
|
|
71
|
+
name: str,
|
|
72
|
+
*,
|
|
73
|
+
branch: Optional[str] = None,
|
|
74
|
+
start_point: Optional[str] = None,
|
|
75
|
+
create_branch: bool = True,
|
|
76
|
+
owner_session_id: Optional[str] = None,
|
|
77
|
+
) -> Dict[str, Any]:
|
|
78
|
+
"""Create a worktree if absent; idempotent if already present with same branch.
|
|
79
|
+
|
|
80
|
+
Calls ``worktree_ensure`` per candidate-WT-1.md section 5.1.
|
|
81
|
+
"""
|
|
82
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
83
|
+
name = _require_non_empty(name, field="name")
|
|
84
|
+
|
|
85
|
+
params: Dict[str, Any] = {
|
|
86
|
+
"project_id": project_id,
|
|
87
|
+
"name": name,
|
|
88
|
+
}
|
|
89
|
+
if branch is not None:
|
|
90
|
+
params["branch"] = branch
|
|
91
|
+
if start_point is not None:
|
|
92
|
+
params["start_point"] = start_point
|
|
93
|
+
if not create_branch:
|
|
94
|
+
params["create_branch"] = False
|
|
95
|
+
if owner_session_id is not None:
|
|
96
|
+
params["owner_session_id"] = owner_session_id
|
|
97
|
+
|
|
98
|
+
return _unwrap(
|
|
99
|
+
await self._client.call_validated("worktree_ensure", params)
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
async def list(
|
|
103
|
+
self,
|
|
104
|
+
project_id: str,
|
|
105
|
+
*,
|
|
106
|
+
owner_session_id: Optional[str] = None,
|
|
107
|
+
only_names: Optional[List[str]] = None,
|
|
108
|
+
) -> Dict[str, Any]:
|
|
109
|
+
"""List worktrees in a project.
|
|
110
|
+
|
|
111
|
+
Calls ``worktree_list`` per candidate-WT-1.md section 5.2.
|
|
112
|
+
"""
|
|
113
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
114
|
+
|
|
115
|
+
params: Dict[str, Any] = {"project_id": project_id}
|
|
116
|
+
if owner_session_id is not None:
|
|
117
|
+
params["owner_session_id"] = owner_session_id
|
|
118
|
+
if only_names is not None:
|
|
119
|
+
params["only_names"] = only_names
|
|
120
|
+
|
|
121
|
+
return _unwrap(
|
|
122
|
+
await self._client.call_validated("worktree_list", params)
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
async def status(
|
|
126
|
+
self,
|
|
127
|
+
project_id: str,
|
|
128
|
+
name: str,
|
|
129
|
+
) -> Dict[str, Any]:
|
|
130
|
+
"""Get git status of one worktree (working tree + index).
|
|
131
|
+
|
|
132
|
+
Calls ``worktree_status`` per candidate-WT-1.md section 5.3.
|
|
133
|
+
"""
|
|
134
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
135
|
+
name = _require_non_empty(name, field="name")
|
|
136
|
+
|
|
137
|
+
params: Dict[str, Any] = {
|
|
138
|
+
"project_id": project_id,
|
|
139
|
+
"name": name,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return _unwrap(
|
|
143
|
+
await self._client.call_validated("worktree_status", params)
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
async def diff(
|
|
147
|
+
self,
|
|
148
|
+
project_id: str,
|
|
149
|
+
name: str,
|
|
150
|
+
*,
|
|
151
|
+
base: Optional[str] = None,
|
|
152
|
+
path: Optional[str] = None,
|
|
153
|
+
include_patch: bool = False,
|
|
154
|
+
) -> Dict[str, Any]:
|
|
155
|
+
"""Diff worktree against base branch.
|
|
156
|
+
|
|
157
|
+
Calls ``worktree_diff`` per candidate-WT-1.md section 5.4.
|
|
158
|
+
"""
|
|
159
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
160
|
+
name = _require_non_empty(name, field="name")
|
|
161
|
+
|
|
162
|
+
params: Dict[str, Any] = {
|
|
163
|
+
"project_id": project_id,
|
|
164
|
+
"name": name,
|
|
165
|
+
}
|
|
166
|
+
if base is not None:
|
|
167
|
+
params["base"] = base
|
|
168
|
+
if path is not None:
|
|
169
|
+
params["path"] = path
|
|
170
|
+
if include_patch:
|
|
171
|
+
params["include_patch"] = True
|
|
172
|
+
|
|
173
|
+
return _unwrap(
|
|
174
|
+
await self._client.call_validated("worktree_diff", params)
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# === Sync and conflict resolution ===
|
|
178
|
+
|
|
179
|
+
async def sync(
|
|
180
|
+
self,
|
|
181
|
+
project_id: str,
|
|
182
|
+
name: str,
|
|
183
|
+
*,
|
|
184
|
+
strategy: Optional[str] = None,
|
|
185
|
+
base: Optional[str] = None,
|
|
186
|
+
auto_poll: bool = True,
|
|
187
|
+
timeout: Optional[float] = None,
|
|
188
|
+
) -> Dict[str, Any]:
|
|
189
|
+
"""Sync worktree from main branch (merge or rebase).
|
|
190
|
+
|
|
191
|
+
Calls ``worktree_sync`` per candidate-WT-1.md section 5.5.
|
|
192
|
+
Raises WorktreeConflictError on WORKTREE_SYNC_CONFLICT.
|
|
193
|
+
"""
|
|
194
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
195
|
+
name = _require_non_empty(name, field="name")
|
|
196
|
+
|
|
197
|
+
params: Dict[str, Any] = {
|
|
198
|
+
"project_id": project_id,
|
|
199
|
+
"name": name,
|
|
200
|
+
}
|
|
201
|
+
if strategy is not None:
|
|
202
|
+
params["strategy"] = strategy
|
|
203
|
+
if base is not None:
|
|
204
|
+
params["base"] = base
|
|
205
|
+
|
|
206
|
+
result = await self._client.call_validated(
|
|
207
|
+
"worktree_sync",
|
|
208
|
+
params,
|
|
209
|
+
auto_poll=auto_poll,
|
|
210
|
+
timeout=timeout,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Check for WORKTREE_SYNC_CONFLICT error
|
|
214
|
+
if isinstance(result, dict) and not result.get("success", True):
|
|
215
|
+
error = result.get("error", {})
|
|
216
|
+
if error.get("code") == "WORKTREE_SYNC_CONFLICT":
|
|
217
|
+
details = error.get("details", {})
|
|
218
|
+
raise WorktreeConflictError(
|
|
219
|
+
"Worktree sync conflict",
|
|
220
|
+
conflicts=details.get("conflicts"),
|
|
221
|
+
preserved_locked_files=details.get("preserved_locked_files"),
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
return _unwrap(result)
|
|
225
|
+
|
|
226
|
+
async def conflicts(
|
|
227
|
+
self,
|
|
228
|
+
project_id: str,
|
|
229
|
+
name: str,
|
|
230
|
+
) -> Dict[str, Any]:
|
|
231
|
+
"""List merge/rebase conflicts with per-file markers.
|
|
232
|
+
|
|
233
|
+
Calls ``worktree_conflicts`` per candidate-WT-1.md section 5.6.
|
|
234
|
+
"""
|
|
235
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
236
|
+
name = _require_non_empty(name, field="name")
|
|
237
|
+
|
|
238
|
+
params: Dict[str, Any] = {
|
|
239
|
+
"project_id": project_id,
|
|
240
|
+
"name": name,
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return _unwrap(
|
|
244
|
+
await self._client.call_validated("worktree_conflicts", params)
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
async def continue_(
|
|
248
|
+
self,
|
|
249
|
+
project_id: str,
|
|
250
|
+
name: str,
|
|
251
|
+
resolved_paths: List[str],
|
|
252
|
+
*,
|
|
253
|
+
message: Optional[str] = None,
|
|
254
|
+
auto_poll: bool = True,
|
|
255
|
+
timeout: Optional[float] = None,
|
|
256
|
+
) -> Dict[str, Any]:
|
|
257
|
+
"""Finalize merge or rebase after resolving conflicts.
|
|
258
|
+
|
|
259
|
+
Calls ``worktree_continue`` per candidate-WT-1.md section 5.7.
|
|
260
|
+
"""
|
|
261
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
262
|
+
name = _require_non_empty(name, field="name")
|
|
263
|
+
if not resolved_paths:
|
|
264
|
+
raise ClientValidationError(
|
|
265
|
+
"resolved_paths must be non-empty",
|
|
266
|
+
field="resolved_paths",
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
params: Dict[str, Any] = {
|
|
270
|
+
"project_id": project_id,
|
|
271
|
+
"name": name,
|
|
272
|
+
"resolved_paths": resolved_paths,
|
|
273
|
+
}
|
|
274
|
+
if message is not None:
|
|
275
|
+
params["message"] = message
|
|
276
|
+
|
|
277
|
+
return _unwrap(
|
|
278
|
+
await self._client.call_validated(
|
|
279
|
+
"worktree_continue",
|
|
280
|
+
params,
|
|
281
|
+
auto_poll=auto_poll,
|
|
282
|
+
timeout=timeout,
|
|
283
|
+
)
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
async def abort(
|
|
287
|
+
self,
|
|
288
|
+
project_id: str,
|
|
289
|
+
name: str,
|
|
290
|
+
*,
|
|
291
|
+
auto_poll: bool = True,
|
|
292
|
+
timeout: Optional[float] = None,
|
|
293
|
+
) -> Dict[str, Any]:
|
|
294
|
+
"""Abort in-progress merge or rebase.
|
|
295
|
+
|
|
296
|
+
Calls ``worktree_abort`` per candidate-WT-1.md section 5.8.
|
|
297
|
+
"""
|
|
298
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
299
|
+
name = _require_non_empty(name, field="name")
|
|
300
|
+
|
|
301
|
+
params: Dict[str, Any] = {
|
|
302
|
+
"project_id": project_id,
|
|
303
|
+
"name": name,
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return _unwrap(
|
|
307
|
+
await self._client.call_validated(
|
|
308
|
+
"worktree_abort",
|
|
309
|
+
params,
|
|
310
|
+
auto_poll=auto_poll,
|
|
311
|
+
timeout=timeout,
|
|
312
|
+
)
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
# === Commit and removal ===
|
|
316
|
+
|
|
317
|
+
async def commit(
|
|
318
|
+
self,
|
|
319
|
+
project_id: str,
|
|
320
|
+
name: str,
|
|
321
|
+
message: str,
|
|
322
|
+
*,
|
|
323
|
+
paths: Optional[List[str]] = None,
|
|
324
|
+
all: bool = False,
|
|
325
|
+
auto_poll: bool = True,
|
|
326
|
+
timeout: Optional[float] = None,
|
|
327
|
+
) -> Dict[str, Any]:
|
|
328
|
+
"""Commit staged or all changes in worktree.
|
|
329
|
+
|
|
330
|
+
Calls ``worktree_commit`` per candidate-WT-1.md section 5.9.
|
|
331
|
+
"""
|
|
332
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
333
|
+
name = _require_non_empty(name, field="name")
|
|
334
|
+
message = _require_non_empty(message, field="message")
|
|
335
|
+
|
|
336
|
+
if not paths and not all:
|
|
337
|
+
raise ClientValidationError(
|
|
338
|
+
"At least one of paths or all=true is required",
|
|
339
|
+
field="paths",
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
params: Dict[str, Any] = {
|
|
343
|
+
"project_id": project_id,
|
|
344
|
+
"name": name,
|
|
345
|
+
"message": message,
|
|
346
|
+
}
|
|
347
|
+
if paths is not None:
|
|
348
|
+
params["paths"] = paths
|
|
349
|
+
if all:
|
|
350
|
+
params["all"] = True
|
|
351
|
+
|
|
352
|
+
return _unwrap(
|
|
353
|
+
await self._client.call_validated(
|
|
354
|
+
"worktree_commit",
|
|
355
|
+
params,
|
|
356
|
+
auto_poll=auto_poll,
|
|
357
|
+
timeout=timeout,
|
|
358
|
+
)
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
async def remove(
|
|
362
|
+
self,
|
|
363
|
+
project_id: str,
|
|
364
|
+
name: str,
|
|
365
|
+
*,
|
|
366
|
+
force: bool = False,
|
|
367
|
+
delete_branch: bool = True,
|
|
368
|
+
auto_poll: bool = True,
|
|
369
|
+
timeout: Optional[float] = None,
|
|
370
|
+
) -> Dict[str, Any]:
|
|
371
|
+
"""Remove a worktree and optionally its branch.
|
|
372
|
+
|
|
373
|
+
Calls ``worktree_remove`` per candidate-WT-1.md section 5.10.
|
|
374
|
+
"""
|
|
375
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
376
|
+
name = _require_non_empty(name, field="name")
|
|
377
|
+
|
|
378
|
+
params: Dict[str, Any] = {
|
|
379
|
+
"project_id": project_id,
|
|
380
|
+
"name": name,
|
|
381
|
+
}
|
|
382
|
+
if force:
|
|
383
|
+
params["force"] = True
|
|
384
|
+
if not delete_branch:
|
|
385
|
+
params["delete_branch"] = False
|
|
386
|
+
|
|
387
|
+
return _unwrap(
|
|
388
|
+
await self._client.call_validated(
|
|
389
|
+
"worktree_remove",
|
|
390
|
+
params,
|
|
391
|
+
auto_poll=auto_poll,
|
|
392
|
+
timeout=timeout,
|
|
393
|
+
)
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
async def prune(
|
|
397
|
+
self,
|
|
398
|
+
project_id: str,
|
|
399
|
+
*,
|
|
400
|
+
name: Optional[str] = None,
|
|
401
|
+
ttl_seconds: Optional[int] = None,
|
|
402
|
+
only_names: Optional[List[str]] = None,
|
|
403
|
+
dry_run: bool = False,
|
|
404
|
+
auto_poll: bool = True,
|
|
405
|
+
timeout: Optional[float] = None,
|
|
406
|
+
) -> Dict[str, Any]:
|
|
407
|
+
"""TTL safety net: reap idle worktrees whose sessions are gone.
|
|
408
|
+
|
|
409
|
+
Calls ``worktree_prune`` per candidate-WT-1.md section 5.11.
|
|
410
|
+
"""
|
|
411
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
412
|
+
|
|
413
|
+
params: Dict[str, Any] = {"project_id": project_id}
|
|
414
|
+
if name is not None:
|
|
415
|
+
params["name"] = name
|
|
416
|
+
if ttl_seconds is not None:
|
|
417
|
+
params["ttl_seconds"] = ttl_seconds
|
|
418
|
+
if only_names is not None:
|
|
419
|
+
params["only_names"] = only_names
|
|
420
|
+
if dry_run:
|
|
421
|
+
params["dry_run"] = True
|
|
422
|
+
|
|
423
|
+
return _unwrap(
|
|
424
|
+
await self._client.call_validated(
|
|
425
|
+
"worktree_prune",
|
|
426
|
+
params,
|
|
427
|
+
auto_poll=auto_poll,
|
|
428
|
+
timeout=timeout,
|
|
429
|
+
)
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
# === Lock and maintenance ===
|
|
433
|
+
|
|
434
|
+
async def lock(
|
|
435
|
+
self,
|
|
436
|
+
project_id: str,
|
|
437
|
+
name: str,
|
|
438
|
+
*,
|
|
439
|
+
reason: Optional[str] = None,
|
|
440
|
+
) -> Dict[str, Any]:
|
|
441
|
+
"""Lock a worktree to protect from removal.
|
|
442
|
+
|
|
443
|
+
Calls ``worktree_lock`` per candidate-WT-1.md section 5.12.
|
|
444
|
+
"""
|
|
445
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
446
|
+
name = _require_non_empty(name, field="name")
|
|
447
|
+
|
|
448
|
+
params: Dict[str, Any] = {
|
|
449
|
+
"project_id": project_id,
|
|
450
|
+
"name": name,
|
|
451
|
+
}
|
|
452
|
+
if reason is not None:
|
|
453
|
+
params["reason"] = reason
|
|
454
|
+
|
|
455
|
+
return _unwrap(
|
|
456
|
+
await self._client.call_validated("worktree_lock", params)
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
async def unlock(
|
|
460
|
+
self,
|
|
461
|
+
project_id: str,
|
|
462
|
+
name: str,
|
|
463
|
+
) -> Dict[str, Any]:
|
|
464
|
+
"""Unlock a worktree.
|
|
465
|
+
|
|
466
|
+
Calls ``worktree_unlock`` per candidate-WT-1.md section 5.13.
|
|
467
|
+
"""
|
|
468
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
469
|
+
name = _require_non_empty(name, field="name")
|
|
470
|
+
|
|
471
|
+
params: Dict[str, Any] = {
|
|
472
|
+
"project_id": project_id,
|
|
473
|
+
"name": name,
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return _unwrap(
|
|
477
|
+
await self._client.call_validated("worktree_unlock", params)
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
async def move(
|
|
481
|
+
self,
|
|
482
|
+
project_id: str,
|
|
483
|
+
name: str,
|
|
484
|
+
new_name: str,
|
|
485
|
+
*,
|
|
486
|
+
auto_poll: bool = True,
|
|
487
|
+
timeout: Optional[float] = None,
|
|
488
|
+
) -> Dict[str, Any]:
|
|
489
|
+
"""Move/rename a worktree.
|
|
490
|
+
|
|
491
|
+
Calls ``worktree_move`` per candidate-WT-1.md section 5.14.
|
|
492
|
+
"""
|
|
493
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
494
|
+
name = _require_non_empty(name, field="name")
|
|
495
|
+
new_name = _require_non_empty(new_name, field="new_name")
|
|
496
|
+
|
|
497
|
+
params: Dict[str, Any] = {
|
|
498
|
+
"project_id": project_id,
|
|
499
|
+
"name": name,
|
|
500
|
+
"new_name": new_name,
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return _unwrap(
|
|
504
|
+
await self._client.call_validated(
|
|
505
|
+
"worktree_move",
|
|
506
|
+
params,
|
|
507
|
+
auto_poll=auto_poll,
|
|
508
|
+
timeout=timeout,
|
|
509
|
+
)
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
async def repair(
|
|
513
|
+
self,
|
|
514
|
+
project_id: str,
|
|
515
|
+
name: str,
|
|
516
|
+
*,
|
|
517
|
+
auto_poll: bool = True,
|
|
518
|
+
timeout: Optional[float] = None,
|
|
519
|
+
) -> Dict[str, Any]:
|
|
520
|
+
"""Repair worktree after manual filesystem move/restore.
|
|
521
|
+
|
|
522
|
+
Calls ``worktree_repair`` per candidate-WT-1.md section 5.15.
|
|
523
|
+
"""
|
|
524
|
+
project_id = _require_non_empty(project_id, field="project_id")
|
|
525
|
+
name = _require_non_empty(name, field="name")
|
|
526
|
+
|
|
527
|
+
params: Dict[str, Any] = {
|
|
528
|
+
"project_id": project_id,
|
|
529
|
+
"name": name,
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return _unwrap(
|
|
533
|
+
await self._client.call_validated(
|
|
534
|
+
"worktree_repair",
|
|
535
|
+
params,
|
|
536
|
+
auto_poll=auto_poll,
|
|
537
|
+
timeout=timeout,
|
|
538
|
+
)
|
|
539
|
+
)
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/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.6.
|
|
3
|
+
Version: 1.6.176
|
|
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
|
|
@@ -15,6 +15,7 @@ code_analysis_client/server_schema.py
|
|
|
15
15
|
code_analysis_client/universal_file.py
|
|
16
16
|
code_analysis_client/validation.py
|
|
17
17
|
code_analysis_client/version.txt
|
|
18
|
+
code_analysis_client/worktree.py
|
|
18
19
|
code_analysis_client.egg-info/PKG-INFO
|
|
19
20
|
code_analysis_client.egg-info/SOURCES.txt
|
|
20
21
|
code_analysis_client.egg-info/dependency_links.txt
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.6.173
|
|
File without changes
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/commands_proxy.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/config.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/exceptions.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/file_session.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/queue_wait.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/responses.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/server_api.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/server_schema.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/universal_file.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.173 → code_analysis_client-1.6.176}/code_analysis_client/validation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|