delegate-agent-cli 0.22.0__tar.gz → 0.23.0__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.
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/CHANGELOG.md +11 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/PKG-INFO +2 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/README.md +1 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/cli-reference.md +3 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/delegate-workflows.md +2 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/pyproject.toml +1 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/__init__.py +1 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/cli.py +6 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/cli_parser.py +35 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/command_help.py +30 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/inspection_commands.py +31 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/rendering.py +18 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/run_registry.py +155 -3
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent_cli.egg-info/PKG-INFO +2 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_delegate_help_cli.py +1 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_delegate_parser.py +24 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_inspection_commands.py +170 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/CONTRIBUTING.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/LICENSE +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/MANIFEST.in +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/SECURITY.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/bin/delegate-profile-shim +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/bin/delegate.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/config.example.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/agent-setup.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/assets/delegate-agent-header.png +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/configuration.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/development.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/live-runtime.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/publishing-checklist.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/security-model.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/troubleshooting.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/docs/worktrees.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/examples/task.claude.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/examples/task.codex.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/examples/task.cursor.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/examples/task.droid.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/examples/task.grok.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/examples/task.judge.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/examples/task.kimi.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/setup.cfg +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/archived_logs.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/argv_builders.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/argv_utils.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/bundled_models.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/capability_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/child_failures.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/command_errors.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/config.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/config_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/constants.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/describe_payload.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/errors.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/git_utils.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/harness_discovery.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/harness_events.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/isolation.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/json_types.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/log_output.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/model_discovery.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/private_io.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/profile_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/profile_guard.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/profiles.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/prompt_instructions.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/prompt_transport.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/reasoning.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/redaction.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/request_build.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/request_models.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/retention.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/run_metadata.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/run_output_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/run_status.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/runner.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/safe_workspace.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/seatbelt.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/setup_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/snapshot_view.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/structured_output.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/wait_cancel_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/workflows/__init__.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/workflows/commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/workflows/registry.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/workflows/runtime.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/workflows/schema.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/workflows/script.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/worktree_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/worktree_execution.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/worktree_gc.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/worktree_mgmt.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/worktree_records.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/worktree_remove.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/worktree_summary.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/wsl.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent_cli.egg-info/SOURCES.txt +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent_cli.egg-info/dependency_links.txt +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent_cli.egg-info/entry_points.txt +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent_cli.egg-info/requires.txt +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent_cli.egg-info/top_level.txt +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_capability_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_child_failures.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_codex_pure_sandbox.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_codex_thread_resilience.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_command_help.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_config_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_delegate_isolation.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_delegate_validation.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_end_to_end_tracking.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_engine_argv.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_execution_argv_and_prompt.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_execution_dry_run.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_execution_worktree_failure_cleanup.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_execution_worktree_preflight.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_execution_worktree_run.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_harness_discovery.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_harness_events.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_kimi_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_model_discovery.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_model_selection_wave1a.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_model_selection_wave1b.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_omp_read_only_behavior.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_packaging.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_profiles.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_pure_call.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_reasoning_capabilities.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_retention.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_run_registry.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_runner_capture.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_safe_workspace_isolation.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_setup_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_slash_passthrough.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_snapshot_redaction.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_snapshot_rendering.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_snapshot_run_output.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_snapshot_view.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_structured_output.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_tracked_timeout.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_utility_modules.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_wait_cancel_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_wave4_launch_features.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_workflow_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_worktree_list_show.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_worktree_prune_gc.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_worktree_remove.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/tests/test_wsl_guardrails.py +0 -0
|
@@ -5,6 +5,16 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.23.0] - 2026-07-30
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added `delegate runs prune` with a 30-day default age threshold, an explicit `--older-than` override, and `--dry-run` preview output. It prunes terminal Run records and their associated Registry artifacts (per-Run directory, logs, Completion Report, retained raw-log archive) without touching genuinely running Runs. Persistent-worktree Runs are skipped unless their worktree is recorded as removed or missing — unknown or unrecorded worktree status is treated as possibly present, mirroring `worktree gc` — so live worktrees never lose their Registry records. The ambient retention pass is bypassed on the prune command path so a dry run never mutates state.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Focused unittest invocations (`python3 -m unittest tests.<module>`) no longer fail on the src layout import: `tests/__init__.py` now puts `src` on `sys.path` before any test module import runs.
|
|
17
|
+
|
|
8
18
|
## [0.22.0] - 2026-07-26
|
|
9
19
|
|
|
10
20
|
### Changed
|
|
@@ -759,6 +769,7 @@ Usage-audit fix wave: 82 sessions and 1,241 delegate invocations from one week o
|
|
|
759
769
|
|
|
760
770
|
- Releases before 0.1.3 predate this changelog.
|
|
761
771
|
|
|
772
|
+
[0.23.0]: https://github.com/treygoff24/delegate-agent/compare/v0.22.0...v0.23.0
|
|
762
773
|
[0.22.0]: https://github.com/treygoff24/delegate-agent/compare/v0.21.0...v0.22.0
|
|
763
774
|
[0.21.0]: https://github.com/treygoff24/delegate-agent/compare/v0.20.0...v0.21.0
|
|
764
775
|
[0.20.0]: https://github.com/treygoff24/delegate-agent/compare/v0.19.0...v0.20.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: delegate-agent-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
4
4
|
Summary: A tiny CLI for delegating bounded agent tasks across coding-agent runtimes.
|
|
5
5
|
Author: Trey Goff
|
|
6
6
|
License-Expression: MIT
|
|
@@ -332,6 +332,7 @@ delegate runs --recent
|
|
|
332
332
|
delegate ps # active and stale tracked runs
|
|
333
333
|
delegate snapshot <alias-or-runId>
|
|
334
334
|
delegate run-output <alias-or-runId>
|
|
335
|
+
delegate runs prune --dry-run # preview GC of terminal run records older than 30 days
|
|
335
336
|
```
|
|
336
337
|
|
|
337
338
|
Aliases are always numbered (`codex-1`, `cursor-2`); a **bare harness name
|
|
@@ -299,6 +299,7 @@ delegate runs --recent
|
|
|
299
299
|
delegate ps # active and stale tracked runs
|
|
300
300
|
delegate snapshot <alias-or-runId>
|
|
301
301
|
delegate run-output <alias-or-runId>
|
|
302
|
+
delegate runs prune --dry-run # preview GC of terminal run records older than 30 days
|
|
302
303
|
```
|
|
303
304
|
|
|
304
305
|
Aliases are always numbered (`codex-1`, `cursor-2`); a **bare harness name
|
|
@@ -931,6 +931,7 @@ Tracked runs return bounded parent-facing output and store local metadata under
|
|
|
931
931
|
|
|
932
932
|
```bash
|
|
933
933
|
delegate runs [--active|--running|--stale|--recent] [--harness HARNESS] [--group NAME] [--limit N]
|
|
934
|
+
delegate runs prune [--older-than DAYS] [--dry-run]
|
|
934
935
|
delegate ps [--harness HARNESS] [--group NAME] [--limit N]
|
|
935
936
|
delegate snapshot [--latest HARNESS] [--no-redact] <handle>
|
|
936
937
|
delegate run-output [--latest HARNESS] <handle> [--completion-report] [--stdout] [--stderr] [--tail N] [--max-chars N] [--raw] [--no-redact]
|
|
@@ -942,6 +943,8 @@ delegate cancel <handle>...
|
|
|
942
943
|
`delegate ps` is the shorter first-class form of `delegate runs --active` and
|
|
943
944
|
accepts the same harness, group, and limit selectors.
|
|
944
945
|
|
|
946
|
+
`delegate runs prune` removes old terminal Run records from the workspace Registry so they stop accumulating forever. Only runs whose effective status is terminal (`succeeded`, `failed`, `cancelled`, or `stale` from a dead child) and whose last Registry activity is older than the threshold (default 30 days; override with `--older-than DAYS`) are eligible. Effectively running runs are always skipped, and persistent-worktree runs are skipped unless their worktree is recorded as removed or missing — pruning the record of a live worktree would orphan it from `worktree list`/`show`/`remove`. Pruning deletes the per-Run directory (Snapshot, Manifest, logs, events, Completion Report) and the retained raw-log archive; worktree paths on disk are never touched. `--dry-run` reports what would be removed without changing anything. JSON output uses schema `delegate.runs-prune.v1` with `planned`, `removed`, `skipped` (each entry carries a `reason`), and `errors` sections.
|
|
947
|
+
|
|
945
948
|
Run-scoped handles (`snapshot`, `run-output`, `wait`, and `cancel`)
|
|
946
949
|
resolve exact run IDs and numbered aliases first. A bare harness name such as
|
|
947
950
|
`codex` resolves to that harness's latest run, and `harness:modelAlias` (for
|
|
@@ -175,6 +175,7 @@ engines = args.get("engines", ["codex", "claude", "cursor"])
|
|
|
175
175
|
models = args.get("models", {})
|
|
176
176
|
prompt = args["prompt"]
|
|
177
177
|
|
|
178
|
+
|
|
178
179
|
def reviewer(engine):
|
|
179
180
|
return lambda: agent(
|
|
180
181
|
prompt,
|
|
@@ -184,6 +185,7 @@ def reviewer(engine):
|
|
|
184
185
|
phase=f"Review ({engine})",
|
|
185
186
|
)
|
|
186
187
|
|
|
188
|
+
|
|
187
189
|
reviews = parallel([reviewer(engine) for engine in engines])
|
|
188
190
|
return {"reviews": dict(zip(engines, reviews))}
|
|
189
191
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "delegate-agent-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.23.0"
|
|
8
8
|
description = "A tiny CLI for delegating bounded agent tasks across coding-agent runtimes."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -1180,7 +1180,12 @@ def main(
|
|
|
1180
1180
|
"workflow",
|
|
1181
1181
|
}:
|
|
1182
1182
|
existing_registry = run_registry.registry_root_if_exists(Path(workspace.path))
|
|
1183
|
-
|
|
1183
|
+
pruning_runs = (
|
|
1184
|
+
parsed.subcommand == "runs"
|
|
1185
|
+
and parsed.runs is not None
|
|
1186
|
+
and parsed.runs.action == "prune"
|
|
1187
|
+
)
|
|
1188
|
+
if existing_registry is not None and not pruning_runs:
|
|
1184
1189
|
maybe_run_retention_pass(existing_registry, config)
|
|
1185
1190
|
if parsed.subcommand == "snapshot":
|
|
1186
1191
|
return emit_snapshot(parsed, workspace, stdout)
|
|
@@ -1380,7 +1380,10 @@ def parse_runs(
|
|
|
1380
1380
|
# front-ends (ps) do not report errors against flags nobody entered.
|
|
1381
1381
|
rest, json_mode = consume_json_option(rest, json_mode)
|
|
1382
1382
|
if any(command_help.is_help_token(token) for token in rest):
|
|
1383
|
-
|
|
1383
|
+
topic = "runs prune" if rest and rest[0] == "prune" else "runs"
|
|
1384
|
+
return help_command(json_mode, topic)
|
|
1385
|
+
if rest and rest[0] == "prune":
|
|
1386
|
+
return parse_runs_prune(rest[1:], json_mode, cwd)
|
|
1384
1387
|
active = False
|
|
1385
1388
|
recent = False
|
|
1386
1389
|
running = False
|
|
@@ -1468,6 +1471,37 @@ def parse_runs(
|
|
|
1468
1471
|
)
|
|
1469
1472
|
|
|
1470
1473
|
|
|
1474
|
+
def parse_runs_prune(rest: list[str], json_mode: bool, cwd: str | None) -> ParsedCommand:
|
|
1475
|
+
rest, json_mode = consume_json_option(rest, json_mode)
|
|
1476
|
+
if any(command_help.is_help_token(token) for token in rest):
|
|
1477
|
+
return help_command(json_mode, "runs prune")
|
|
1478
|
+
older_than_days = None
|
|
1479
|
+
dry_run = False
|
|
1480
|
+
i = 0
|
|
1481
|
+
while i < len(rest):
|
|
1482
|
+
token = rest[i]
|
|
1483
|
+
if token == "--older-than":
|
|
1484
|
+
value = _require_option_value(rest, i, token)
|
|
1485
|
+
older_than_days = parse_non_negative_int(value, option="runs prune --older-than")
|
|
1486
|
+
i += 2
|
|
1487
|
+
continue
|
|
1488
|
+
if token == "--dry-run":
|
|
1489
|
+
dry_run = True
|
|
1490
|
+
i += 1
|
|
1491
|
+
continue
|
|
1492
|
+
raise DelegateError("unknown_option", f"runs prune does not support option: {token}")
|
|
1493
|
+
return ParsedCommand(
|
|
1494
|
+
"runs",
|
|
1495
|
+
global_options=GlobalOptions(json_mode=json_mode, cwd=cwd),
|
|
1496
|
+
runs=inspection_commands.RunsCommand(
|
|
1497
|
+
action="prune",
|
|
1498
|
+
older_than_days=older_than_days,
|
|
1499
|
+
dry_run=dry_run,
|
|
1500
|
+
json_mode=json_mode,
|
|
1501
|
+
),
|
|
1502
|
+
)
|
|
1503
|
+
|
|
1504
|
+
|
|
1471
1505
|
def parse_ps(rest: list[str], json_mode: bool, cwd: str | None) -> ParsedCommand:
|
|
1472
1506
|
rest, json_mode = consume_json_option(rest, json_mode)
|
|
1473
1507
|
if any(command_help.is_help_token(token) for token in rest):
|
|
@@ -16,6 +16,7 @@ from dataclasses import dataclass, field
|
|
|
16
16
|
from delegate_agent import VERSION
|
|
17
17
|
from delegate_agent.constants import ENGINES_PROSE
|
|
18
18
|
from delegate_agent.json_types import JsonObject
|
|
19
|
+
from delegate_agent.run_registry import DEFAULT_RUN_PRUNE_DAYS
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
@dataclass(frozen=True)
|
|
@@ -818,7 +819,34 @@ COMMAND_SPECS: dict[str, CommandSpec] = {
|
|
|
818
819
|
"delegate runs --group wave4",
|
|
819
820
|
),
|
|
820
821
|
notes=("--active, --running, --stale, and --recent are mutually exclusive.",),
|
|
821
|
-
see_also=("ps", "snapshot", "run-output"),
|
|
822
|
+
see_also=("ps", "runs prune", "snapshot", "run-output"),
|
|
823
|
+
unsupported_global_options=("--auth-profile",),
|
|
824
|
+
),
|
|
825
|
+
"runs prune": CommandSpec(
|
|
826
|
+
name="runs prune",
|
|
827
|
+
summary="Prune old terminal Run records from the workspace Registry.",
|
|
828
|
+
usage=("delegate [--cwd PATH] [--json] runs prune [--older-than DAYS] [--dry-run]",),
|
|
829
|
+
options=(
|
|
830
|
+
OptionSpec(
|
|
831
|
+
"--older-than",
|
|
832
|
+
"DAYS",
|
|
833
|
+
f"Prune Runs older than DAYS by Registry activity time (defaults to {DEFAULT_RUN_PRUNE_DAYS}; non-negative integer).",
|
|
834
|
+
),
|
|
835
|
+
OptionSpec(
|
|
836
|
+
"--dry-run",
|
|
837
|
+
None,
|
|
838
|
+
"Report planned removals without changing the Registry, logs, or artifacts.",
|
|
839
|
+
),
|
|
840
|
+
),
|
|
841
|
+
examples=(
|
|
842
|
+
"delegate runs prune --dry-run",
|
|
843
|
+
"delegate runs prune --older-than 14",
|
|
844
|
+
),
|
|
845
|
+
notes=(
|
|
846
|
+
"Only terminal effective statuses are eligible: succeeded, failed, cancelled, and stale from a dead child; effective running Runs are always skipped.",
|
|
847
|
+
"Runs with a registered present persistent worktree are skipped, so their worktree remains manageable. Pruning removes the per-Run directory, including its Snapshot, Manifest, logs, events, and Completion Report, plus the retained raw-log archive.",
|
|
848
|
+
),
|
|
849
|
+
see_also=("runs", "snapshot", "run-output"),
|
|
822
850
|
unsupported_global_options=("--auth-profile",),
|
|
823
851
|
),
|
|
824
852
|
"ps": CommandSpec(
|
|
@@ -1745,6 +1773,7 @@ def render_overview_text() -> str:
|
|
|
1745
1773
|
"delegate [--cwd PATH] [--json] snapshot [--latest HARNESS] [--no-redact] <handle>",
|
|
1746
1774
|
"delegate [--cwd PATH] [--json] runs "
|
|
1747
1775
|
"[--active|--running|--stale|--recent] [--harness HARNESS] [--limit N]",
|
|
1776
|
+
"delegate [--cwd PATH] [--json] runs prune [--older-than DAYS] [--dry-run]",
|
|
1748
1777
|
"delegate [--cwd PATH] [--json] ps [--harness HARNESS] [--group NAME] [--limit N]",
|
|
1749
1778
|
"delegate [--cwd PATH] [--json] run-output <handle> "
|
|
1750
1779
|
"[--completion-report] [--stdout] [--stderr] [--tail N] [--max-chars N] "
|
{delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent/inspection_commands.py
RENAMED
|
@@ -19,12 +19,15 @@ class SnapshotCommand:
|
|
|
19
19
|
|
|
20
20
|
@dataclass(frozen=True)
|
|
21
21
|
class RunsCommand:
|
|
22
|
+
action: str | None = None
|
|
22
23
|
active: bool = False
|
|
23
24
|
running: bool = False
|
|
24
25
|
stale: bool = False
|
|
25
26
|
harness: str | None = None
|
|
26
27
|
group: str | None = None
|
|
27
28
|
limit: int | None = None
|
|
29
|
+
older_than_days: int | None = None
|
|
30
|
+
dry_run: bool = False
|
|
28
31
|
json_mode: bool = False
|
|
29
32
|
|
|
30
33
|
|
|
@@ -64,6 +67,34 @@ def emit_snapshot(command: SnapshotCommand, *, workspace_path: str, stdout: Text
|
|
|
64
67
|
|
|
65
68
|
def emit_runs(command: RunsCommand, *, workspace_path: str, stdout: TextIO) -> int:
|
|
66
69
|
registry_root = run_registry.registry_root_if_exists(Path(workspace_path))
|
|
70
|
+
if command.action == "prune":
|
|
71
|
+
older_than_days = (
|
|
72
|
+
command.older_than_days
|
|
73
|
+
if command.older_than_days is not None
|
|
74
|
+
else run_registry.DEFAULT_RUN_PRUNE_DAYS
|
|
75
|
+
)
|
|
76
|
+
payload = (
|
|
77
|
+
run_registry.prune_runs(
|
|
78
|
+
registry_root,
|
|
79
|
+
older_than_days=older_than_days,
|
|
80
|
+
dry_run=command.dry_run,
|
|
81
|
+
)
|
|
82
|
+
if registry_root is not None
|
|
83
|
+
else run_registry.empty_run_prune_payload(
|
|
84
|
+
older_than_days=older_than_days,
|
|
85
|
+
dry_run=command.dry_run,
|
|
86
|
+
)
|
|
87
|
+
)
|
|
88
|
+
if command.json_mode:
|
|
89
|
+
delegate_rendering.print_json(payload, stdout)
|
|
90
|
+
else:
|
|
91
|
+
delegate_rendering.render_runs_prune_text(payload, stdout)
|
|
92
|
+
if payload.get("ok") is False:
|
|
93
|
+
exit_code = payload.get("exitCode")
|
|
94
|
+
return exit_code if isinstance(exit_code, int) else 1
|
|
95
|
+
return 0
|
|
96
|
+
if command.action is not None:
|
|
97
|
+
raise InspectionError("unknown_runs_action", f"Unknown runs action: {command.action}")
|
|
67
98
|
limit = command.limit or run_registry.DEFAULT_RUNS_LIMIT
|
|
68
99
|
if command.running:
|
|
69
100
|
mode = "running"
|
|
@@ -554,6 +554,24 @@ def render_worktree_prune_text(payload: JsonObject, stdout: TextIO) -> None:
|
|
|
554
554
|
print(f" - {label} {detail}", file=stdout)
|
|
555
555
|
|
|
556
556
|
|
|
557
|
+
def render_runs_prune_text(payload: JsonObject, stdout: TextIO) -> None:
|
|
558
|
+
print(f"older than: {payload.get('olderThanDays', '?')} days", file=stdout)
|
|
559
|
+
if payload.get("dryRun") is True:
|
|
560
|
+
print("dry run: Registry, logs, and artifacts unchanged", file=stdout)
|
|
561
|
+
for section in ("planned", "removed", "skipped", "errors"):
|
|
562
|
+
items = payload.get(section)
|
|
563
|
+
count = len(items) if isinstance(items, list) else 0
|
|
564
|
+
print(f"{section}: {count}", file=stdout)
|
|
565
|
+
if isinstance(items, list):
|
|
566
|
+
for item in items[:20]:
|
|
567
|
+
if isinstance(item, dict):
|
|
568
|
+
label = item.get("alias") or item.get("runId") or "?"
|
|
569
|
+
detail = (
|
|
570
|
+
item.get("reason") or item.get("code") or item.get("effectiveStatus") or ""
|
|
571
|
+
)
|
|
572
|
+
print(f" - {label} {detail}", file=stdout)
|
|
573
|
+
|
|
574
|
+
|
|
557
575
|
def render_worktree_gc_text(payload: JsonObject, stdout: TextIO) -> None:
|
|
558
576
|
print(f"reconciled: {payload.get('reconciled', 0)}", file=stdout)
|
|
559
577
|
if payload.get("dryRun") is True:
|
|
@@ -6,16 +6,17 @@ import os
|
|
|
6
6
|
import re
|
|
7
7
|
import secrets
|
|
8
8
|
import shlex
|
|
9
|
+
import shutil
|
|
9
10
|
import subprocess
|
|
10
11
|
import time
|
|
11
12
|
from collections.abc import Iterator
|
|
12
13
|
from contextlib import contextmanager
|
|
13
14
|
from dataclasses import dataclass
|
|
14
|
-
from datetime import UTC, datetime
|
|
15
|
+
from datetime import UTC, datetime, timedelta
|
|
15
16
|
from pathlib import Path
|
|
16
17
|
|
|
17
|
-
from delegate_agent import private_io
|
|
18
|
-
from delegate_agent.json_types import JsonObject
|
|
18
|
+
from delegate_agent import archived_logs, private_io
|
|
19
|
+
from delegate_agent.json_types import JsonObject, is_non_negative_int
|
|
19
20
|
from delegate_agent.private_io import ( # noqa: F401 # re-exported
|
|
20
21
|
RegistryJsonError,
|
|
21
22
|
ensure_private_dir,
|
|
@@ -47,6 +48,9 @@ STATE_SCHEMA = "delegate.state.v1"
|
|
|
47
48
|
SNAPSHOT_SCHEMA = "delegate.snapshot.v1"
|
|
48
49
|
RUNS_SCHEMA = "delegate.runs.v1"
|
|
49
50
|
RUN_OUTPUT_SCHEMA = "delegate.run-output.v1"
|
|
51
|
+
RUNS_PRUNE_SCHEMA = "delegate.runs-prune.v1"
|
|
52
|
+
DEFAULT_RUN_PRUNE_DAYS = 30
|
|
53
|
+
RUN_PRUNE_ERROR_EXIT_CODE = 1
|
|
50
54
|
REGISTRY_LOCK_NAME = ".registry.lock"
|
|
51
55
|
REGISTRY_LOCK_TIMEOUT_SECONDS = 30.0
|
|
52
56
|
REGISTRY_LOCK_POLL_SECONDS = 0.05
|
|
@@ -832,3 +836,151 @@ from delegate_agent.run_status import ( # noqa: E402, F401 # re-exported
|
|
|
832
836
|
stale_next_actions,
|
|
833
837
|
status_fields,
|
|
834
838
|
)
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def _run_prune_ref(
|
|
842
|
+
index: JsonObject,
|
|
843
|
+
run_id: str,
|
|
844
|
+
status: str,
|
|
845
|
+
*,
|
|
846
|
+
reason: str | None = None,
|
|
847
|
+
) -> JsonObject:
|
|
848
|
+
entry: JsonObject = {
|
|
849
|
+
"alias": alias_for_run(index, run_id),
|
|
850
|
+
"runId": run_id,
|
|
851
|
+
"effectiveStatus": status,
|
|
852
|
+
}
|
|
853
|
+
if reason is not None:
|
|
854
|
+
entry["reason"] = reason
|
|
855
|
+
return entry
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
def _remove_run_record_artifacts(registry_root: Path, run_id: str) -> None:
|
|
859
|
+
run_path = run_directory(registry_root, run_id)
|
|
860
|
+
if run_path.is_symlink():
|
|
861
|
+
raise OSError(f"refusing to prune symlinked run directory: {run_path}")
|
|
862
|
+
if run_path.exists():
|
|
863
|
+
shutil.rmtree(run_path)
|
|
864
|
+
archived_logs.archive_path(registry_root, run_id).unlink(missing_ok=True)
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
def empty_run_prune_payload(*, older_than_days: int, dry_run: bool) -> JsonObject:
|
|
868
|
+
return {
|
|
869
|
+
"schema": RUNS_PRUNE_SCHEMA,
|
|
870
|
+
"ok": True,
|
|
871
|
+
"olderThanDays": older_than_days,
|
|
872
|
+
"dryRun": dry_run,
|
|
873
|
+
"planned": [],
|
|
874
|
+
"removed": [],
|
|
875
|
+
"skipped": [],
|
|
876
|
+
"errors": [],
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
def prune_runs(
|
|
881
|
+
registry_root: Path,
|
|
882
|
+
*,
|
|
883
|
+
older_than_days: int = DEFAULT_RUN_PRUNE_DAYS,
|
|
884
|
+
dry_run: bool = False,
|
|
885
|
+
now: datetime | None = None,
|
|
886
|
+
) -> JsonObject:
|
|
887
|
+
"""Prune old terminal Run records and their per-Run artifacts."""
|
|
888
|
+
if not is_non_negative_int(older_than_days):
|
|
889
|
+
raise ValueError("older_than_days must be a non-negative integer")
|
|
890
|
+
# worktree_records imports this module, so keep this dependency local.
|
|
891
|
+
from delegate_agent import worktree_records
|
|
892
|
+
|
|
893
|
+
cutoff = (now or datetime.now(UTC)) - timedelta(days=older_than_days)
|
|
894
|
+
planned: list[JsonObject] = []
|
|
895
|
+
removed: list[JsonObject] = []
|
|
896
|
+
skipped: list[JsonObject] = []
|
|
897
|
+
errors: list[JsonObject] = []
|
|
898
|
+
index_changed = False
|
|
899
|
+
|
|
900
|
+
with registry_lock(registry_root):
|
|
901
|
+
index = load_index(registry_root)
|
|
902
|
+
# Like worktree gc, treat unknown/unrecorded status as possibly present:
|
|
903
|
+
# only records whose worktree is affirmatively gone are prunable.
|
|
904
|
+
present_persistent_worktree_run_ids = {
|
|
905
|
+
record["runId"]
|
|
906
|
+
for record in worktree_records.load_persistent_records(registry_root)
|
|
907
|
+
if record.get("registryWorktreeStatus")
|
|
908
|
+
not in (worktree_records.STATUS_REMOVED, worktree_records.STATUS_MISSING)
|
|
909
|
+
}
|
|
910
|
+
for run_id, index_entry in list(index.get("runs", {}).items()):
|
|
911
|
+
if not isinstance(run_id, str) or not isinstance(index_entry, dict):
|
|
912
|
+
continue
|
|
913
|
+
if not RUN_ID_RE.fullmatch(run_id):
|
|
914
|
+
skipped.append(
|
|
915
|
+
_run_prune_ref(
|
|
916
|
+
index, run_id, run_status.STATUS_UNKNOWN, reason="invalid_run_id"
|
|
917
|
+
)
|
|
918
|
+
)
|
|
919
|
+
continue
|
|
920
|
+
state = load_run_state_or_none(registry_root, run_id)
|
|
921
|
+
effective_status = run_status.effective_status(state)
|
|
922
|
+
if run_id in present_persistent_worktree_run_ids:
|
|
923
|
+
skipped.append(
|
|
924
|
+
_run_prune_ref(
|
|
925
|
+
index,
|
|
926
|
+
run_id,
|
|
927
|
+
effective_status,
|
|
928
|
+
reason="persistent_worktree",
|
|
929
|
+
)
|
|
930
|
+
)
|
|
931
|
+
continue
|
|
932
|
+
if effective_status == run_status.STATUS_RUNNING:
|
|
933
|
+
skipped.append(_run_prune_ref(index, run_id, effective_status, reason="running"))
|
|
934
|
+
continue
|
|
935
|
+
if effective_status not in run_status.TERMINAL_STATUSES | {run_status.STATUS_STALE}:
|
|
936
|
+
skipped.append(
|
|
937
|
+
_run_prune_ref(index, run_id, effective_status, reason="non_terminal")
|
|
938
|
+
)
|
|
939
|
+
continue
|
|
940
|
+
manifest = load_run_manifest_or_none(registry_root, run_id)
|
|
941
|
+
activity = run_status.activity_datetime(state, manifest, run_id)
|
|
942
|
+
if activity is None:
|
|
943
|
+
skipped.append(
|
|
944
|
+
_run_prune_ref(index, run_id, effective_status, reason="invalid_activity")
|
|
945
|
+
)
|
|
946
|
+
continue
|
|
947
|
+
if activity >= cutoff:
|
|
948
|
+
skipped.append(
|
|
949
|
+
_run_prune_ref(index, run_id, effective_status, reason="not_yet_old_enough")
|
|
950
|
+
)
|
|
951
|
+
continue
|
|
952
|
+
candidate = _run_prune_ref(index, run_id, effective_status)
|
|
953
|
+
candidate["activityAt"] = run_status.activity_timestamp(state, manifest, run_id)
|
|
954
|
+
planned.append(candidate)
|
|
955
|
+
if dry_run:
|
|
956
|
+
continue
|
|
957
|
+
try:
|
|
958
|
+
_remove_run_record_artifacts(registry_root, run_id)
|
|
959
|
+
except OSError as exc:
|
|
960
|
+
errors.append({**candidate, "code": "record_remove_failed", "message": str(exc)})
|
|
961
|
+
continue
|
|
962
|
+
for alias, target_run_id in list(index.get("aliases", {}).items()):
|
|
963
|
+
if target_run_id != run_id:
|
|
964
|
+
continue
|
|
965
|
+
index["aliases"].pop(alias, None)
|
|
966
|
+
if isinstance(alias, str) and alias and alias not in {".", ".."}:
|
|
967
|
+
claim_path = aliases_dir(registry_root) / alias
|
|
968
|
+
if Path(alias).name == alias and (
|
|
969
|
+
claim_path.is_file() or claim_path.is_symlink()
|
|
970
|
+
):
|
|
971
|
+
claim_path.unlink(missing_ok=True)
|
|
972
|
+
index["runs"].pop(run_id, None)
|
|
973
|
+
removed.append(candidate)
|
|
974
|
+
index_changed = True
|
|
975
|
+
if index_changed:
|
|
976
|
+
save_index(registry_root, index)
|
|
977
|
+
|
|
978
|
+
payload = empty_run_prune_payload(older_than_days=older_than_days, dry_run=dry_run)
|
|
979
|
+
payload["planned"] = planned
|
|
980
|
+
payload["removed"] = removed
|
|
981
|
+
payload["skipped"] = skipped
|
|
982
|
+
payload["errors"] = errors
|
|
983
|
+
if errors:
|
|
984
|
+
payload["ok"] = False
|
|
985
|
+
payload["exitCode"] = RUN_PRUNE_ERROR_EXIT_CODE
|
|
986
|
+
return payload
|
{delegate_agent_cli-0.22.0 → delegate_agent_cli-0.23.0}/src/delegate_agent_cli.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: delegate-agent-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
4
4
|
Summary: A tiny CLI for delegating bounded agent tasks across coding-agent runtimes.
|
|
5
5
|
Author: Trey Goff
|
|
6
6
|
License-Expression: MIT
|
|
@@ -332,6 +332,7 @@ delegate runs --recent
|
|
|
332
332
|
delegate ps # active and stale tracked runs
|
|
333
333
|
delegate snapshot <alias-or-runId>
|
|
334
334
|
delegate run-output <alias-or-runId>
|
|
335
|
+
delegate runs prune --dry-run # preview GC of terminal run records older than 30 days
|
|
335
336
|
```
|
|
336
337
|
|
|
337
338
|
Aliases are always numbered (`codex-1`, `cursor-2`); a **bare harness name
|
|
@@ -101,6 +101,7 @@ class MultiLevelHelpTests(HelpCliTestBase):
|
|
|
101
101
|
(["dry-run", "droid", "--help"], "dry-run"),
|
|
102
102
|
(["worktree", "remove", "--help"], "worktree remove"),
|
|
103
103
|
(["worktree", "prune", "--help"], "worktree prune"),
|
|
104
|
+
(["runs", "prune", "--help"], "runs prune"),
|
|
104
105
|
(["worktree", "list", "--help"], "worktree list"),
|
|
105
106
|
(["worktree", "show", "--help"], "worktree show"),
|
|
106
107
|
(["worktree", "gc", "--help"], "worktree gc"),
|
|
@@ -1100,6 +1100,30 @@ class ParserTests(unittest.TestCase):
|
|
|
1100
1100
|
self.delegate.parse_cli(["runs", "--limit", "0"])
|
|
1101
1101
|
self.assertEqual(ctx.exception.error, "invalid_limit")
|
|
1102
1102
|
|
|
1103
|
+
def test_runs_prune_parses_age_override_and_dry_run(self):
|
|
1104
|
+
parsed = self.delegate.parse_cli(
|
|
1105
|
+
[
|
|
1106
|
+
"--json",
|
|
1107
|
+
"--cwd",
|
|
1108
|
+
"/tmp/repo",
|
|
1109
|
+
"runs",
|
|
1110
|
+
"prune",
|
|
1111
|
+
"--older-than",
|
|
1112
|
+
"14",
|
|
1113
|
+
"--dry-run",
|
|
1114
|
+
]
|
|
1115
|
+
)
|
|
1116
|
+
self.assertEqual(parsed.subcommand, "runs")
|
|
1117
|
+
self.assertEqual(parsed.runs.action, "prune")
|
|
1118
|
+
self.assertEqual(parsed.runs.older_than_days, 14)
|
|
1119
|
+
self.assertTrue(parsed.runs.dry_run)
|
|
1120
|
+
self.assertTrue(parsed.runs.json_mode)
|
|
1121
|
+
|
|
1122
|
+
def test_runs_prune_rejects_negative_age(self):
|
|
1123
|
+
with self.assertRaises(self.delegate.DelegateError) as ctx:
|
|
1124
|
+
self.delegate.parse_cli(["runs", "prune", "--older-than", "-1"])
|
|
1125
|
+
self.assertEqual(ctx.exception.error, "missing_option_value")
|
|
1126
|
+
|
|
1103
1127
|
def test_has_misplaced_global_option_detects_exact_tokens(self):
|
|
1104
1128
|
self.assertFalse(self.delegate.has_misplaced_global_option([]))
|
|
1105
1129
|
self.assertFalse(self.delegate.has_misplaced_global_option(["--jsonish"]))
|