agentic-dev-loop 1.0.0a49__tar.gz → 1.0.0a50__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.0a49/src/agentic_dev_loop.egg-info → agentic_dev_loop-1.0.0a50}/PKG-INFO +5 -2
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/README.md +4 -1
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/pyproject.toml +1 -1
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/isolation.py +35 -16
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50/src/agentic_dev_loop.egg-info}/PKG-INFO +5 -2
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_containers.py +5 -1
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_isolation.py +69 -7
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/LICENSE +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/setup.cfg +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/core/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/core/config.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/core/paths.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/core/results.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/core/verdict.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/actions.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/agent_error_guide.md +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/agent_error_guide.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/agents.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/allowlist.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/brief_coverage.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/brief_prompt.md +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/brief_prompt.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/cli.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/containers.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/deps.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/dryrun.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/egress_policy.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/egress_proxy.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/extensions/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/extensions/aidlc.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/forbidden.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/graph.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/hostboundary.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/llm.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/loaders.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/mounts.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/outputs.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/presets.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/proc.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/registry.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/seccomp/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/seccomp/chromium-userns.json +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/secrets.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/stages.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/step_workspace.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/sync_back.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/py.typed +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/viz/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/viz/__main__.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/viz/server.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop.egg-info/SOURCES.txt +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop.egg-info/dependency_links.txt +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop.egg-info/entry_points.txt +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop.egg-info/requires.txt +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop.egg-info/top_level.txt +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_028_declared_caches.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_029_merge_on_conflict.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_033_brief_step.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_035_finalize_nudge.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_036_banned_commands_and_lane_boundary.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_041_brief_coverage.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_046_brief_prompt.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_actions.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_agent_error_guide.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_agents.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_aidlc.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_cli.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_config.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_deps.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_dry_run.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_e2e_fixtures.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_egress_proxy.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_graph.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_hostboundary.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_hostboundary_integration.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_isolation_integration.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_isolation_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_llm.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_loaders.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_module_contract.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_outputs.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_outputs_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_proc.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_publish.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_qa_prompt.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_registry.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_repo_ascii.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_results.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_sdk_compat.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_secrets.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_secrets_integration.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_secrets_pipeline.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_source_resolution.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_stages.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_step_workspace.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_sync_back.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_trigger_script.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_unit5_config.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_unit5_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_unit5_pure.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_verdict.py +0 -0
- {agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/tests/test_viz.py +0 -0
{agentic_dev_loop-1.0.0a49/src/agentic_dev_loop.egg-info → agentic_dev_loop-1.0.0a50}/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.0a50
|
|
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
|
|
@@ -169,7 +169,10 @@ engine-owned object to its owning run and a `live`, `orphaned`,
|
|
|
169
169
|
registry-owned orphans whose owner pid is dead (never unregistered names).
|
|
170
170
|
A SIGTERM to a running pipeline still closes the sandbox (the graph's
|
|
171
171
|
`finally` runs); SIGKILL is unhandleable, so its containers are reclaimed by
|
|
172
|
-
the startup reaper on the next run or by `containers --reap`.
|
|
172
|
+
the startup reaper on the next run or by `containers --reap`. The reaper
|
|
173
|
+
and `--reap` prune a registry entry only after the daemon confirms the
|
|
174
|
+
object is gone; a surviving object (a failed removal) keeps its entry so
|
|
175
|
+
the next startup retries it. Pass
|
|
173
176
|
`--state-dir` to point at a custom `isolation.state_dir`.
|
|
174
177
|
|
|
175
178
|
**What a run looks like** (the shipped self-loop example):
|
|
@@ -125,7 +125,10 @@ engine-owned object to its owning run and a `live`, `orphaned`,
|
|
|
125
125
|
registry-owned orphans whose owner pid is dead (never unregistered names).
|
|
126
126
|
A SIGTERM to a running pipeline still closes the sandbox (the graph's
|
|
127
127
|
`finally` runs); SIGKILL is unhandleable, so its containers are reclaimed by
|
|
128
|
-
the startup reaper on the next run or by `containers --reap`.
|
|
128
|
+
the startup reaper on the next run or by `containers --reap`. The reaper
|
|
129
|
+
and `--reap` prune a registry entry only after the daemon confirms the
|
|
130
|
+
object is gone; a surviving object (a failed removal) keeps its entry so
|
|
131
|
+
the next startup retries it. Pass
|
|
129
132
|
`--state-dir` to point at a custom `isolation.state_dir`.
|
|
130
133
|
|
|
131
134
|
**What a run looks like** (the shipped self-loop example):
|
|
@@ -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.0a50"
|
|
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"
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/isolation.py
RENAMED
|
@@ -1632,23 +1632,12 @@ class DockerBackend(Sandbox):
|
|
|
1632
1632
|
_write_registry(self._iso_state_dir, remaining)
|
|
1633
1633
|
|
|
1634
1634
|
def _container_gone(self, name: str) -> bool:
|
|
1635
|
-
"""
|
|
1636
|
-
|
|
1637
|
-
res = self._runner.run(
|
|
1638
|
-
["docker", "ps", "-a", "--filter", f"name={name}",
|
|
1639
|
-
"--format", "{{.Names}}"], timeout=30)
|
|
1640
|
-
if res.exit_code != 0:
|
|
1641
|
-
return False
|
|
1642
|
-
return name not in res.stdout.splitlines()
|
|
1635
|
+
"""Thin delegation to the module-level confirm helper (050 D2)."""
|
|
1636
|
+
return _container_gone(self._runner, name)
|
|
1643
1637
|
|
|
1644
1638
|
def _network_gone(self, name: str) -> bool:
|
|
1645
|
-
"""
|
|
1646
|
-
|
|
1647
|
-
res = self._runner.run(
|
|
1648
|
-
["docker", "network", "inspect", name], timeout=30)
|
|
1649
|
-
if res.exit_code == 0:
|
|
1650
|
-
return False
|
|
1651
|
-
return "No such network" in f"{res.stderr} {res.stdout}"
|
|
1639
|
+
"""Thin delegation to the module-level confirm helper (050 D2)."""
|
|
1640
|
+
return _network_gone(self._runner, name)
|
|
1652
1641
|
|
|
1653
1642
|
# -- internal -----------------------------------------------------------
|
|
1654
1643
|
|
|
@@ -1882,6 +1871,28 @@ def _pid_alive_matches(pid: int, recorded_start: str | None) -> bool:
|
|
|
1882
1871
|
return current == recorded_start
|
|
1883
1872
|
|
|
1884
1873
|
|
|
1874
|
+
def _container_gone(runner: CommandRunner, name: str) -> bool:
|
|
1875
|
+
"""True only when the daemon confirms the container no longer exists.
|
|
1876
|
+
A nonzero daemon exit keeps the entry."""
|
|
1877
|
+
res = runner.run(
|
|
1878
|
+
["docker", "ps", "-a", "--filter", f"name={name}",
|
|
1879
|
+
"--format", "{{.Names}}"], timeout=30)
|
|
1880
|
+
if res.exit_code != 0:
|
|
1881
|
+
return False
|
|
1882
|
+
return name not in res.stdout.splitlines()
|
|
1883
|
+
|
|
1884
|
+
|
|
1885
|
+
def _network_gone(runner: CommandRunner, name: str) -> bool:
|
|
1886
|
+
"""True only when the daemon reports the network is missing. Any
|
|
1887
|
+
other inspect failure (daemon unreachable) keeps the entry."""
|
|
1888
|
+
res = runner.run(
|
|
1889
|
+
["docker", "network", "inspect", name], timeout=30)
|
|
1890
|
+
if res.exit_code == 0:
|
|
1891
|
+
return False
|
|
1892
|
+
return "No such network" in f"{res.stderr} {res.stdout}"
|
|
1893
|
+
|
|
1894
|
+
|
|
1895
|
+
|
|
1885
1896
|
def reap_orphaned_containers(state_dir: str | Path,
|
|
1886
1897
|
runner: CommandRunner | None = None,
|
|
1887
1898
|
*, announce: bool = True) -> list[str]:
|
|
@@ -1889,7 +1900,9 @@ def reap_orphaned_containers(state_dir: str | Path,
|
|
|
1889
1900
|
and the per-run internal network whose owning CLI process is gone (crashed
|
|
1890
1901
|
before close()). Exact by construction - only engine registry names are
|
|
1891
1902
|
touched, and a live owner (pid alive with the same start time) is left
|
|
1892
|
-
alone.
|
|
1903
|
+
alone. A surviving object (rm failure) keeps its entry so the next
|
|
1904
|
+
startup reaper retries; only a daemon-confirmed absence prunes it (050
|
|
1905
|
+
D1). Best-effort: never raises."""
|
|
1893
1906
|
runner = runner or _default_runner
|
|
1894
1907
|
entries = _read_registry(Path(state_dir))
|
|
1895
1908
|
if not entries:
|
|
@@ -1909,6 +1922,9 @@ def reap_orphaned_containers(state_dir: str | Path,
|
|
|
1909
1922
|
remaining.append(entry)
|
|
1910
1923
|
continue
|
|
1911
1924
|
runner.run(["docker", "network", "rm", name], timeout=60)
|
|
1925
|
+
if not _network_gone(runner, name):
|
|
1926
|
+
remaining.append(entry)
|
|
1927
|
+
continue
|
|
1912
1928
|
if announce:
|
|
1913
1929
|
_announce(f"reaped orphaned sandbox network {name}")
|
|
1914
1930
|
reaped.append(name)
|
|
@@ -1924,6 +1940,9 @@ def reap_orphaned_containers(state_dir: str | Path,
|
|
|
1924
1940
|
remaining.append(entry)
|
|
1925
1941
|
continue
|
|
1926
1942
|
runner.run(["docker", "rm", "-f", name], timeout=60)
|
|
1943
|
+
if not _container_gone(runner, name):
|
|
1944
|
+
remaining.append(entry)
|
|
1945
|
+
continue
|
|
1927
1946
|
if announce:
|
|
1928
1947
|
_announce(f"reaped orphaned sandbox container {name}")
|
|
1929
1948
|
reaped.append(name)
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50/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.0a50
|
|
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
|
|
@@ -169,7 +169,10 @@ engine-owned object to its owning run and a `live`, `orphaned`,
|
|
|
169
169
|
registry-owned orphans whose owner pid is dead (never unregistered names).
|
|
170
170
|
A SIGTERM to a running pipeline still closes the sandbox (the graph's
|
|
171
171
|
`finally` runs); SIGKILL is unhandleable, so its containers are reclaimed by
|
|
172
|
-
the startup reaper on the next run or by `containers --reap`.
|
|
172
|
+
the startup reaper on the next run or by `containers --reap`. The reaper
|
|
173
|
+
and `--reap` prune a registry entry only after the daemon confirms the
|
|
174
|
+
object is gone; a surviving object (a failed removal) keeps its entry so
|
|
175
|
+
the next startup retries it. Pass
|
|
173
176
|
`--state-dir` to point at a custom `isolation.state_dir`.
|
|
174
177
|
|
|
175
178
|
**What a run looks like** (the shipped self-loop example):
|
|
@@ -123,7 +123,11 @@ class TestReapReturnValue:
|
|
|
123
123
|
_write(tmp_path / "state", [_entry(name, proc.pid, None)])
|
|
124
124
|
runner = FakeRunner(ok(""))
|
|
125
125
|
assert reap_orphaned_containers(tmp_path / "state", runner) == [name]
|
|
126
|
-
assert runner.calls == [
|
|
126
|
+
assert runner.calls == [
|
|
127
|
+
["docker", "rm", "-f", name],
|
|
128
|
+
["docker", "ps", "-a", "--filter", f"name={name}",
|
|
129
|
+
"--format", "{{.Names}}"],
|
|
130
|
+
]
|
|
127
131
|
|
|
128
132
|
def test_reap_live_owner_returns_empty(self, tmp_path):
|
|
129
133
|
name = f"{'b' * 32}-exec"
|
|
@@ -2251,7 +2251,11 @@ class TestReaper:
|
|
|
2251
2251
|
runner = FakeRunner()
|
|
2252
2252
|
reaped = reap_orphaned_containers(tmp_path / "state", runner)
|
|
2253
2253
|
assert reaped == [name]
|
|
2254
|
-
assert runner.calls == [
|
|
2254
|
+
assert runner.calls == [
|
|
2255
|
+
["docker", "rm", "-f", name],
|
|
2256
|
+
["docker", "ps", "-a", "--filter", f"name={name}",
|
|
2257
|
+
"--format", "{{.Names}}"],
|
|
2258
|
+
]
|
|
2255
2259
|
assert self._read(tmp_path / "state") == []
|
|
2256
2260
|
|
|
2257
2261
|
def test_live_pid_left_alone(self, tmp_path):
|
|
@@ -2282,9 +2286,13 @@ class TestReaper:
|
|
|
2282
2286
|
"run_id": "r", "name": name, "kind": "network",
|
|
2283
2287
|
"pid": proc.pid, "process_start": None, "created_at": "now",
|
|
2284
2288
|
}])
|
|
2285
|
-
runner = FakeRunner()
|
|
2286
|
-
reap_orphaned_containers(tmp_path / "state", runner)
|
|
2287
|
-
assert
|
|
2289
|
+
runner = FakeRunner(ok(""), fail(1, "No such network"))
|
|
2290
|
+
reaped = reap_orphaned_containers(tmp_path / "state", runner)
|
|
2291
|
+
assert reaped == [name]
|
|
2292
|
+
assert runner.calls == [
|
|
2293
|
+
["docker", "network", "rm", name],
|
|
2294
|
+
["docker", "network", "inspect", name],
|
|
2295
|
+
]
|
|
2288
2296
|
assert self._read(tmp_path / "state") == []
|
|
2289
2297
|
|
|
2290
2298
|
def test_malformed_name_skipped(self, tmp_path):
|
|
@@ -2300,11 +2308,65 @@ class TestReaper:
|
|
|
2300
2308
|
proc.wait()
|
|
2301
2309
|
name = f"{'e' * 32}-exec"
|
|
2302
2310
|
self._write(tmp_path / "state", [self._entry(name, proc.pid)])
|
|
2303
|
-
runner = FakeRunner(fail(1, "No such container"))
|
|
2304
|
-
reap_orphaned_containers(tmp_path / "state", runner)
|
|
2305
|
-
assert
|
|
2311
|
+
runner = FakeRunner(fail(1, "No such container"), ok(""))
|
|
2312
|
+
reaped = reap_orphaned_containers(tmp_path / "state", runner)
|
|
2313
|
+
assert reaped == [name]
|
|
2314
|
+
assert runner.calls == [
|
|
2315
|
+
["docker", "rm", "-f", name],
|
|
2316
|
+
["docker", "ps", "-a", "--filter", f"name={name}",
|
|
2317
|
+
"--format", "{{.Names}}"],
|
|
2318
|
+
]
|
|
2306
2319
|
assert self._read(tmp_path / "state") == []
|
|
2307
2320
|
|
|
2321
|
+
def test_rm_failure_container_survives_retained(self, tmp_path):
|
|
2322
|
+
proc = subprocess.Popen([sys.executable, "-c", "pass"])
|
|
2323
|
+
proc.wait()
|
|
2324
|
+
name = f"{'a' * 32}-exec"
|
|
2325
|
+
entry = self._entry(name, proc.pid)
|
|
2326
|
+
self._write(tmp_path / "state", [entry])
|
|
2327
|
+
runner = FakeRunner(fail(1, "daemon busy"), ok(name + "\n"))
|
|
2328
|
+
reaped = reap_orphaned_containers(tmp_path / "state", runner)
|
|
2329
|
+
assert reaped == []
|
|
2330
|
+
assert self._read(tmp_path / "state") == [entry]
|
|
2331
|
+
assert runner.calls == [
|
|
2332
|
+
["docker", "rm", "-f", name],
|
|
2333
|
+
["docker", "ps", "-a", "--filter", f"name={name}",
|
|
2334
|
+
"--format", "{{.Names}}"],
|
|
2335
|
+
]
|
|
2336
|
+
|
|
2337
|
+
def test_rm_failure_network_survives_retained(self, tmp_path):
|
|
2338
|
+
proc = subprocess.Popen([sys.executable, "-c", "pass"])
|
|
2339
|
+
proc.wait()
|
|
2340
|
+
name = f"{'a' * 32}-net"
|
|
2341
|
+
entry = {"run_id": "r", "name": name, "kind": "network",
|
|
2342
|
+
"pid": proc.pid, "process_start": None, "created_at": "now"}
|
|
2343
|
+
self._write(tmp_path / "state", [entry])
|
|
2344
|
+
runner = FakeRunner(fail(1, "daemon busy"), ok(name))
|
|
2345
|
+
reaped = reap_orphaned_containers(tmp_path / "state", runner)
|
|
2346
|
+
assert reaped == []
|
|
2347
|
+
assert self._read(tmp_path / "state") == [entry]
|
|
2348
|
+
assert runner.calls == [
|
|
2349
|
+
["docker", "network", "rm", name],
|
|
2350
|
+
["docker", "network", "inspect", name],
|
|
2351
|
+
]
|
|
2352
|
+
|
|
2353
|
+
def test_missing_network_tolerated(self, tmp_path):
|
|
2354
|
+
proc = subprocess.Popen([sys.executable, "-c", "pass"])
|
|
2355
|
+
proc.wait()
|
|
2356
|
+
name = f"{'a' * 32}-net"
|
|
2357
|
+
entry = {"run_id": "r", "name": name, "kind": "network",
|
|
2358
|
+
"pid": proc.pid, "process_start": None, "created_at": "now"}
|
|
2359
|
+
self._write(tmp_path / "state", [entry])
|
|
2360
|
+
runner = FakeRunner(fail(1, "No such network"),
|
|
2361
|
+
fail(1, "No such network"))
|
|
2362
|
+
reaped = reap_orphaned_containers(tmp_path / "state", runner)
|
|
2363
|
+
assert reaped == [name]
|
|
2364
|
+
assert self._read(tmp_path / "state") == []
|
|
2365
|
+
assert runner.calls == [
|
|
2366
|
+
["docker", "network", "rm", name],
|
|
2367
|
+
["docker", "network", "inspect", name],
|
|
2368
|
+
]
|
|
2369
|
+
|
|
2308
2370
|
def test_no_registry_is_a_noop(self, tmp_path):
|
|
2309
2371
|
runner = FakeRunner()
|
|
2310
2372
|
reap_orphaned_containers(tmp_path / "state", runner)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/core/results.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/core/verdict.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/__init__.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/actions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/agents.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/allowlist.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/brief_prompt.md
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/brief_prompt.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/containers.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/dryrun.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/egress_policy.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/egress_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/forbidden.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/graph.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/hostboundary.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/loaders.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/mounts.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/outputs.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/presets.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/secrets.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/stages.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/engine/sync_back.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/viz/__init__.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop/viz/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/src/agentic_dev_loop.egg-info/requires.txt
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a49 → agentic_dev_loop-1.0.0a50}/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
|
|
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.0a49 → agentic_dev_loop-1.0.0a50}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|