agentic-dev-loop 1.0.0a26__tar.gz → 1.0.0a27__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.
Potentially problematic release.
This version of agentic-dev-loop might be problematic. Click here for more details.
- {agentic_dev_loop-1.0.0a26/src/agentic_dev_loop.egg-info → agentic_dev_loop-1.0.0a27}/PKG-INFO +17 -3
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/README.md +16 -2
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/pyproject.toml +1 -1
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/proc.py +7 -35
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27/src/agentic_dev_loop.egg-info}/PKG-INFO +17 -3
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_actions.py +2 -3
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_proc.py +7 -41
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_stages.py +2 -2
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_sync_back.py +3 -3
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_trigger_script.py +4 -21
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/LICENSE +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/setup.cfg +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/core/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/core/config.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/core/paths.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/core/results.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/core/verdict.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/actions.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/agents.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/cli.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/deps.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/dryrun.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/egress_policy.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/egress_proxy.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/extensions/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/extensions/aidlc.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/graph.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/hostboundary.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/isolation.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/llm.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/loaders.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/mounts.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/outputs.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/presets.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/registry.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/seccomp/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/seccomp/chromium-userns.json +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/secrets.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/stages.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/step_workspace.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/sync_back.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/py.typed +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/viz/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/viz/__main__.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/viz/server.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop.egg-info/SOURCES.txt +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop.egg-info/dependency_links.txt +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop.egg-info/entry_points.txt +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop.egg-info/requires.txt +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop.egg-info/top_level.txt +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_028_declared_caches.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_029_merge_on_conflict.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_agents.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_aidlc.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_cli.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_config.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_deps.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_dry_run.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_e2e_fixtures.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_egress_proxy.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_graph.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_hostboundary.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_hostboundary_integration.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_isolation.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_isolation_integration.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_isolation_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_llm.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_loaders.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_module_contract.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_outputs.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_outputs_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_publish.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_qa_prompt.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_registry.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_repo_ascii.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_results.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_sdk_compat.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_secrets.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_secrets_integration.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_secrets_pipeline.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_source_resolution.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_step_workspace.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_unit5_config.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_unit5_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_unit5_pure.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_verdict.py +0 -0
- {agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_viz.py +0 -0
{agentic_dev_loop-1.0.0a26/src/agentic_dev_loop.egg-info → agentic_dev_loop-1.0.0a27}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-dev-loop
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.0a27
|
|
4
4
|
Summary: Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase.
|
|
5
5
|
Author: Luke Wilson
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -84,6 +84,20 @@ timeout (agent runs are long), and fail fast on a broken sandbox - daemon-side
|
|
|
84
84
|
exec failures are classified and stop the run without an agent retry loop,
|
|
85
85
|
while a startup reaper reclaims containers leaked by a crashed run.
|
|
86
86
|
|
|
87
|
+
## Supported platforms
|
|
88
|
+
|
|
89
|
+
The engine is plain Linux under the hood and runs wherever a compliant
|
|
90
|
+
Docker engine does:
|
|
91
|
+
|
|
92
|
+
| Platform | Support |
|
|
93
|
+
| --- | --- |
|
|
94
|
+
| **Linux** | Native. Docker Engine, OrbStack, Colima, or podman with docker compat. |
|
|
95
|
+
| **macOS** | Native. Docker Desktop, OrbStack, or Colima. |
|
|
96
|
+
| **Windows** | Via **WSL2** (Ubuntu distro). Enable Docker Desktop's WSL integration (or run Docker Engine inside the distro) and keep the repo on the WSL filesystem (`~/dev/...`), not `/mnt/c` - bind-mounting a 9p path into containers breaks permissions and is slow. |
|
|
97
|
+
|
|
98
|
+
Native Windows (outside WSL2) is not supported: every Windows-specific code
|
|
99
|
+
path and test was removed, and CI runs on Ubuntu only.
|
|
100
|
+
|
|
87
101
|
## Installation
|
|
88
102
|
|
|
89
103
|
**Prerequisites**
|
|
@@ -91,7 +105,7 @@ while a startup reaper reclaims containers leaked by a crashed run.
|
|
|
91
105
|
| Requirement | Detail |
|
|
92
106
|
| --- | --- |
|
|
93
107
|
| Python | ≥ 3.12 |
|
|
94
|
-
| Docker engine | Engine API ≥ 1.43 (Engine 24). Any compliant engine works - Docker Desktop, OrbStack, Colima, Rancher Desktop, podman docker-compat. On Windows,
|
|
108
|
+
| Docker engine | Engine API ≥ 1.43 (Engine 24). Any compliant engine works - Docker Desktop, OrbStack, Colima, Rancher Desktop, podman docker-compat. On Windows, run under WSL2: the repo must live on the WSL filesystem, not /mnt/c. |
|
|
95
109
|
| LLM API key | The env var named by your pipeline's `api_key_env` (e.g. `OPENAI_API_KEY`) must be set - a missing key fails fast, naming it. |
|
|
96
110
|
|
|
97
111
|
```bash
|
|
@@ -579,7 +593,7 @@ agentic-dev-loop agentic-dev-loop/pipeline.yaml --dry-run # run the shipped pi
|
|
|
579
593
|
- The shipped pipeline (`agentic-dev-loop/pipeline.yaml`) **dogfoods the tool on
|
|
580
594
|
its own repo** - dev → test → review → qa → commit, with the engine's own
|
|
581
595
|
three agent definitions in `sdk_agents/`.
|
|
582
|
-
- CI: `ci.yml` (unit + integration suite, ubuntu
|
|
596
|
+
- CI: `ci.yml` (unit + integration suite, ubuntu),
|
|
583
597
|
`publish-image.yml` (multi-arch dev image, amd64 + arm64), `release.yml`
|
|
584
598
|
(PyPI publishing).
|
|
585
599
|
|
|
@@ -42,6 +42,20 @@ timeout (agent runs are long), and fail fast on a broken sandbox - daemon-side
|
|
|
42
42
|
exec failures are classified and stop the run without an agent retry loop,
|
|
43
43
|
while a startup reaper reclaims containers leaked by a crashed run.
|
|
44
44
|
|
|
45
|
+
## Supported platforms
|
|
46
|
+
|
|
47
|
+
The engine is plain Linux under the hood and runs wherever a compliant
|
|
48
|
+
Docker engine does:
|
|
49
|
+
|
|
50
|
+
| Platform | Support |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| **Linux** | Native. Docker Engine, OrbStack, Colima, or podman with docker compat. |
|
|
53
|
+
| **macOS** | Native. Docker Desktop, OrbStack, or Colima. |
|
|
54
|
+
| **Windows** | Via **WSL2** (Ubuntu distro). Enable Docker Desktop's WSL integration (or run Docker Engine inside the distro) and keep the repo on the WSL filesystem (`~/dev/...`), not `/mnt/c` - bind-mounting a 9p path into containers breaks permissions and is slow. |
|
|
55
|
+
|
|
56
|
+
Native Windows (outside WSL2) is not supported: every Windows-specific code
|
|
57
|
+
path and test was removed, and CI runs on Ubuntu only.
|
|
58
|
+
|
|
45
59
|
## Installation
|
|
46
60
|
|
|
47
61
|
**Prerequisites**
|
|
@@ -49,7 +63,7 @@ while a startup reaper reclaims containers leaked by a crashed run.
|
|
|
49
63
|
| Requirement | Detail |
|
|
50
64
|
| --- | --- |
|
|
51
65
|
| Python | ≥ 3.12 |
|
|
52
|
-
| Docker engine | Engine API ≥ 1.43 (Engine 24). Any compliant engine works - Docker Desktop, OrbStack, Colima, Rancher Desktop, podman docker-compat. On Windows,
|
|
66
|
+
| Docker engine | Engine API ≥ 1.43 (Engine 24). Any compliant engine works - Docker Desktop, OrbStack, Colima, Rancher Desktop, podman docker-compat. On Windows, run under WSL2: the repo must live on the WSL filesystem, not /mnt/c. |
|
|
53
67
|
| LLM API key | The env var named by your pipeline's `api_key_env` (e.g. `OPENAI_API_KEY`) must be set - a missing key fails fast, naming it. |
|
|
54
68
|
|
|
55
69
|
```bash
|
|
@@ -537,7 +551,7 @@ agentic-dev-loop agentic-dev-loop/pipeline.yaml --dry-run # run the shipped pi
|
|
|
537
551
|
- The shipped pipeline (`agentic-dev-loop/pipeline.yaml`) **dogfoods the tool on
|
|
538
552
|
its own repo** - dev → test → review → qa → commit, with the engine's own
|
|
539
553
|
three agent definitions in `sdk_agents/`.
|
|
540
|
-
- CI: `ci.yml` (unit + integration suite, ubuntu
|
|
554
|
+
- CI: `ci.yml` (unit + integration suite, ubuntu),
|
|
541
555
|
`publish-image.yml` (multi-arch dev image, amd64 + arm64), `release.yml`
|
|
542
556
|
(PyPI publishing).
|
|
543
557
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentic-dev-loop"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.0a27"
|
|
8
8
|
description = "Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -9,9 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
import os
|
|
11
11
|
import shlex
|
|
12
|
-
import shutil
|
|
13
12
|
import signal
|
|
14
|
-
import subprocess
|
|
15
13
|
from collections.abc import Mapping
|
|
16
14
|
|
|
17
15
|
_SHELL_METACHARS = frozenset("&|;><$`~*?[]")
|
|
@@ -33,47 +31,21 @@ def split_command(command: str) -> list[str]:
|
|
|
33
31
|
return shlex.split(command)
|
|
34
32
|
|
|
35
33
|
|
|
36
|
-
def host_shell_execution(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
POSIX: the raw string with ``shell=True`` (unchanged unit-2 behaviour).
|
|
42
|
-
Windows: ``shell=True`` is cmd.exe, which mangles ``$VAR`` expansion and
|
|
43
|
-
``|`` pipelines (the CI-red hybrid failures) - prefer the discovered
|
|
44
|
-
POSIX ``sh`` (git-bash) via argv instead; fall back to ``shell=True``
|
|
45
|
-
only when no ``sh`` exists anywhere on PATH.
|
|
46
|
-
"""
|
|
47
|
-
if not nt:
|
|
48
|
-
return command, True
|
|
49
|
-
sh = which("sh")
|
|
50
|
-
if sh:
|
|
51
|
-
return [sh, "-c", command], False
|
|
34
|
+
def host_shell_execution(command: str) -> tuple[str, bool]:
|
|
35
|
+
"""How the HOST (non-sandbox) path executes a shell-needing command:
|
|
36
|
+
the raw string with ``shell=True``. The engine targets Linux and WSL2
|
|
37
|
+
(which is plain Linux), so ``sh`` is always present."""
|
|
52
38
|
return command, True
|
|
53
39
|
|
|
54
40
|
|
|
55
|
-
def kill_process_tree(proc
|
|
56
|
-
run=subprocess.run) -> None:
|
|
41
|
+
def kill_process_tree(proc) -> None:
|
|
57
42
|
"""Terminate `proc` and its descendants after a timeout.
|
|
58
43
|
|
|
59
|
-
|
|
44
|
+
``start_new_session`` made ``proc.pid`` the process-group id, so
|
|
60
45
|
``killpg`` reaps the whole group (a shell wrapper's children survive a
|
|
61
46
|
plain ``kill``).
|
|
62
|
-
|
|
63
|
-
Windows: ``proc.kill()`` terminates only the direct child - a git-bash
|
|
64
|
-
``sh -c`` wrapper's python child survives and keeps the pipes open, so
|
|
65
|
-
the follow-up ``communicate()`` blocks out the child's full lifetime.
|
|
66
|
-
``taskkill /T`` walks the process tree while the parent is still alive,
|
|
67
|
-
then ``kill`` sweeps up anything left (CI-red: 9.5s timeout test).
|
|
68
47
|
"""
|
|
69
|
-
|
|
70
|
-
nt = os.name == "nt"
|
|
71
|
-
if nt:
|
|
72
|
-
run(["taskkill", "/F", "/T", "/PID", str(proc.pid)],
|
|
73
|
-
capture_output=True, check=False)
|
|
74
|
-
proc.kill()
|
|
75
|
-
else:
|
|
76
|
-
os.killpg(proc.pid, signal.SIGKILL)
|
|
48
|
+
os.killpg(proc.pid, signal.SIGKILL)
|
|
77
49
|
|
|
78
50
|
|
|
79
51
|
def is_pid_token(token: str) -> bool:
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27/src/agentic_dev_loop.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-dev-loop
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.0a27
|
|
4
4
|
Summary: Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase.
|
|
5
5
|
Author: Luke Wilson
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -84,6 +84,20 @@ timeout (agent runs are long), and fail fast on a broken sandbox - daemon-side
|
|
|
84
84
|
exec failures are classified and stop the run without an agent retry loop,
|
|
85
85
|
while a startup reaper reclaims containers leaked by a crashed run.
|
|
86
86
|
|
|
87
|
+
## Supported platforms
|
|
88
|
+
|
|
89
|
+
The engine is plain Linux under the hood and runs wherever a compliant
|
|
90
|
+
Docker engine does:
|
|
91
|
+
|
|
92
|
+
| Platform | Support |
|
|
93
|
+
| --- | --- |
|
|
94
|
+
| **Linux** | Native. Docker Engine, OrbStack, Colima, or podman with docker compat. |
|
|
95
|
+
| **macOS** | Native. Docker Desktop, OrbStack, or Colima. |
|
|
96
|
+
| **Windows** | Via **WSL2** (Ubuntu distro). Enable Docker Desktop's WSL integration (or run Docker Engine inside the distro) and keep the repo on the WSL filesystem (`~/dev/...`), not `/mnt/c` - bind-mounting a 9p path into containers breaks permissions and is slow. |
|
|
97
|
+
|
|
98
|
+
Native Windows (outside WSL2) is not supported: every Windows-specific code
|
|
99
|
+
path and test was removed, and CI runs on Ubuntu only.
|
|
100
|
+
|
|
87
101
|
## Installation
|
|
88
102
|
|
|
89
103
|
**Prerequisites**
|
|
@@ -91,7 +105,7 @@ while a startup reaper reclaims containers leaked by a crashed run.
|
|
|
91
105
|
| Requirement | Detail |
|
|
92
106
|
| --- | --- |
|
|
93
107
|
| Python | ≥ 3.12 |
|
|
94
|
-
| Docker engine | Engine API ≥ 1.43 (Engine 24). Any compliant engine works - Docker Desktop, OrbStack, Colima, Rancher Desktop, podman docker-compat. On Windows,
|
|
108
|
+
| Docker engine | Engine API ≥ 1.43 (Engine 24). Any compliant engine works - Docker Desktop, OrbStack, Colima, Rancher Desktop, podman docker-compat. On Windows, run under WSL2: the repo must live on the WSL filesystem, not /mnt/c. |
|
|
95
109
|
| LLM API key | The env var named by your pipeline's `api_key_env` (e.g. `OPENAI_API_KEY`) must be set - a missing key fails fast, naming it. |
|
|
96
110
|
|
|
97
111
|
```bash
|
|
@@ -579,7 +593,7 @@ agentic-dev-loop agentic-dev-loop/pipeline.yaml --dry-run # run the shipped pi
|
|
|
579
593
|
- The shipped pipeline (`agentic-dev-loop/pipeline.yaml`) **dogfoods the tool on
|
|
580
594
|
its own repo** - dev → test → review → qa → commit, with the engine's own
|
|
581
595
|
three agent definitions in `sdk_agents/`.
|
|
582
|
-
- CI: `ci.yml` (unit + integration suite, ubuntu
|
|
596
|
+
- CI: `ci.yml` (unit + integration suite, ubuntu),
|
|
583
597
|
`publish-image.yml` (multi-arch dev image, amd64 + arm64), `release.yml`
|
|
584
598
|
(PyPI publishing).
|
|
585
599
|
|
|
@@ -375,9 +375,8 @@ class TestCommitNode:
|
|
|
375
375
|
|
|
376
376
|
def test_add_excludes_live_checkpoint_db(self, tmp_path, monkeypatch):
|
|
377
377
|
"""The live checkpointer DB under state_dir stays open for the whole
|
|
378
|
-
run
|
|
379
|
-
|
|
380
|
-
exclude sqlite files under the state dir on every OS."""
|
|
378
|
+
run, so `git add -A` cannot hash it. The add must exclude sqlite
|
|
379
|
+
files under the state dir."""
|
|
381
380
|
repo = tmp_path / "repo"
|
|
382
381
|
init_git_repo(repo)
|
|
383
382
|
(repo / "feature.cs").write_text("// constructed by the pipeline")
|
|
@@ -5,11 +5,8 @@ stateless pure functions shared by the command-step and action-step
|
|
|
5
5
|
surfaces; property tests exercise the invariants that keep the subprocess
|
|
6
6
|
boundary fail-safe (BR-4, BR-5)."""
|
|
7
7
|
|
|
8
|
-
import os
|
|
9
|
-
import pytest
|
|
10
8
|
import signal
|
|
11
9
|
import string
|
|
12
|
-
import subprocess
|
|
13
10
|
|
|
14
11
|
from hypothesis import given, settings
|
|
15
12
|
from hypothesis import strategies as st
|
|
@@ -45,23 +42,10 @@ class TestNeedsShell:
|
|
|
45
42
|
|
|
46
43
|
|
|
47
44
|
class TestHostShellExecution:
|
|
48
|
-
"""How the HOST (non-sandbox) path executes a shell-needing command.
|
|
49
|
-
Windows cannot rely on shell=True - cmd.exe mangles $VAR and pipelines
|
|
50
|
-
(the CI-red hybrid failures) - so it prefers the discovered POSIX sh."""
|
|
45
|
+
"""How the HOST (non-sandbox) path executes a shell-needing command."""
|
|
51
46
|
|
|
52
|
-
def
|
|
53
|
-
argv, shell = host_shell_execution("a && b"
|
|
54
|
-
assert (argv, shell) == ("a && b", True)
|
|
55
|
-
|
|
56
|
-
def test_windows_prefers_discovered_sh(self):
|
|
57
|
-
which = lambda name: "C:/Program Files/Git/bin/sh.exe" # noqa: E731
|
|
58
|
-
argv, shell = host_shell_execution("a && b", nt=True, which=which)
|
|
59
|
-
assert argv == ["C:/Program Files/Git/bin/sh.exe", "-c", "a && b"]
|
|
60
|
-
assert shell is False
|
|
61
|
-
|
|
62
|
-
def test_windows_without_sh_falls_back_to_shell_true(self):
|
|
63
|
-
argv, shell = host_shell_execution("a && b", nt=True,
|
|
64
|
-
which=lambda name: None)
|
|
47
|
+
def test_uses_shell_true(self):
|
|
48
|
+
argv, shell = host_shell_execution("a && b")
|
|
65
49
|
assert (argv, shell) == ("a && b", True)
|
|
66
50
|
|
|
67
51
|
|
|
@@ -144,10 +128,8 @@ class TestChildEnv:
|
|
|
144
128
|
|
|
145
129
|
|
|
146
130
|
class TestKillProcessTree:
|
|
147
|
-
"""The timeout reap path
|
|
148
|
-
|
|
149
|
-
survives, keeps the pipes open, and the follow-up communicate() blocks
|
|
150
|
-
out the full sleep. The tree must be reaped root-to-leaves."""
|
|
131
|
+
"""The timeout reap path: ``start_new_session`` made ``proc.pid`` the
|
|
132
|
+
process-group id, so ``killpg`` reaps the whole tree."""
|
|
151
133
|
|
|
152
134
|
class _Proc:
|
|
153
135
|
def __init__(self, log):
|
|
@@ -157,30 +139,14 @@ class TestKillProcessTree:
|
|
|
157
139
|
def kill(self):
|
|
158
140
|
self.log.append("kill")
|
|
159
141
|
|
|
160
|
-
|
|
161
|
-
def test_posix_reaps_the_whole_process_group(self, monkeypatch):
|
|
142
|
+
def test_reaps_the_whole_process_group(self, monkeypatch):
|
|
162
143
|
killed = []
|
|
163
144
|
monkeypatch.setattr(
|
|
164
145
|
"agentic_dev_loop.engine.proc.os.killpg",
|
|
165
146
|
lambda pid, sig: killed.append((pid, sig)))
|
|
166
147
|
proc = self._Proc([])
|
|
167
148
|
|
|
168
|
-
kill_process_tree(proc
|
|
149
|
+
kill_process_tree(proc)
|
|
169
150
|
|
|
170
151
|
assert killed == [(99, signal.SIGKILL)]
|
|
171
152
|
assert proc.log == [] # the wrapper needs no separate kill
|
|
172
|
-
|
|
173
|
-
def test_windows_taskkills_the_tree_then_kills_the_wrapper(self):
|
|
174
|
-
log = []
|
|
175
|
-
proc = self._Proc(log)
|
|
176
|
-
|
|
177
|
-
def fake_run(argv, **kwargs):
|
|
178
|
-
log.append("taskkill")
|
|
179
|
-
assert argv == ["taskkill", "/F", "/T", "/PID", "99"]
|
|
180
|
-
return subprocess.CompletedProcess(argv, 0, "", "")
|
|
181
|
-
|
|
182
|
-
kill_process_tree(proc, nt=True, run=fake_run)
|
|
183
|
-
|
|
184
|
-
# taskkill /T needs the parent alive to walk the tree - then the
|
|
185
|
-
# wrapper itself is swept up.
|
|
186
|
-
assert log == ["taskkill", "kill"]
|
|
@@ -393,8 +393,8 @@ class TestCommandNode:
|
|
|
393
393
|
"""The host-path timeout must cut the WHOLE tree short, not just the
|
|
394
394
|
direct child - a shell wrapper's grandchild that survives keeps the
|
|
395
395
|
pipes open and the follow-up communicate() blocks out the full sleep
|
|
396
|
-
(CI-red 9.5s). kill_process_tree
|
|
397
|
-
|
|
396
|
+
(CI-red 9.5s). kill_process_tree is unit-pinned in
|
|
397
|
+
tests/test_proc.py::TestKillProcessTree."""
|
|
398
398
|
code, out, timed_out = _run_command(
|
|
399
399
|
f'"{sys.executable}" -c "import time; time.sleep(30)"',
|
|
400
400
|
tmp_path, 0.2)
|
|
@@ -338,9 +338,9 @@ class TestMergeOnConflictPartition:
|
|
|
338
338
|
exp = _export(tmp_path, ws)
|
|
339
339
|
(ws / "src" / "audit.md").write_text("base\n")
|
|
340
340
|
(exp / "src" / "audit.md").write_text("base\nexport\n")
|
|
341
|
-
# Baseline comes from the real workspace bytes
|
|
342
|
-
#
|
|
343
|
-
#
|
|
341
|
+
# Baseline comes from the real workspace bytes, so a fabricated
|
|
342
|
+
# sha256(b"base\n") would never match and would misclassify the
|
|
343
|
+
# copy as a merge conflict.
|
|
344
344
|
baseline = {"src/audit.md": _digest(ws / "src" / "audit.md")}
|
|
345
345
|
report = sync_back(exp, ws, ["src"], baseline=baseline,
|
|
346
346
|
merge_on_conflict=["src/audit.md"])
|
|
@@ -6,11 +6,7 @@ a stale install rejects newer pipeline configs at load time (e.g.
|
|
|
6
6
|
is upgraded on every run. Tests drive the real script with stub
|
|
7
7
|
executables on PATH - no network, no mocks of the script's logic.
|
|
8
8
|
|
|
9
|
-
The script is bash, so it is executed through `bash
|
|
10
|
-
Windows cannot CreateProcess a `.sh` file (shebangs are a POSIX concept)
|
|
11
|
-
and its MSYS bash (git-bash, preinstalled on windows-latest runners)
|
|
12
|
-
understands only POSIX-style paths (`/c/...`), so PATH entries and
|
|
13
|
-
redirect targets inside stub bodies are converted accordingly.
|
|
9
|
+
The script is bash, so it is executed through `bash`.
|
|
14
10
|
"""
|
|
15
11
|
|
|
16
12
|
import os
|
|
@@ -24,19 +20,6 @@ REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
|
24
20
|
SCRIPT = REPO_ROOT / "trigger-agentic-dev-loop.sh"
|
|
25
21
|
|
|
26
22
|
|
|
27
|
-
def _msys(path: Path) -> str:
|
|
28
|
-
"""POSIX-style form of a Windows path (`C:\\x` -> `/c/x`).
|
|
29
|
-
|
|
30
|
-
MSYS bash splits PATH on `:` and treats backslashes as escapes, so a
|
|
31
|
-
native `C:\\...` entry would fragment into `C` + `\\...`. Pass the
|
|
32
|
-
mount-style form instead. On POSIX the path is returned unchanged.
|
|
33
|
-
"""
|
|
34
|
-
if os.name != "nt":
|
|
35
|
-
return str(path)
|
|
36
|
-
drive, rest = os.path.splitdrive(str(path))
|
|
37
|
-
return "/" + drive[0].lower() + rest.replace("\\", "/")
|
|
38
|
-
|
|
39
|
-
|
|
40
23
|
def _bash() -> str:
|
|
41
24
|
bash = shutil.which("bash")
|
|
42
25
|
if bash is None:
|
|
@@ -46,7 +29,7 @@ def _bash() -> str:
|
|
|
46
29
|
|
|
47
30
|
def _run_script(*args: str, env: dict) -> subprocess.CompletedProcess:
|
|
48
31
|
return subprocess.run(
|
|
49
|
-
[_bash(),
|
|
32
|
+
[_bash(), str(SCRIPT), *args],
|
|
50
33
|
capture_output=True,
|
|
51
34
|
text=True,
|
|
52
35
|
env=env,
|
|
@@ -64,7 +47,7 @@ def _make_stub(bin_dir: Path, name: str, body: str) -> None:
|
|
|
64
47
|
def _env_with(bin_dir: Path | None = None) -> dict:
|
|
65
48
|
entries = ["/usr/bin", "/bin"]
|
|
66
49
|
if bin_dir is not None:
|
|
67
|
-
entries.insert(0,
|
|
50
|
+
entries.insert(0, str(bin_dir))
|
|
68
51
|
return {**os.environ, "PATH": ":".join(entries)}
|
|
69
52
|
|
|
70
53
|
|
|
@@ -80,7 +63,7 @@ def test_trigger_upgrades_existing_install(tmp_path):
|
|
|
80
63
|
_make_stub(
|
|
81
64
|
bin_dir,
|
|
82
65
|
"pipx",
|
|
83
|
-
f'echo "$*" >> "{
|
|
66
|
+
f'echo "$*" >> "{str(pipx_log)}"',
|
|
84
67
|
)
|
|
85
68
|
|
|
86
69
|
result = _run_script("--plan", "plan.md", env=_env_with(bin_dir))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/core/results.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/core/verdict.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/__init__.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/actions.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/agents.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/dryrun.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/egress_policy.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/egress_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/graph.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/hostboundary.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/isolation.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/loaders.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/mounts.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/outputs.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/presets.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/secrets.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/stages.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/engine/sync_back.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/viz/__init__.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop/viz/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop.egg-info/requires.txt
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/src/agentic_dev_loop.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a26 → agentic_dev_loop-1.0.0a27}/tests/test_hostboundary_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|