delegate-agent-cli 0.22.0__tar.gz → 0.24.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.24.0}/CHANGELOG.md +26 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/PKG-INFO +9 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/README.md +8 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/cli-reference.md +40 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/delegate-workflows.md +2 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/security-model.md +13 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/worktrees.md +19 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/pyproject.toml +1 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/__init__.py +1 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/cli.py +234 -7
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/cli_parser.py +208 -3
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/command_help.py +91 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/inspection_commands.py +31 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/isolation.py +3 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/private_io.py +97 -6
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/prompt_transport.py +6 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/rendering.py +18 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/request_build.py +83 -13
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/request_models.py +35 -0
- delegate_agent_cli-0.24.0/src/delegate_agent/resume_command.py +861 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/run_metadata.py +3 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/run_registry.py +303 -30
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/run_status.py +9 -4
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/runner.py +63 -7
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/snapshot_view.py +2 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/wait_cancel_commands.py +1 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/workflows/runtime.py +6 -2
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/worktree_execution.py +18 -2
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/worktree_gc.py +19 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/worktree_records.py +78 -7
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/worktree_remove.py +31 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent_cli.egg-info/PKG-INFO +9 -1
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent_cli.egg-info/SOURCES.txt +10 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_command_help.py +1 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_delegate_help_cli.py +1 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_delegate_parser.py +24 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_delegate_validation.py +17 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_inspection_commands.py +170 -1
- delegate_agent_cli-0.24.0/tests/test_resume_attachment.py +604 -0
- delegate_agent_cli-0.24.0/tests/test_resume_capture.py +186 -0
- delegate_agent_cli-0.24.0/tests/test_resume_inheritance.py +385 -0
- delegate_agent_cli-0.24.0/tests/test_resume_parser.py +54 -0
- delegate_agent_cli-0.24.0/tests/test_resume_projections.py +87 -0
- delegate_agent_cli-0.24.0/tests/test_resume_refusals.py +140 -0
- delegate_agent_cli-0.24.0/tests/test_resume_size_guard.py +151 -0
- delegate_agent_cli-0.24.0/tests/test_resume_stale.py +172 -0
- delegate_agent_cli-0.24.0/tests/test_resume_trust.py +301 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_retention.py +33 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_run_registry.py +164 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_runner_capture.py +80 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/CONTRIBUTING.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/LICENSE +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/MANIFEST.in +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/SECURITY.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/bin/delegate-profile-shim +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/bin/delegate.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/config.example.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/agent-setup.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/assets/delegate-agent-header.png +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/configuration.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/development.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/live-runtime.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/publishing-checklist.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/docs/troubleshooting.md +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/examples/task.claude.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/examples/task.codex.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/examples/task.cursor.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/examples/task.droid.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/examples/task.grok.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/examples/task.judge.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/examples/task.kimi.json +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/setup.cfg +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/archived_logs.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/argv_builders.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/argv_utils.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/bundled_models.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/capability_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/child_failures.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/command_errors.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/config.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/config_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/constants.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/describe_payload.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/errors.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/git_utils.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/harness_discovery.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/harness_events.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/json_types.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/log_output.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/model_discovery.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/profile_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/profile_guard.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/profiles.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/prompt_instructions.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/reasoning.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/redaction.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/retention.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/run_output_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/safe_workspace.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/seatbelt.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/setup_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/structured_output.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/workflows/__init__.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/workflows/commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/workflows/registry.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/workflows/schema.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/workflows/script.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/worktree_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/worktree_mgmt.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/worktree_summary.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent/wsl.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent_cli.egg-info/dependency_links.txt +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent_cli.egg-info/entry_points.txt +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent_cli.egg-info/requires.txt +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/src/delegate_agent_cli.egg-info/top_level.txt +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_capability_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_child_failures.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_codex_pure_sandbox.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_codex_thread_resilience.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_config_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_delegate_isolation.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_end_to_end_tracking.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_engine_argv.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_execution_argv_and_prompt.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_execution_dry_run.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_execution_worktree_failure_cleanup.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_execution_worktree_preflight.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_execution_worktree_run.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_harness_discovery.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_harness_events.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_kimi_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_model_discovery.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_model_selection_wave1a.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_model_selection_wave1b.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_omp_read_only_behavior.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_packaging.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_profiles.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_pure_call.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_reasoning_capabilities.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_safe_workspace_isolation.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_setup_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_slash_passthrough.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_snapshot_redaction.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_snapshot_rendering.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_snapshot_run_output.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_snapshot_view.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_structured_output.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_tracked_timeout.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_utility_modules.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_wait_cancel_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_wave4_launch_features.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_workflow_commands.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_worktree_list_show.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_worktree_prune_gc.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_worktree_remove.py +0 -0
- {delegate_agent_cli-0.22.0 → delegate_agent_cli-0.24.0}/tests/test_wsl_guardrails.py +0 -0
|
@@ -5,6 +5,30 @@ 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.24.0] - 2026-07-31
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added `delegate resume` for relaunching terminal Runs with a bounded,
|
|
13
|
+
untrusted continuation built from the original prompt and prior result.
|
|
14
|
+
Resume preserves compatible launch settings, supports explicit cross-engine
|
|
15
|
+
resumes, and attaches to an existing persistent worktree with a live cleanup
|
|
16
|
+
lease rather than creating a second worktree.
|
|
17
|
+
- Added private `prompt.txt` capture for new tracked Runs so their original
|
|
18
|
+
prompts can be resumed without placing prompt text in the Manifest or
|
|
19
|
+
Snapshot. Legacy records without that capture fail closed with a clear
|
|
20
|
+
`resume_prompt_unavailable` error.
|
|
21
|
+
|
|
22
|
+
## [0.23.0] - 2026-07-30
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- 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.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- 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.
|
|
31
|
+
|
|
8
32
|
## [0.22.0] - 2026-07-26
|
|
9
33
|
|
|
10
34
|
### Changed
|
|
@@ -759,6 +783,8 @@ Usage-audit fix wave: 82 sessions and 1,241 delegate invocations from one week o
|
|
|
759
783
|
|
|
760
784
|
- Releases before 0.1.3 predate this changelog.
|
|
761
785
|
|
|
786
|
+
[0.24.0]: https://github.com/treygoff24/delegate-agent/compare/v0.23.0...v0.24.0
|
|
787
|
+
[0.23.0]: https://github.com/treygoff24/delegate-agent/compare/v0.22.0...v0.23.0
|
|
762
788
|
[0.22.0]: https://github.com/treygoff24/delegate-agent/compare/v0.21.0...v0.22.0
|
|
763
789
|
[0.21.0]: https://github.com/treygoff24/delegate-agent/compare/v0.20.0...v0.21.0
|
|
764
790
|
[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.24.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,8 @@ 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 resume <alias-or-runId> "Continue from the previous result and run the tests."
|
|
336
|
+
delegate runs prune --dry-run # preview GC of terminal run records older than 30 days
|
|
335
337
|
```
|
|
336
338
|
|
|
337
339
|
Aliases are always numbered (`codex-1`, `cursor-2`); a **bare harness name
|
|
@@ -340,6 +342,12 @@ newest codex run and `delegate run-output codex:glm` the newest matching
|
|
|
340
342
|
model. Envelopes echo `requestedHandle`/`resolvedHandle`/`resolutionKind` so you
|
|
341
343
|
can confirm which run you addressed.
|
|
342
344
|
|
|
345
|
+
`resume` creates a new Run from a terminal source Run. It carries forward the
|
|
346
|
+
source mode and compatible launch settings, places the prior prompt and bounded
|
|
347
|
+
result before your new instructions, and attaches to an existing persistent
|
|
348
|
+
worktree instead of creating another one. Use `--dry-run` to inspect the
|
|
349
|
+
resolved launch without creating a Run.
|
|
350
|
+
|
|
343
351
|
`run-output` defaults to the best available parent-facing output: a completion
|
|
344
352
|
report when present, a recovered final assistant message when possible, or
|
|
345
353
|
bounded stdout/stderr diagnostics. Use `--completion-report` when you want that
|
|
@@ -299,6 +299,8 @@ 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 resume <alias-or-runId> "Continue from the previous result and run the tests."
|
|
303
|
+
delegate runs prune --dry-run # preview GC of terminal run records older than 30 days
|
|
302
304
|
```
|
|
303
305
|
|
|
304
306
|
Aliases are always numbered (`codex-1`, `cursor-2`); a **bare harness name
|
|
@@ -307,6 +309,12 @@ newest codex run and `delegate run-output codex:glm` the newest matching
|
|
|
307
309
|
model. Envelopes echo `requestedHandle`/`resolvedHandle`/`resolutionKind` so you
|
|
308
310
|
can confirm which run you addressed.
|
|
309
311
|
|
|
312
|
+
`resume` creates a new Run from a terminal source Run. It carries forward the
|
|
313
|
+
source mode and compatible launch settings, places the prior prompt and bounded
|
|
314
|
+
result before your new instructions, and attaches to an existing persistent
|
|
315
|
+
worktree instead of creating another one. Use `--dry-run` to inspect the
|
|
316
|
+
resolved launch without creating a Run.
|
|
317
|
+
|
|
310
318
|
`run-output` defaults to the best available parent-facing output: a completion
|
|
311
319
|
report when present, a recovered final assistant message when possible, or
|
|
312
320
|
bounded stdout/stderr diagnostics. Use `--completion-report` when you want that
|
|
@@ -931,17 +931,57 @@ 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]
|
|
938
|
+
delegate resume [--engine ENGINE] [--model MODEL] [--reasoning-effort LEVEL] [--timeout SEC] [--dry-run] <handle> [extra instructions...]
|
|
937
939
|
delegate wait <handle>... [--latest HARNESS] [--group NAME] [--timeout SEC] [--interval SEC] [--completion-report]
|
|
938
940
|
delegate cancel <handle>...
|
|
939
941
|
```
|
|
940
942
|
|
|
943
|
+
`delegate resume` relaunches a terminal Run as a new Run. It accepts
|
|
944
|
+
`succeeded`, `failed`, `cancelled`, and stale Runs; an effectively running Run
|
|
945
|
+
is refused. A successful source requires extra instructions. The continuation
|
|
946
|
+
contains the original prompt, then a bounded prior-run Completion Report (or a
|
|
947
|
+
Snapshot digest), then the new instructions last. Prior-run content is framed
|
|
948
|
+
as untrusted data and is disclosed to the target Harness, including on a
|
|
949
|
+
cross-engine resume. Resume options must appear before the handle; trailing
|
|
950
|
+
tokens are continuation instructions.
|
|
951
|
+
|
|
952
|
+
The new Run inherits source settings according to this table. `--engine` and
|
|
953
|
+
the listed resume flags must precede the handle; `--group` and
|
|
954
|
+
`--auth-profile` are global flags and therefore precede `resume`. A persistent
|
|
955
|
+
worktree source is resumed by attaching to its existing worktree rather than
|
|
956
|
+
creating a second one. The attachment is a live lease: `worktree remove`,
|
|
957
|
+
`worktree prune`, and `worktree gc` refuse or skip the worktree while the
|
|
958
|
+
attached Run may still be active. `--dry-run` resolves the continuation without
|
|
959
|
+
creating a Run or writing a prompt record.
|
|
960
|
+
|
|
961
|
+
| Field | Source manifest key | Override flag | Absent or legacy behavior | Cross-engine rule |
|
|
962
|
+
| --- | --- | --- | --- | --- |
|
|
963
|
+
| Engine | `engine`, falling back to `harness` | `--engine` | A missing or unknown source engine refuses resume. | The selected engine becomes the target; engine-scoped fields below may drop. |
|
|
964
|
+
| Mode | `mode` | None; v1 does not override mode. | A missing or invalid mode refuses resume. | Retained unchanged. |
|
|
965
|
+
| Model selection | `modelAlias`, then `modelRequested`, `modelResolved`, then `model` | `--model` | No usable key uses the target engine configuration default and emits a note. | Source model selection drops; pass `--model` to pin a target model. |
|
|
966
|
+
| Reasoning effort | `requestedReasoningEffort`, then `resolvedReasoningEffort`, together with `reasoningEffortSource` | `--reasoning-effort` | Missing effort uses the target default and emits a note. A source value from configuration is re-resolved through target capability/configuration; only `cli` and `input-json` source intent is inherited directly. | Source effort drops with a note; an explicit override remains valid. |
|
|
967
|
+
| Fast tier | `requestedFast` | `--fast` or `--no-fast` | Omitted leaves fast unspecified. | Inherited only for a same-engine Codex resume. Other targets drop it; non-Codex targets emit a drop note when a source value is present. |
|
|
968
|
+
| Progress intent | `progressRequested` (`on`, `off`, or omitted) | `--progress` or `--no-progress` | Omitted uses target progress configuration and emits a note; only `on` and `off` are inherited. | Retained; progress intent is not engine-specific. |
|
|
969
|
+
| Timeout | `timeoutSeconds` | `--timeout` | Omitted uses the target timeout default and emits a note. A present value must be a positive integer (an integral JSON float is accepted). | Retained. |
|
|
970
|
+
| Output schema | Inline `outputSchema` text | `--output-schema PATH` or `--no-output-schema` | Omitted means no schema. Stored text is re-materialized privately only during normal launch. | Only Codex inherits inline schema text. Other engines soft-drop it with a note before output-schema validation. |
|
|
971
|
+
| OpenCode agent | `agent` | None | Omitted means no agent selection. | Inherited only for a same-engine OpenCode resume; otherwise dropped with a note. |
|
|
972
|
+
| Workspace cwd / execution cwd | `cwd`; persistent records also derive `executionCwd`, branch, and source Git root | None (`--cwd` selects the registry workspace and must match recorded `cwd`) | Missing `cwd` falls back to the selected registry workspace; missing persistent-worktree metadata causes attachment validation to refuse. | Retained as workspace context; an attach uses the validated existing worktree rather than copying `executionCwd` into a new worktree. |
|
|
973
|
+
| Isolation / lifecycle | `isolationMode`; persistent detection also reads `isolationLifecycle`, `preservedWorkspace`, `worktreeStatus`, and `worktreeAttachment` | None; `--isolation` is rejected for resume. | Missing ordinary `isolationMode` uses target isolation configuration and emits a note. | Retained. Persistent or attached sources become an `attached` execution lifecycle. |
|
|
974
|
+
| Group | `group` | Global `--group` | Omitted uses the ungrouped target default and emits a note. | Retained. |
|
|
975
|
+
| Auth profile | `authProfile` | Global `--auth-profile` | Omitted uses target profile detection/default and emits a note. | Retained. |
|
|
976
|
+
| Forbid commit | `commitPolicy.forbidCommit` when exactly `true` | None | Omitted or any other value leaves commit prohibition off. | Retained. |
|
|
977
|
+
| Include dirty | `includeDirty` | `--include-dirty` | Source and explicit values are creation-only and are dropped for ordinary resume with a note. | Retained only as a drop decision; on a persistent/attached source, explicit `--include-dirty` is rejected because attachment does not create or sync a worktree. |
|
|
978
|
+
|
|
941
979
|
`delegate runs` defaults to recent runs. `--active` preserves the legacy active view and includes both live `running` runs and `stale` runs. Use `--running` for only live tracked processes and `--stale` for runs recorded as running whose PID is missing or dead. `--active`, `--running`, `--stale`, and `--recent` are mutually exclusive. `--group NAME` filters by launch group and the runs table shows a `group` column when any visible run has one.
|
|
942
980
|
`delegate ps` is the shorter first-class form of `delegate runs --active` and
|
|
943
981
|
accepts the same harness, group, and limit selectors.
|
|
944
982
|
|
|
983
|
+
`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.
|
|
984
|
+
|
|
945
985
|
Run-scoped handles (`snapshot`, `run-output`, `wait`, and `cancel`)
|
|
946
986
|
resolve exact run IDs and numbered aliases first. A bare harness name such as
|
|
947
987
|
`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
|
```
|
|
@@ -200,6 +200,19 @@ Persistent worktree isolation is not a security sandbox. It does not prevent:
|
|
|
200
200
|
- Writes to absolute paths outside the worktree.
|
|
201
201
|
- Actions taken through authenticated tools, MCP servers, browser sessions, or external CLIs.
|
|
202
202
|
|
|
203
|
+
`delegate resume` reads the initial manifest and `prompt.txt` outside the Registry
|
|
204
|
+
lock with bounded, no-follow, single-link readers. It re-checks status and reads
|
|
205
|
+
the report or snapshot history inside the lock using those same readers.
|
|
206
|
+
Completion Reports are used only when the source Run is terminal under the lock;
|
|
207
|
+
otherwise resume falls back to an atomic Snapshot digest. Prompt and report text are untrusted data, not
|
|
208
|
+
Delegate instructions, and are disclosed to the target Harness as part of the
|
|
209
|
+
continuation. `prompt.txt` is verbatim, unredacted, child-tamperable, retained
|
|
210
|
+
until `delegate runs prune`, and an `--engine` override can disclose it to a
|
|
211
|
+
different provider. A persistent-worktree resume attaches to the existing path
|
|
212
|
+
by deriving and validating its Registry record; it does not weaken
|
|
213
|
+
safe/worktree path checks or create a replacement worktree when the original
|
|
214
|
+
has moved.
|
|
215
|
+
|
|
203
216
|
## Config and secret hygiene
|
|
204
217
|
|
|
205
218
|
- Keep real config in `~/.delegate/config.json` or a private `DELEGATE_CONFIG` path. Repository-local `.delegate/config.json` is not loaded implicitly.
|
|
@@ -83,6 +83,25 @@ Delegate also creates a local branch named like:
|
|
|
83
83
|
delegate/<label>-<short-run-id>
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
### Resume attachment
|
|
87
|
+
|
|
88
|
+
To continue a terminal Run that used a persistent worktree, use the Run handle
|
|
89
|
+
rather than launching a second persistent worktree:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
delegate resume <alias-or-runId> "Continue the implementation and run the tests."
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The resumed Run attaches to the existing execution path and records an
|
|
96
|
+
attachment lease. It does not create a new branch, copy dirty files, or derive
|
|
97
|
+
a second persistent-worktree record. The lease is released when the attached
|
|
98
|
+
Run reaches a terminal state. Worktree removal, pruning, and registry repair
|
|
99
|
+
refuse or skip a path with a live attached Run; inspect or wait for that Run
|
|
100
|
+
before cleanup. A missing, moved, symlinked, unregistered, or branch-mismatched
|
|
101
|
+
source worktree is refused rather than recreated implicitly. `--include-dirty`
|
|
102
|
+
is rejected on attached resume because it only controls creation-time
|
|
103
|
+
synchronization; ordinary resume drops the flag with a note.
|
|
104
|
+
|
|
86
105
|
## Preflight requirements
|
|
87
106
|
|
|
88
107
|
Persistent worktree work-mode runs require:
|
|
@@ -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.24.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"
|
|
@@ -23,6 +23,7 @@ from delegate_agent import (
|
|
|
23
23
|
profiles,
|
|
24
24
|
reasoning,
|
|
25
25
|
redaction,
|
|
26
|
+
resume_command,
|
|
26
27
|
run_metadata,
|
|
27
28
|
run_output_commands,
|
|
28
29
|
run_registry,
|
|
@@ -79,7 +80,7 @@ from delegate_agent.errors import (
|
|
|
79
80
|
EXIT_USAGE,
|
|
80
81
|
DelegateError,
|
|
81
82
|
)
|
|
82
|
-
from delegate_agent.git_utils import capture_git_metadata #
|
|
83
|
+
from delegate_agent.git_utils import capture_git_metadata # re-exported for tests
|
|
83
84
|
from delegate_agent.isolation import ( # noqa: F401 # re-exported for tests
|
|
84
85
|
IsolationContext,
|
|
85
86
|
build_isolation_context,
|
|
@@ -100,6 +101,7 @@ from delegate_agent.prompt_transport import ( # noqa: F401 # CURSOR_PROMPT_RED
|
|
|
100
101
|
)
|
|
101
102
|
from delegate_agent.request_build import ( # noqa: F401 # re-exported for tests / back-compat
|
|
102
103
|
CALL_TEMP_CWD_PLACEHOLDER,
|
|
104
|
+
INLINE_OUTPUT_SCHEMA_PLACEHOLDER,
|
|
103
105
|
RUN_INPUT_KEYS,
|
|
104
106
|
_load_input_json_object,
|
|
105
107
|
build_request,
|
|
@@ -306,16 +308,28 @@ def dry_run_payload(request: Request) -> JsonObject:
|
|
|
306
308
|
run_metadata.add_model_payload_fields(payload, request)
|
|
307
309
|
reasoning.add_reasoning_payload_fields(payload, request)
|
|
308
310
|
run_metadata.add_speed_payload_fields(payload, request)
|
|
311
|
+
if request.output_schema_text is not None:
|
|
312
|
+
payload["outputSchemaInline"] = True
|
|
313
|
+
payload["argv"] = [
|
|
314
|
+
"<inline output schema>" if value == INLINE_OUTPUT_SCHEMA_PLACEHOLDER else value
|
|
315
|
+
for value in payload["argv"]
|
|
316
|
+
]
|
|
309
317
|
if request.warnings:
|
|
310
318
|
payload["warnings"] = list(request.warnings)
|
|
311
319
|
if request.progress:
|
|
312
320
|
payload["progressRequested"] = True
|
|
321
|
+
if request.timeout is not None:
|
|
322
|
+
payload["timeoutSeconds"] = request.timeout
|
|
313
323
|
if request.forbid_commit:
|
|
314
324
|
payload["commitPolicy"] = {"forbidCommit": True}
|
|
315
325
|
if request.include_dirty:
|
|
316
326
|
payload["includeDirty"] = True
|
|
317
327
|
if request.group is not None:
|
|
318
328
|
payload["group"] = request.group
|
|
329
|
+
if request.agent is not None:
|
|
330
|
+
payload["agent"] = request.agent
|
|
331
|
+
if request.resumed_from is not None:
|
|
332
|
+
payload["resumedFrom"] = request.resumed_from
|
|
319
333
|
if request.auth_profile is not None:
|
|
320
334
|
payload["authProfile"] = request.auth_profile
|
|
321
335
|
if request.fallback_auth_profile is not None:
|
|
@@ -329,6 +343,8 @@ def dry_run_payload(request: Request) -> JsonObject:
|
|
|
329
343
|
# Keep the existing human-readable `isolation` note for legacy use.
|
|
330
344
|
if ctx.effective_isolation == "worktree" and ctx.isolation_lifecycle == "persistent":
|
|
331
345
|
payload["isolation"] = "worktree persistent"
|
|
346
|
+
elif ctx.effective_isolation == "worktree" and ctx.isolation_lifecycle == "attached":
|
|
347
|
+
payload["isolation"] = "worktree attached (resume)"
|
|
332
348
|
elif ctx.effective_isolation == "worktree":
|
|
333
349
|
payload["isolation"] = "worktree temporary"
|
|
334
350
|
elif ctx.effective_isolation == "none":
|
|
@@ -344,7 +360,7 @@ def dry_run_payload(request: Request) -> JsonObject:
|
|
|
344
360
|
# Only persistent worktree isolation has a planned Delegate-managed
|
|
345
361
|
# branch/path. Temporary safe-mode isolation is created ephemerally at
|
|
346
362
|
# execution time and must not claim a persistent worktree plan.
|
|
347
|
-
if ctx.isolation_lifecycle
|
|
363
|
+
if ctx.isolation_lifecycle in ("persistent", "attached"):
|
|
348
364
|
planned_cwd = ctx.planned_execution_cwd or "<planned-worktree-path>"
|
|
349
365
|
planned_branch = ctx.planned_branch or "<planned-branch>"
|
|
350
366
|
payload["plannedExecutionCwd"] = planned_cwd
|
|
@@ -356,7 +372,11 @@ def dry_run_payload(request: Request) -> JsonObject:
|
|
|
356
372
|
payload["plannedBranch"] = None
|
|
357
373
|
|
|
358
374
|
# Always emit isolatedWorkspace as explicit boolean (mirrors preservedWorkspace).
|
|
359
|
-
payload["isolatedWorkspace"] = ctx.isolation_lifecycle in (
|
|
375
|
+
payload["isolatedWorkspace"] = ctx.isolation_lifecycle in (
|
|
376
|
+
"temporary",
|
|
377
|
+
"persistent",
|
|
378
|
+
"attached",
|
|
379
|
+
)
|
|
360
380
|
else:
|
|
361
381
|
# Fallback when no isolation context is provided (e.g. direct build_request calls in tests).
|
|
362
382
|
# Use embedded-default logic: safe local harnesses -> worktree temporary, others -> none.
|
|
@@ -498,10 +518,11 @@ def make_run_context(
|
|
|
498
518
|
)
|
|
499
519
|
execution_cwd = request.workspace
|
|
500
520
|
# isolated_workspace must reflect the EFFECTIVE behavior, not the
|
|
501
|
-
# mere presence of an isolation_context object. Only "temporary"
|
|
502
|
-
# "persistent" lifecycle means a physically separate
|
|
521
|
+
# mere presence of an isolation_context object. Only "temporary",
|
|
522
|
+
# "persistent", or "attached" lifecycle means a physically separate
|
|
523
|
+
# execution workspace.
|
|
503
524
|
isolated_workspace = (
|
|
504
|
-
request.isolation_context.isolation_lifecycle in ("temporary", "persistent")
|
|
525
|
+
request.isolation_context.isolation_lifecycle in ("temporary", "persistent", "attached")
|
|
505
526
|
if request.isolation_context is not None
|
|
506
527
|
else False
|
|
507
528
|
)
|
|
@@ -575,6 +596,12 @@ def make_run_context(
|
|
|
575
596
|
call_read_only=request.call_read_only or request.pure,
|
|
576
597
|
pure=request.pure,
|
|
577
598
|
prompt_instruction_mode=request.prompt_instruction_mode,
|
|
599
|
+
source_prompt=request.source_prompt,
|
|
600
|
+
progress_requested=request.progress_requested,
|
|
601
|
+
timeout_seconds=request.timeout,
|
|
602
|
+
output_schema_text=request.output_schema_record_text,
|
|
603
|
+
agent=request.agent,
|
|
604
|
+
resumed_from=request.resumed_from,
|
|
578
605
|
)
|
|
579
606
|
|
|
580
607
|
|
|
@@ -626,6 +653,173 @@ def _preserve_call_artifacts(
|
|
|
626
653
|
)
|
|
627
654
|
|
|
628
655
|
|
|
656
|
+
def _execute_attached_worktree(
|
|
657
|
+
request: Request,
|
|
658
|
+
json_mode: bool,
|
|
659
|
+
*,
|
|
660
|
+
config: JsonObject,
|
|
661
|
+
config_source: str | None,
|
|
662
|
+
completion_report_mode: str,
|
|
663
|
+
source_workspace: ResolvedWorkspace,
|
|
664
|
+
stdout: TextIO,
|
|
665
|
+
stderr: TextIO,
|
|
666
|
+
) -> tuple[int, JsonObject | None]:
|
|
667
|
+
"""Launch a resumed child inside the source run's existing worktree.
|
|
668
|
+
|
|
669
|
+
Lease-by-derivation: the attachment is recorded in this run's manifest
|
|
670
|
+
(``worktreeAttachment``) and removal paths refuse while the run is
|
|
671
|
+
effectively running. No worktree record is derived for attached runs.
|
|
672
|
+
"""
|
|
673
|
+
from dataclasses import replace as dc_replace
|
|
674
|
+
|
|
675
|
+
iso = request.isolation_context
|
|
676
|
+
assert iso is not None and iso.isolation_lifecycle == "attached"
|
|
677
|
+
worktree_path = iso.planned_execution_cwd
|
|
678
|
+
if not worktree_path:
|
|
679
|
+
raise DelegateError("worktree_missing", "Attached execution has no worktree path.")
|
|
680
|
+
wt = Path(worktree_path)
|
|
681
|
+
if wt.is_symlink() or not wt.is_dir():
|
|
682
|
+
raise DelegateError(
|
|
683
|
+
"worktree_missing",
|
|
684
|
+
f"The source run's worktree path is no longer a directory: {worktree_path}",
|
|
685
|
+
)
|
|
686
|
+
|
|
687
|
+
head_probe = capture_git_metadata(worktree_path)
|
|
688
|
+
start_head_oid = head_probe[2]
|
|
689
|
+
if not start_head_oid:
|
|
690
|
+
raise DelegateError(
|
|
691
|
+
"worktree_missing",
|
|
692
|
+
f"Could not resolve HEAD in the attached worktree: {worktree_path}",
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
execution_request = worktree_execution._request_for_execution_workspace(request, worktree_path)
|
|
696
|
+
# Re-check the actual argv payload now that the worktree note (and any
|
|
697
|
+
# forbid-commit note) has been prepended.
|
|
698
|
+
resume_command.enforce_resume_prompt_size(
|
|
699
|
+
request.engine,
|
|
700
|
+
execution_request.argv[-1],
|
|
701
|
+
)
|
|
702
|
+
ensure_binary(
|
|
703
|
+
execution_request.argv,
|
|
704
|
+
engine=request.engine,
|
|
705
|
+
config_source=config_source,
|
|
706
|
+
env_overrides=request.env_overrides,
|
|
707
|
+
)
|
|
708
|
+
if request.engine == "codex":
|
|
709
|
+
profiles.preflight_codex_request(request, config.get("codex", {}))
|
|
710
|
+
|
|
711
|
+
registry_root = run_registry.ensure_registry(
|
|
712
|
+
Path(source_workspace.path),
|
|
713
|
+
workspace_kind=source_workspace.kind,
|
|
714
|
+
)
|
|
715
|
+
maybe_run_retention_pass(registry_root, config)
|
|
716
|
+
run_id, alias = run_registry.register_run(
|
|
717
|
+
registry_root,
|
|
718
|
+
harness=request.engine,
|
|
719
|
+
metadata={
|
|
720
|
+
"mode": request.mode,
|
|
721
|
+
"model": request.model,
|
|
722
|
+
"modelAlias": request.model_alias,
|
|
723
|
+
"modelResolved": request.model,
|
|
724
|
+
"group": request.group,
|
|
725
|
+
"workflowAgentKey": request.workflow_agent_key,
|
|
726
|
+
"cwd": source_workspace.path,
|
|
727
|
+
"worktreeAttachment": {
|
|
728
|
+
**(iso.attachment or {}),
|
|
729
|
+
"startHeadOid": start_head_oid,
|
|
730
|
+
},
|
|
731
|
+
},
|
|
732
|
+
)
|
|
733
|
+
ctx_runner = make_run_context(
|
|
734
|
+
registry_root,
|
|
735
|
+
request,
|
|
736
|
+
run_id=run_id,
|
|
737
|
+
alias=alias,
|
|
738
|
+
source_workspace=source_workspace,
|
|
739
|
+
)
|
|
740
|
+
attachment = {
|
|
741
|
+
**(iso.attachment or {}),
|
|
742
|
+
"startHeadOid": start_head_oid,
|
|
743
|
+
}
|
|
744
|
+
ctx_runner = dc_replace(
|
|
745
|
+
ctx_runner,
|
|
746
|
+
execution_cwd=worktree_path,
|
|
747
|
+
isolated_workspace=True,
|
|
748
|
+
branch=iso.planned_branch,
|
|
749
|
+
source_git_root=iso.source_git_root,
|
|
750
|
+
creation_context={"sourceHeadOid": start_head_oid},
|
|
751
|
+
worktree_attachment=attachment,
|
|
752
|
+
)
|
|
753
|
+
try:
|
|
754
|
+
resume_command.revalidate_attached_target(
|
|
755
|
+
registry_root, attachment, expected_branch=iso.planned_branch
|
|
756
|
+
)
|
|
757
|
+
except DelegateError as exc:
|
|
758
|
+
run_path = run_registry.run_directory(registry_root, run_id)
|
|
759
|
+
if ctx_runner.source_prompt is not None:
|
|
760
|
+
run_registry.write_private_text(
|
|
761
|
+
run_path / run_registry.PROMPT_TXT_FILE, ctx_runner.source_prompt
|
|
762
|
+
)
|
|
763
|
+
delegate_runner.write_manifest(
|
|
764
|
+
run_path,
|
|
765
|
+
delegate_runner.build_manifest(ctx_runner, execution_request.display_argv),
|
|
766
|
+
)
|
|
767
|
+
delegate_runner.write_state(
|
|
768
|
+
run_path,
|
|
769
|
+
delegate_runner.build_state(
|
|
770
|
+
ctx_runner,
|
|
771
|
+
status=run_registry.STATUS_FAILED,
|
|
772
|
+
exit_code=1,
|
|
773
|
+
extra={
|
|
774
|
+
"error": "worktree_missing",
|
|
775
|
+
"message": exc.message,
|
|
776
|
+
"failureReason": "worktree_missing",
|
|
777
|
+
},
|
|
778
|
+
),
|
|
779
|
+
)
|
|
780
|
+
raise DelegateError("worktree_missing", exc.message) from exc
|
|
781
|
+
execution_root = str(Path(worktree_path).resolve(strict=False))
|
|
782
|
+
source_root = str(Path(source_workspace.path).resolve(strict=False))
|
|
783
|
+
child_env = {
|
|
784
|
+
**(request.env_overrides or {}),
|
|
785
|
+
"DELEGATE_SOURCE_ROOT": source_root,
|
|
786
|
+
"DELEGATE_EXECUTION_ROOT": execution_root,
|
|
787
|
+
"WORKSPACE_ROOT": execution_root,
|
|
788
|
+
}
|
|
789
|
+
ctx_runner = dc_replace(
|
|
790
|
+
ctx_runner,
|
|
791
|
+
env_overrides=child_env,
|
|
792
|
+
fallback_env_overrides=profiles.codex_fallback_child_env_overrides(
|
|
793
|
+
request.profile_resolution,
|
|
794
|
+
child_env,
|
|
795
|
+
),
|
|
796
|
+
)
|
|
797
|
+
try:
|
|
798
|
+
return delegate_runner.execute_tracked(
|
|
799
|
+
execution_request.argv,
|
|
800
|
+
worktree_path,
|
|
801
|
+
ctx_runner,
|
|
802
|
+
json_mode=json_mode,
|
|
803
|
+
stdout=stdout,
|
|
804
|
+
stderr=stderr,
|
|
805
|
+
completion_report_mode=completion_report_mode,
|
|
806
|
+
stdin_text=execution_request.stdin_text,
|
|
807
|
+
prompt_file_text=execution_request.prompt_file_text,
|
|
808
|
+
prompt_file_placeholder=PROMPT_FILE_ARG_PLACEHOLDER,
|
|
809
|
+
agent_config_text=execution_request.agent_config_text,
|
|
810
|
+
agent_config_placeholder=DEVIN_AGENT_CONFIG_ARG_PLACEHOLDER,
|
|
811
|
+
output_schema_text=request.output_schema_text,
|
|
812
|
+
output_schema_path=request.output_schema,
|
|
813
|
+
manifest_argv=execution_request.display_argv,
|
|
814
|
+
progress=request.progress,
|
|
815
|
+
progress_initial_delay_sec=request.progress_initial_delay_sec,
|
|
816
|
+
progress_interval_sec=request.progress_interval_sec,
|
|
817
|
+
timeout=request.timeout,
|
|
818
|
+
)
|
|
819
|
+
except delegate_runner.RunnerLaunchError as exc:
|
|
820
|
+
raise DelegateError(exc.error, exc.message, exc.exit_code) from exc
|
|
821
|
+
|
|
822
|
+
|
|
629
823
|
def execute_request(
|
|
630
824
|
request: Request,
|
|
631
825
|
json_mode: bool,
|
|
@@ -849,6 +1043,21 @@ def execute_request(
|
|
|
849
1043
|
profiles.preflight_codex_request(request, config.get("codex", {}))
|
|
850
1044
|
ctx = request.isolation_context
|
|
851
1045
|
|
|
1046
|
+
# Attached resume runs execute inside an existing persistent worktree:
|
|
1047
|
+
# never plan, create, or sync a worktree — short-circuit before the
|
|
1048
|
+
# persistent branch.
|
|
1049
|
+
if ctx is not None and ctx.isolation_lifecycle == "attached":
|
|
1050
|
+
return _execute_attached_worktree(
|
|
1051
|
+
request,
|
|
1052
|
+
json_mode,
|
|
1053
|
+
config=config,
|
|
1054
|
+
config_source=config_source,
|
|
1055
|
+
completion_report_mode=completion_report_mode,
|
|
1056
|
+
source_workspace=source_workspace,
|
|
1057
|
+
stdout=stdout,
|
|
1058
|
+
stderr=stderr,
|
|
1059
|
+
)
|
|
1060
|
+
|
|
852
1061
|
# Persistent worktree runs (work + worktree) hand off to worktree_execution.
|
|
853
1062
|
if ctx is not None and ctx.isolation_lifecycle == "persistent":
|
|
854
1063
|
try:
|
|
@@ -875,6 +1084,10 @@ def execute_request(
|
|
|
875
1084
|
|
|
876
1085
|
with safe_isolated_request(request) as isolated_request:
|
|
877
1086
|
_set_child_root_env(isolated_request, source_workspace)
|
|
1087
|
+
if isolated_request.resumed_from is not None and isolated_request.argv:
|
|
1088
|
+
resume_command.enforce_resume_prompt_size(
|
|
1089
|
+
isolated_request.engine, isolated_request.argv[-1]
|
|
1090
|
+
)
|
|
878
1091
|
ensure_binary(
|
|
879
1092
|
isolated_request.argv,
|
|
880
1093
|
engine=isolated_request.engine,
|
|
@@ -1180,7 +1393,12 @@ def main(
|
|
|
1180
1393
|
"workflow",
|
|
1181
1394
|
}:
|
|
1182
1395
|
existing_registry = run_registry.registry_root_if_exists(Path(workspace.path))
|
|
1183
|
-
|
|
1396
|
+
pruning_runs = (
|
|
1397
|
+
parsed.subcommand == "runs"
|
|
1398
|
+
and parsed.runs is not None
|
|
1399
|
+
and parsed.runs.action == "prune"
|
|
1400
|
+
)
|
|
1401
|
+
if existing_registry is not None and not pruning_runs:
|
|
1184
1402
|
maybe_run_retention_pass(existing_registry, config)
|
|
1185
1403
|
if parsed.subcommand == "snapshot":
|
|
1186
1404
|
return emit_snapshot(parsed, workspace, stdout)
|
|
@@ -1200,7 +1418,16 @@ def main(
|
|
|
1200
1418
|
if parsed.subcommand == "profiles":
|
|
1201
1419
|
return emit_profiles_command(parsed, config, source, stdout)
|
|
1202
1420
|
|
|
1421
|
+
resume_plan: resume_command.ResumePlan | None = None
|
|
1422
|
+
if parsed.subcommand == "resume":
|
|
1423
|
+
resume_plan = resume_command.build_resume_plan(parsed, workspace, config, stderr=stderr)
|
|
1424
|
+
# The plan is a fully ordinary launch; from here on the resume flows
|
|
1425
|
+
# through the normal request build and execution path.
|
|
1426
|
+
parsed = resume_plan.parsed
|
|
1427
|
+
global_options = parsed.global_options
|
|
1203
1428
|
request = request_from_parsed(parsed, config, stdin)
|
|
1429
|
+
if resume_plan is not None:
|
|
1430
|
+
request = resume_command.apply_resume_to_request(request, resume_plan)
|
|
1204
1431
|
if request.dry_run:
|
|
1205
1432
|
payload = dry_run_payload(request)
|
|
1206
1433
|
if global_options.json_mode:
|