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,143 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from dataclasses import dataclass
5
+ from pathlib import Path
6
+ from typing import TextIO
7
+
8
+ from delegate_agent import config as delegate_config
9
+ from delegate_agent import rendering as delegate_rendering
10
+ from delegate_agent import wsl
11
+ from delegate_agent.errors import EXIT_OK, DelegateError
12
+ from delegate_agent.json_types import JsonObject
13
+ from delegate_agent.private_io import ensure_private_file
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class ConfigCommand:
18
+ action: str
19
+ force: bool = False
20
+ json_mode: bool = False
21
+
22
+
23
+ PROFILE_CONFIG_NAMES = delegate_config.PROFILE_CONFIG_NAMES
24
+
25
+
26
+ def _target_path() -> Path:
27
+ raw = delegate_config.config_path()
28
+ if wsl.should_reject_windows_path(str(raw)):
29
+ raise DelegateError("windows_path", wsl.windows_path_message("DELEGATE_CONFIG", str(raw)))
30
+ return raw
31
+
32
+
33
+ def _profile_overlay(config: JsonObject, profile: str) -> JsonObject | None:
34
+ profiles = config.get("profiles")
35
+ if not isinstance(profiles, dict):
36
+ return None
37
+ definitions = profiles.get("definitions")
38
+ if not isinstance(definitions, dict):
39
+ return None
40
+ definition = definitions.get(profile)
41
+ if not isinstance(definition, dict):
42
+ return None
43
+ detect_from = profiles.get("detectFrom", [])
44
+ overlay_profiles: JsonObject = {
45
+ "default": profile,
46
+ "definitions": {profile: definition},
47
+ }
48
+ if isinstance(detect_from, list):
49
+ overlay_profiles["detectFrom"] = [
50
+ item for item in detect_from if isinstance(item, str) and item.strip()
51
+ ]
52
+ return {"profiles": overlay_profiles}
53
+
54
+
55
+ def _write_missing_profile_configs(base_path: Path, config: JsonObject) -> JsonObject:
56
+ created: list[str] = []
57
+ existing: list[str] = []
58
+ skipped: list[str] = []
59
+ for profile in PROFILE_CONFIG_NAMES:
60
+ path = delegate_config.profile_config_path(base_path, profile)
61
+ if path.exists():
62
+ existing.append(str(path))
63
+ continue
64
+ overlay = _profile_overlay(config, profile)
65
+ if overlay is None:
66
+ skipped.append(profile)
67
+ continue
68
+ path.write_text(json.dumps(overlay, indent=2) + "\n", encoding="utf-8")
69
+ ensure_private_file(path)
70
+ created.append(str(path))
71
+ return {
72
+ "created": created,
73
+ "existing": existing,
74
+ "skipped": skipped,
75
+ }
76
+
77
+
78
+ def _read_config(path: Path) -> JsonObject:
79
+ try:
80
+ return delegate_config.read_config_file(path)
81
+ except delegate_config.ConfigError as exc:
82
+ raise DelegateError(exc.error, exc.message) from exc
83
+
84
+
85
+ def _validated_effective_config(config: JsonObject) -> JsonObject:
86
+ merged = delegate_config.merge_config_layer(delegate_config.embedded_default_config(), config)
87
+ try:
88
+ delegate_config.validate_config(merged)
89
+ except delegate_config.ConfigError as exc:
90
+ raise DelegateError(exc.error, exc.message) from exc
91
+ return merged
92
+
93
+
94
+ def emit(command: ConfigCommand, stdout: TextIO) -> int:
95
+ if command.action not in {"init", "sync-profiles"}:
96
+ raise DelegateError("invalid_config_command", f"Unknown config action: {command.action}")
97
+ path = _target_path()
98
+ if command.action == "sync-profiles":
99
+ if not path.exists():
100
+ raise DelegateError(
101
+ "config_not_found",
102
+ f"Config does not exist at {path}; run delegate config init first.",
103
+ )
104
+ payload = _validated_effective_config(_read_config(path))
105
+ profile_configs = _write_missing_profile_configs(path, payload)
106
+ result: JsonObject = {
107
+ "ok": True,
108
+ "path": str(path),
109
+ "action": "sync-profiles",
110
+ "profileConfigs": profile_configs,
111
+ }
112
+ if command.json_mode:
113
+ delegate_rendering.print_json(result, stdout)
114
+ else:
115
+ for created in profile_configs["created"]:
116
+ print(f"wrote profile config: {created}", file=stdout)
117
+ if not profile_configs["created"]:
118
+ print("profile configs already present", file=stdout)
119
+ return EXIT_OK
120
+ if path.exists() and not command.force:
121
+ raise DelegateError(
122
+ "config_exists",
123
+ f"Config already exists at {path}; pass --force to overwrite it.",
124
+ )
125
+ path.parent.mkdir(parents=True, exist_ok=True)
126
+ payload = delegate_config.example_config()
127
+ path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
128
+ ensure_private_file(path)
129
+ profile_configs = _write_missing_profile_configs(path, payload)
130
+ result: JsonObject = {
131
+ "ok": True,
132
+ "path": str(path),
133
+ "action": "init",
134
+ "force": command.force,
135
+ "profileConfigs": profile_configs,
136
+ }
137
+ if command.json_mode:
138
+ delegate_rendering.print_json(result, stdout)
139
+ else:
140
+ print(f"wrote config: {path}", file=stdout)
141
+ for created in profile_configs["created"]:
142
+ print(f"wrote profile config: {created}", file=stdout)
143
+ return EXIT_OK
@@ -0,0 +1,50 @@
1
+ """Cross-cutting CLI mode vocabulary and validation.
2
+
3
+ A dependency leaf shared by the parser, request builder, argv builders, and
4
+ execution layers so they agree on the launch mode vocabulary without
5
+ importing ``cli``.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from delegate_agent.errors import DelegateError
11
+
12
+ MODE_SAFE = "safe"
13
+ MODE_WORK = "work"
14
+ MODE_CALL = "call"
15
+ VALID_MODES = {MODE_SAFE, MODE_WORK, MODE_CALL}
16
+
17
+ # Canonical engine/harness vocabulary. This tuple's order is the registry order
18
+ # reused wherever engines are enumerated (the describe payload, help prose, the
19
+ # runs/worktree --harness filters). Membership checks and the prose enumeration
20
+ # both derive from it so the list can never drift out of sync.
21
+ KNOWN_ENGINES = ("cursor", "droid", "codex", "kimi", "claude", "grok")
22
+ # "cursor, droid, codex, kimi, claude, or grok" — for error messages and help text.
23
+ ENGINES_PROSE = f"{', '.join(KNOWN_ENGINES[:-1])}, or {KNOWN_ENGINES[-1]}"
24
+
25
+ # Engines launched without a model-alias positional argument.
26
+ MODELESS_ENGINES = tuple(engine for engine in KNOWN_ENGINES if engine != "droid")
27
+ # Engines whose binary is a simple <engine>.binary config key.
28
+ BINARY_CONFIG_ENGINES = tuple(engine for engine in KNOWN_ENGINES if engine != "cursor")
29
+ # Modeless engines accepted by input JSON's optional model field.
30
+ MODELESS_NONCURSOR_ENGINES = tuple(
31
+ engine for engine in KNOWN_ENGINES if engine not in {"cursor", "droid"}
32
+ )
33
+ # Engines whose safe-review prompt prefix is injected by request_build.effective_prompt.
34
+ SAFE_REVIEW_PREFIX_INJECTED_HERE_ENGINES = tuple(
35
+ engine for engine in KNOWN_ENGINES if engine in {"codex", "droid", "claude", "grok"}
36
+ )
37
+ # Stable public summary order; membership is still derived from the modeless engine set.
38
+ MODEL_SUMMARY_ENGINES = tuple(
39
+ engine for engine in ("cursor", "codex", "claude", "grok", "kimi") if engine in MODELESS_ENGINES
40
+ )
41
+
42
+
43
+ def validate_mode(mode: str) -> None:
44
+ if mode not in VALID_MODES:
45
+ raise DelegateError(
46
+ "invalid_mode",
47
+ "Mode must be safe, work, or call. Valid forms: "
48
+ "delegate <harness> safe|work <prompt>; "
49
+ "delegate droid <model-alias> safe|work <prompt>.",
50
+ )