delegate-agent-cli 0.11.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- delegate_agent/__init__.py +5 -0
- delegate_agent/archived_logs.py +44 -0
- delegate_agent/argv_builders.py +423 -0
- delegate_agent/argv_utils.py +36 -0
- delegate_agent/capability_commands.py +99 -0
- delegate_agent/cli.py +987 -0
- delegate_agent/cli_parser.py +1627 -0
- delegate_agent/command_errors.py +29 -0
- delegate_agent/command_help.py +1264 -0
- delegate_agent/config.py +1117 -0
- delegate_agent/config_commands.py +143 -0
- delegate_agent/constants.py +50 -0
- delegate_agent/describe_payload.py +1018 -0
- delegate_agent/errors.py +32 -0
- delegate_agent/git_utils.py +180 -0
- delegate_agent/harness_events.py +719 -0
- delegate_agent/inspection_commands.py +104 -0
- delegate_agent/isolation.py +316 -0
- delegate_agent/json_types.py +18 -0
- delegate_agent/log_output.py +78 -0
- delegate_agent/private_io.py +109 -0
- delegate_agent/profile_commands.py +42 -0
- delegate_agent/profile_guard.py +116 -0
- delegate_agent/profiles.py +389 -0
- delegate_agent/prompt_instructions.py +39 -0
- delegate_agent/prompt_transport.py +12 -0
- delegate_agent/reasoning.py +916 -0
- delegate_agent/redaction.py +193 -0
- delegate_agent/rendering.py +573 -0
- delegate_agent/request_build.py +1681 -0
- delegate_agent/request_models.py +191 -0
- delegate_agent/retention.py +321 -0
- delegate_agent/run_metadata.py +78 -0
- delegate_agent/run_output_commands.py +645 -0
- delegate_agent/run_registry.py +747 -0
- delegate_agent/run_status.py +300 -0
- delegate_agent/runner.py +1830 -0
- delegate_agent/safe_workspace.py +821 -0
- delegate_agent/snapshot_view.py +229 -0
- delegate_agent/wait_cancel_commands.py +559 -0
- delegate_agent/worktree_commands.py +218 -0
- delegate_agent/worktree_execution.py +654 -0
- delegate_agent/worktree_gc.py +529 -0
- delegate_agent/worktree_mgmt.py +782 -0
- delegate_agent/worktree_records.py +232 -0
- delegate_agent/worktree_remove.py +547 -0
- delegate_agent/worktree_summary.py +242 -0
- delegate_agent/wsl.py +65 -0
- delegate_agent_cli-0.11.0.dist-info/METADATA +325 -0
- delegate_agent_cli-0.11.0.dist-info/RECORD +54 -0
- delegate_agent_cli-0.11.0.dist-info/WHEEL +5 -0
- delegate_agent_cli-0.11.0.dist-info/entry_points.txt +2 -0
- delegate_agent_cli-0.11.0.dist-info/licenses/LICENSE +21 -0
- delegate_agent_cli-0.11.0.dist-info/top_level.txt +1 -0
delegate_agent/errors.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Process exit codes and the shared CLI error type.
|
|
2
|
+
|
|
3
|
+
This is a dependency leaf: it imports nothing from the rest of the package
|
|
4
|
+
(beyond JSON typing), so every other module can raise ``DelegateError``
|
|
5
|
+
without creating an import cycle through ``cli``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from delegate_agent.json_types import JsonObject
|
|
11
|
+
|
|
12
|
+
EXIT_OK = 0
|
|
13
|
+
EXIT_USAGE = 2
|
|
14
|
+
EXIT_MISSING_BINARY = 3
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DelegateError(Exception):
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
error: str,
|
|
21
|
+
message: str,
|
|
22
|
+
exit_code: int = EXIT_USAGE,
|
|
23
|
+
*,
|
|
24
|
+
diagnostics: JsonObject | None = None,
|
|
25
|
+
next_actions: list[str] | None = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
super().__init__(message)
|
|
28
|
+
self.error = error
|
|
29
|
+
self.message = message
|
|
30
|
+
self.exit_code = exit_code
|
|
31
|
+
self.diagnostics = diagnostics
|
|
32
|
+
self.next_actions = next_actions
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
GIT_QUICK_TIMEOUT_SECONDS = 10
|
|
8
|
+
GIT_MUTATION_TIMEOUT_SECONDS = 30
|
|
9
|
+
GIT_TIMEOUT_RETURN_CODE = 124
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def timeout_completed_process(
|
|
13
|
+
command: list[str],
|
|
14
|
+
exc: subprocess.TimeoutExpired,
|
|
15
|
+
*,
|
|
16
|
+
timeout_seconds: int,
|
|
17
|
+
) -> subprocess.CompletedProcess[str]:
|
|
18
|
+
return subprocess.CompletedProcess(
|
|
19
|
+
command,
|
|
20
|
+
GIT_TIMEOUT_RETURN_CODE,
|
|
21
|
+
exc.stdout or "",
|
|
22
|
+
f"git command timed out after {timeout_seconds}s",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def run_git(
|
|
27
|
+
cwd: str,
|
|
28
|
+
args: list[str],
|
|
29
|
+
*,
|
|
30
|
+
timeout_seconds: int = GIT_MUTATION_TIMEOUT_SECONDS,
|
|
31
|
+
) -> subprocess.CompletedProcess[str]:
|
|
32
|
+
command = ["git", "-C", cwd, *args]
|
|
33
|
+
try:
|
|
34
|
+
return subprocess.run( # nosec B603 - fixed git argv is executed with shell=False and a timeout.
|
|
35
|
+
command,
|
|
36
|
+
text=True,
|
|
37
|
+
capture_output=True,
|
|
38
|
+
check=False,
|
|
39
|
+
timeout=timeout_seconds,
|
|
40
|
+
)
|
|
41
|
+
except subprocess.TimeoutExpired as exc:
|
|
42
|
+
return timeout_completed_process(
|
|
43
|
+
command,
|
|
44
|
+
exc,
|
|
45
|
+
timeout_seconds=timeout_seconds,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def git_stdout_or_warn(
|
|
50
|
+
cwd: str,
|
|
51
|
+
args: list[str],
|
|
52
|
+
*,
|
|
53
|
+
warnings: list[str],
|
|
54
|
+
timeout_seconds: int,
|
|
55
|
+
git_runner: Callable[..., subprocess.CompletedProcess[str]] = run_git,
|
|
56
|
+
) -> str | None:
|
|
57
|
+
result = git_runner(cwd, args, timeout_seconds=timeout_seconds)
|
|
58
|
+
if result.returncode != 0:
|
|
59
|
+
detail = result.stderr.strip() or result.stdout.strip() or f"exit {result.returncode}"
|
|
60
|
+
warnings.append(f"git {' '.join(args)} failed: {detail}")
|
|
61
|
+
return None
|
|
62
|
+
return result.stdout.strip()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def rev_parse_verify(
|
|
66
|
+
cwd: str,
|
|
67
|
+
rev: str,
|
|
68
|
+
*,
|
|
69
|
+
warnings: list[str] | None = None,
|
|
70
|
+
timeout_seconds: int = GIT_QUICK_TIMEOUT_SECONDS,
|
|
71
|
+
git_runner: Callable[..., subprocess.CompletedProcess[str]] = run_git,
|
|
72
|
+
) -> str | None:
|
|
73
|
+
args = ["rev-parse", "--verify", rev]
|
|
74
|
+
if warnings is not None:
|
|
75
|
+
return git_stdout_or_warn(
|
|
76
|
+
cwd,
|
|
77
|
+
args,
|
|
78
|
+
warnings=warnings,
|
|
79
|
+
timeout_seconds=timeout_seconds,
|
|
80
|
+
git_runner=git_runner,
|
|
81
|
+
)
|
|
82
|
+
result = git_runner(cwd, args, timeout_seconds=timeout_seconds)
|
|
83
|
+
if result.returncode != 0:
|
|
84
|
+
return None
|
|
85
|
+
return result.stdout.strip()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def timeout_completed_process_bytes(
|
|
89
|
+
command: list[str],
|
|
90
|
+
exc: subprocess.TimeoutExpired,
|
|
91
|
+
*,
|
|
92
|
+
timeout_seconds: int,
|
|
93
|
+
) -> subprocess.CompletedProcess[bytes]:
|
|
94
|
+
stderr = exc.stderr or f"git command timed out after {timeout_seconds}s".encode()
|
|
95
|
+
if isinstance(stderr, str):
|
|
96
|
+
stderr = stderr.encode()
|
|
97
|
+
stdout = exc.stdout or b""
|
|
98
|
+
if isinstance(stdout, str):
|
|
99
|
+
stdout = stdout.encode()
|
|
100
|
+
return subprocess.CompletedProcess(
|
|
101
|
+
command,
|
|
102
|
+
GIT_TIMEOUT_RETURN_CODE,
|
|
103
|
+
stdout,
|
|
104
|
+
stderr,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def run_git_bytes(
|
|
109
|
+
cwd: str,
|
|
110
|
+
args: list[str],
|
|
111
|
+
*,
|
|
112
|
+
input_bytes: bytes | None = None,
|
|
113
|
+
timeout_seconds: int = GIT_MUTATION_TIMEOUT_SECONDS,
|
|
114
|
+
) -> subprocess.CompletedProcess[bytes]:
|
|
115
|
+
command = ["git", "-C", cwd, *args]
|
|
116
|
+
try:
|
|
117
|
+
return subprocess.run( # nosec B603 - fixed git argv is executed with shell=False and a timeout.
|
|
118
|
+
command,
|
|
119
|
+
input=input_bytes,
|
|
120
|
+
capture_output=True,
|
|
121
|
+
check=False,
|
|
122
|
+
timeout=timeout_seconds,
|
|
123
|
+
)
|
|
124
|
+
except subprocess.TimeoutExpired as exc:
|
|
125
|
+
return timeout_completed_process_bytes(
|
|
126
|
+
command,
|
|
127
|
+
exc,
|
|
128
|
+
timeout_seconds=timeout_seconds,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def capture_git_metadata(
|
|
133
|
+
workspace_path: str,
|
|
134
|
+
) -> tuple[str | None, str | None, str | None, str | None, str | None]:
|
|
135
|
+
"""Capture read-only Git metadata used for isolation planning.
|
|
136
|
+
|
|
137
|
+
Returns ``(git_root, git_common_dir, head_oid, head_ref, branch_name)``.
|
|
138
|
+
All fields are ``None`` when the workspace is not a Git repo or Git cannot
|
|
139
|
+
answer the probes.
|
|
140
|
+
"""
|
|
141
|
+
try:
|
|
142
|
+
root_result = run_git(
|
|
143
|
+
workspace_path,
|
|
144
|
+
["rev-parse", "--show-toplevel"],
|
|
145
|
+
timeout_seconds=GIT_QUICK_TIMEOUT_SECONDS,
|
|
146
|
+
)
|
|
147
|
+
if root_result.returncode != 0:
|
|
148
|
+
return None, None, None, None, None
|
|
149
|
+
git_root = root_result.stdout.strip()
|
|
150
|
+
|
|
151
|
+
common_result = run_git(
|
|
152
|
+
workspace_path,
|
|
153
|
+
["rev-parse", "--git-common-dir"],
|
|
154
|
+
timeout_seconds=GIT_QUICK_TIMEOUT_SECONDS,
|
|
155
|
+
)
|
|
156
|
+
git_common_dir = common_result.stdout.strip() if common_result.returncode == 0 else None
|
|
157
|
+
if git_common_dir and not git_common_dir.startswith("/"):
|
|
158
|
+
git_common_dir = str(Path(git_root) / git_common_dir)
|
|
159
|
+
|
|
160
|
+
oid_result = run_git(
|
|
161
|
+
workspace_path,
|
|
162
|
+
["rev-parse", "HEAD"],
|
|
163
|
+
timeout_seconds=GIT_QUICK_TIMEOUT_SECONDS,
|
|
164
|
+
)
|
|
165
|
+
head_oid = oid_result.stdout.strip() if oid_result.returncode == 0 else None
|
|
166
|
+
|
|
167
|
+
ref_result = run_git(
|
|
168
|
+
workspace_path,
|
|
169
|
+
["symbolic-ref", "--quiet", "HEAD"],
|
|
170
|
+
timeout_seconds=GIT_QUICK_TIMEOUT_SECONDS,
|
|
171
|
+
)
|
|
172
|
+
head_ref = ref_result.stdout.strip() if ref_result.returncode == 0 else None
|
|
173
|
+
|
|
174
|
+
branch_name = None
|
|
175
|
+
if head_ref and head_ref.startswith("refs/heads/"):
|
|
176
|
+
branch_name = head_ref[11:]
|
|
177
|
+
|
|
178
|
+
return git_root, git_common_dir, head_oid, head_ref, branch_name
|
|
179
|
+
except (FileNotFoundError, OSError, subprocess.SubprocessError):
|
|
180
|
+
return None, None, None, None, None
|