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.
Files changed (54) hide show
  1. delegate_agent/__init__.py +5 -0
  2. delegate_agent/archived_logs.py +44 -0
  3. delegate_agent/argv_builders.py +423 -0
  4. delegate_agent/argv_utils.py +36 -0
  5. delegate_agent/capability_commands.py +99 -0
  6. delegate_agent/cli.py +987 -0
  7. delegate_agent/cli_parser.py +1627 -0
  8. delegate_agent/command_errors.py +29 -0
  9. delegate_agent/command_help.py +1264 -0
  10. delegate_agent/config.py +1117 -0
  11. delegate_agent/config_commands.py +143 -0
  12. delegate_agent/constants.py +50 -0
  13. delegate_agent/describe_payload.py +1018 -0
  14. delegate_agent/errors.py +32 -0
  15. delegate_agent/git_utils.py +180 -0
  16. delegate_agent/harness_events.py +719 -0
  17. delegate_agent/inspection_commands.py +104 -0
  18. delegate_agent/isolation.py +316 -0
  19. delegate_agent/json_types.py +18 -0
  20. delegate_agent/log_output.py +78 -0
  21. delegate_agent/private_io.py +109 -0
  22. delegate_agent/profile_commands.py +42 -0
  23. delegate_agent/profile_guard.py +116 -0
  24. delegate_agent/profiles.py +389 -0
  25. delegate_agent/prompt_instructions.py +39 -0
  26. delegate_agent/prompt_transport.py +12 -0
  27. delegate_agent/reasoning.py +916 -0
  28. delegate_agent/redaction.py +193 -0
  29. delegate_agent/rendering.py +573 -0
  30. delegate_agent/request_build.py +1681 -0
  31. delegate_agent/request_models.py +191 -0
  32. delegate_agent/retention.py +321 -0
  33. delegate_agent/run_metadata.py +78 -0
  34. delegate_agent/run_output_commands.py +645 -0
  35. delegate_agent/run_registry.py +747 -0
  36. delegate_agent/run_status.py +300 -0
  37. delegate_agent/runner.py +1830 -0
  38. delegate_agent/safe_workspace.py +821 -0
  39. delegate_agent/snapshot_view.py +229 -0
  40. delegate_agent/wait_cancel_commands.py +559 -0
  41. delegate_agent/worktree_commands.py +218 -0
  42. delegate_agent/worktree_execution.py +654 -0
  43. delegate_agent/worktree_gc.py +529 -0
  44. delegate_agent/worktree_mgmt.py +782 -0
  45. delegate_agent/worktree_records.py +232 -0
  46. delegate_agent/worktree_remove.py +547 -0
  47. delegate_agent/worktree_summary.py +242 -0
  48. delegate_agent/wsl.py +65 -0
  49. delegate_agent_cli-0.11.0.dist-info/METADATA +325 -0
  50. delegate_agent_cli-0.11.0.dist-info/RECORD +54 -0
  51. delegate_agent_cli-0.11.0.dist-info/WHEEL +5 -0
  52. delegate_agent_cli-0.11.0.dist-info/entry_points.txt +2 -0
  53. delegate_agent_cli-0.11.0.dist-info/licenses/LICENSE +21 -0
  54. delegate_agent_cli-0.11.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,193 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from collections.abc import Mapping
5
+
6
+ from delegate_agent.json_types import JsonValue
7
+
8
+ SLACK_WEBHOOK_SCHEME = "https"
9
+ URL_SCHEME_SEPARATOR = "://"
10
+ SLACK_WEBHOOK_HOST_PATTERN = r"hooks\.slack(?:-gov)?\.com"
11
+ SLACK_WEBHOOK_PATH_PATTERN = r"/services/T[A-Z0-9]+/B[A-Z0-9]+/[A-Za-z0-9]+"
12
+
13
+ REDACT_PATTERNS: list[tuple[re.Pattern[str], str]] = [
14
+ # Authorization header value, quoted or bare. The optional quote after the key
15
+ # tolerates JSON ({"Authorization": "..."}); the value is bounded on the right
16
+ # so we don't swallow trailing structure (closing quote/brace/&/,).
17
+ (
18
+ re.compile(
19
+ r"(?i)\b(authorization[\"']?\s*[:=]\s*)"
20
+ r"(?:\"[^\"\r\n]*\"|'[^'\r\n]*'|[^\s,&}\"'\r\n][^\r\n,&}]*)"
21
+ ),
22
+ r"\1***",
23
+ ),
24
+ # Bare scheme token not behind an Authorization key (e.g. "Bearer eyJ...").
25
+ (
26
+ re.compile(r"(?i)\b((?:bearer|basic)\s+)[A-Za-z0-9._~+/=-]{8,}"),
27
+ r"\1***",
28
+ ),
29
+ # Bracketed environment assignments, e.g. os.environ["OPENAI_API_KEY"] = "..."
30
+ # and env['DB_PASSWORD']='...'. Keep this before the generic key matcher: the
31
+ # separator between the secret key and value is outside the bracketed lookup.
32
+ (
33
+ re.compile(
34
+ r"(?i)\b((?:os\.environ|env)\[\s*[\"'][^\"'\]\r\n]*"
35
+ r"(?:api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|"
36
+ r"access[_-]?token|refresh[_-]?token|auth[_-]?token|authtoken|"
37
+ r"client[_-]?secret|password|passwd|secret|token)"
38
+ r"[^\"'\]\r\n]*[\"']\s*\]\s*=\s*)"
39
+ r"(?:\"[^\"\r\n]*\"|'[^'\r\n]*'|[^\s,&};\"'\r\n][^\r\n,&};]*)"
40
+ ),
41
+ r"\1***",
42
+ ),
43
+ # Named credential keys with the value quoted, bare, or JSON-quoted. The left
44
+ # edge anchors on a non-alphanumeric character (or string start) rather than
45
+ # \b, so env-style prefixes joined by "_" still redact (OPENAI_API_KEY=,
46
+ # DB_PASSWORD=, aws_secret_access_key=). Separator is preserved so the shape
47
+ # stays readable.
48
+ (
49
+ re.compile(
50
+ r"(?i)(?:(?<=[^A-Za-z0-9])|^)("
51
+ r"api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|"
52
+ r"access[_-]?token|refresh[_-]?token|auth[_-]?token|authtoken|"
53
+ r"client[_-]?secret|password|passwd|secret|token"
54
+ r")([\"']?\s*[:=]\s*)"
55
+ r"(?:\"[^\"\r\n]*\"|'[^'\r\n]*'|[^\s,&};\"'\r\n][^\r\n,&};]*)"
56
+ ),
57
+ r"\1\2***",
58
+ ),
59
+ # Password embedded in a connection string: scheme://[user]:PASS@host. The
60
+ # scheme length is bounded so a long dotted string cannot backtrack quadratically.
61
+ (
62
+ re.compile(r"(?i)\b([a-z][a-z0-9+.-]{1,40}://[^\s:/@]*:)[^\s:/@]+(@)"),
63
+ r"\1***\2",
64
+ ),
65
+ # JWTs are anchored on the eyJ header (base64url of '{"') so this does not shred
66
+ # ordinary dotted identifiers and tracebacks the parent agent needs to read.
67
+ (
68
+ re.compile(r"\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b"),
69
+ "***",
70
+ ),
71
+ # PEM private key blocks are handled by _redact_pem_blocks() before this list
72
+ # runs. A DOTALL regex here is both easier to make backtracking-prone and can
73
+ # let keyed values like SECRET_KEY=<PEM> leak the body after the first newline.
74
+ # Provider token shapes are prefix-anchored; we deliberately avoid a blanket
75
+ # high-entropy matcher, which would redact legitimate hashes/IDs/output.
76
+ (re.compile(r"\bsk-(?:proj|ant|svcacct)-[A-Za-z0-9_-]{8,}"), "sk-***"),
77
+ (re.compile(r"\bsk-[A-Za-z0-9]{8,}"), "sk-***"),
78
+ (re.compile(r"\bgh[opusr]_[A-Za-z0-9]{20,}\b"), "gh***"),
79
+ (re.compile(r"\bgithub_pat_[A-Za-z0-9_]{20,}\b"), "github_pat_***"),
80
+ (re.compile(r"\b(AKIA|ASIA)[0-9A-Z]{16}\b"), r"\1***"),
81
+ (re.compile(r"\bAIza[0-9A-Za-z_-]{32,}\b"), "AIza***"),
82
+ (re.compile(r"\bxox[baprs]-[A-Za-z0-9-]{10,}"), "xox***"),
83
+ # Stripe secret/restricted keys (live or test); publishable pk_ keys are
84
+ # public by design and intentionally excluded.
85
+ (re.compile(r"\b([sr]k_(?:live|test)_)[0-9A-Za-z]{10,}\b"), r"\1***"),
86
+ (re.compile(r"\bwhsec_[A-Za-z0-9]{10,}\b"), "whsec_***"),
87
+ (re.compile(r"\bnpm_[A-Za-z0-9]{36,}\b"), "npm_***"),
88
+ (re.compile(r"\bSG\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\b"), "SG.***"),
89
+ (
90
+ re.compile(
91
+ SLACK_WEBHOOK_SCHEME
92
+ + URL_SCHEME_SEPARATOR
93
+ + SLACK_WEBHOOK_HOST_PATTERN
94
+ + SLACK_WEBHOOK_PATH_PATTERN
95
+ ),
96
+ "***",
97
+ ),
98
+ ]
99
+
100
+
101
+ PEM_BLOCK_PLACEHOLDER = "***PRIVATE KEY REDACTED***"
102
+ _PEM_BEGIN = re.compile(r"-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----")
103
+ _PEM_END = re.compile(r"-----END [A-Z0-9 ]*PRIVATE KEY-----")
104
+ _URL_SPAN_RE = re.compile(r"[A-Za-z][A-Za-z0-9+.-]*://[^\s\"'`<>|;,)]+")
105
+ # Absolute POSIX paths outside URL spans; avoid matching ratio-style "1/2".
106
+ _ABSOLUTE_POSIX_PATH_RE = re.compile(
107
+ r"(?<![A-Za-z0-9_.~+-])/(?:[^\s\"'`<>|;,)]+(?:/[^\s\"'`<>|;,)]+)*)"
108
+ )
109
+ _TILDE_PATH_RE = re.compile(r"(?<!\S)~(?:/[^\s\"'`<>|;,)]+)+")
110
+ _WINDOWS_PATH_RE = re.compile(r"\b[A-Za-z]:\\[^\s\"'`<>|;,)]+")
111
+ _SECRET_KEY_RE = re.compile(
112
+ r"("
113
+ r"API[_-]?KEY|APIKEY|ACCESS[_-]?KEY|SECRET[_-]?KEY|PRIVATE[_-]?KEY|"
114
+ r"ACCESS[_-]?TOKEN|REFRESH[_-]?TOKEN|AUTH[_-]?TOKEN|AUTHTOKEN|"
115
+ r"CLIENT[_-]?SECRET|PASSWORD|PASSWD|SECRET|TOKEN|CREDENTIAL"
116
+ r")",
117
+ re.IGNORECASE,
118
+ )
119
+
120
+
121
+ def _mask_progress_paths_outside_urls(value: str) -> str:
122
+ parts: list[str] = []
123
+ last = 0
124
+ for match in _URL_SPAN_RE.finditer(value):
125
+ segment = value[last : match.start()]
126
+ if segment:
127
+ segment = _ABSOLUTE_POSIX_PATH_RE.sub("<redacted-path>", segment)
128
+ segment = _TILDE_PATH_RE.sub("<redacted-path>", segment)
129
+ segment = _WINDOWS_PATH_RE.sub("<redacted-path>", segment)
130
+ parts.append(segment)
131
+ parts.append(match.group(0))
132
+ last = match.end()
133
+ tail = value[last:]
134
+ if tail:
135
+ tail = _ABSOLUTE_POSIX_PATH_RE.sub("<redacted-path>", tail)
136
+ tail = _TILDE_PATH_RE.sub("<redacted-path>", tail)
137
+ tail = _WINDOWS_PATH_RE.sub("<redacted-path>", tail)
138
+ parts.append(tail)
139
+ return "".join(parts)
140
+
141
+
142
+ def _redact_pem_blocks(value: str) -> str:
143
+ match = _PEM_BEGIN.search(value)
144
+ if match is None:
145
+ return value
146
+ parts: list[str] = []
147
+ pos = 0
148
+ while match is not None:
149
+ parts.append(value[pos : match.start()])
150
+ end = _PEM_END.search(value, match.end())
151
+ parts.append(PEM_BLOCK_PLACEHOLDER)
152
+ if end is None:
153
+ return "".join(parts)
154
+ pos = end.end()
155
+ match = _PEM_BEGIN.search(value, pos)
156
+ parts.append(value[pos:])
157
+ return "".join(parts)
158
+
159
+
160
+ def redact_string(value: str) -> str:
161
+ redacted = _redact_pem_blocks(value)
162
+ for pattern, replacement in REDACT_PATTERNS:
163
+ redacted = pattern.sub(replacement, redacted)
164
+ return redacted
165
+
166
+
167
+ def redact_progress_label(value: str) -> str:
168
+ redacted = redact_string(value)
169
+ return _mask_progress_paths_outside_urls(redacted)
170
+
171
+
172
+ def key_looks_secret(key: str) -> bool:
173
+ return _SECRET_KEY_RE.search(key) is not None
174
+
175
+
176
+ def redact_mapping_value(key: str, value: JsonValue) -> JsonValue:
177
+ if key_looks_secret(key):
178
+ return "***"
179
+ return redact_value(value)
180
+
181
+
182
+ def redact_env_map(mapping: Mapping[str, str]) -> dict[str, JsonValue]:
183
+ return {key: redact_mapping_value(key, value) for key, value in mapping.items()}
184
+
185
+
186
+ def redact_value(value: JsonValue) -> JsonValue:
187
+ if isinstance(value, str):
188
+ return redact_string(value)
189
+ if isinstance(value, list):
190
+ return [redact_value(item) for item in value]
191
+ if isinstance(value, dict):
192
+ return {key: redact_value(item) for key, item in value.items()}
193
+ return value