agentic-dev-loop 1.0.0rc2__tar.gz → 1.0.0rc3__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.
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/PKG-INFO +4 -3
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/README.md +2 -2
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/pyproject.toml +6 -1
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/core/config.py +1 -1
- agentic_dev_loop-1.0.0rc3/src/agentic_dev_loop/engine/claude_auth.py +301 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/cli.py +31 -2
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/llm.py +20 -5
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/provider_wire.py +41 -4
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/secrets.py +5 -3
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop.egg-info/PKG-INFO +4 -3
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop.egg-info/SOURCES.txt +3 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop.egg-info/requires.txt +1 -0
- agentic_dev_loop-1.0.0rc3/tests/test_claude_auth.py +337 -0
- agentic_dev_loop-1.0.0rc3/tests/test_claude_cli.py +43 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_config.py +9 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_provider_wire.py +98 -3
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_secrets.py +4 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_viz_wheel_contents.py +10 -3
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/LICENSE +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/setup.cfg +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/__init__.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/core/__init__.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/core/failure.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/core/paths.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/core/profiles/__init__.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/core/profiles/data/dotnet-node.yaml +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/core/profiles/data/python.yaml +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/core/results.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/core/verdict.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/__init__.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/actions.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/agent_error_guide.md +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/agent_error_guide.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/agents.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/allowlist.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/brief_coverage.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/brief_prompt.md +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/brief_prompt.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/completion.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/containers.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/copilot_auth.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/deps.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/dryrun.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/egress_policy.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/egress_proxy.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/extensions/__init__.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/extensions/aidlc.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/forbidden.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/graph.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/hostboundary.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/isolation.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/loaders.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/mounts.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/__init__.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/checks.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/doctor.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/init.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/recipes/dotnet-node.yaml +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/recipes/python.yaml +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/recipes.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/templates/dev.agent.md +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/templates/env.example +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/templates/qa.agent.md +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/templates/review.agent.md +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/templates.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/onboarding/upgrade.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/outputs.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/presets.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/proc.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/registry.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/run_status.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/run_status_command.md +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/seccomp/__init__.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/seccomp/chromium-userns.json +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/stages.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/step_workspace.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/sync_back.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/py.typed +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/reporting/__init__.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/reporting/metrics.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/reporting/render.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/reporting/sources.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/__init__.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/layout.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/page.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/runs_view.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/server.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/16-1pKPtbcx.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/16-2lMgbefg.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/16-B0WgRfVg.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/16-B3fCnGwv.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/16-Bm3KyEZC.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/16-DIfh6y3Q.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/16-DxEg5YJZ.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/20-CdViZ4xF.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/accordion.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/button-rSg_K8yf.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/button-skeleton-i-vqINhS.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/button.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/carbon-element-Bi7pQHAl.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/checkbox-D7PSLQCq.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/checkbox.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/class-map-t9xXbTFr.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/code-snippet.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/collection-helpers-BOkEorAG.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/copy-button.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/copy-tonlUGaV.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/data-table.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/decorate-1Ivfrp93.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/decorators-CNcdZSLL.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/deep-shadow-contains-Cs2rSnhr.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/definition-tooltip-FYe4J71p.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/directive-xDpGnViN.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/feature-flags-C7ZDYm5Q.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/floating-controller-DmTRVV0A.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/focus-D91D_iCB.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/form-Sg67yyAA.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/host-listener-CEd01uiB.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/host-listener-D_ODAJ3e.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/icon-button-Be2x1qrf.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/icon-loader-Cj1PggRN.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/icon-loader-utils-CVerE28u.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/if-defined-CV6i5LeB.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/if-non-empty-B5mz8bH9.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/link-aD3OYHCu.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/link.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/manifest.json +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/notification.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/on-DP_Dnlgd.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/popover-content-fajgXUvu.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/popover.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/query-DJR3NpB4.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/query-all-BuL-eXl_.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/radio-button.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/radio-group-manager-BE85t4HN.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/search-CVX2VAop.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/settings-DlHDxgf_.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/skeleton-text-s5gA9_CO.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/skeleton-text.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/tag.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/themes.css +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/tile.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/tooltip-DYtXwn-o.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/tooltip-content-DDo9ICPL.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/tooltip.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/ui-shell.min.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/viz/vendor/unsafe-html-BDr7jYB8.js +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop.egg-info/dependency_links.txt +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop.egg-info/entry_points.txt +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop.egg-info/top_level.txt +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_029_merge_on_conflict.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_033_brief_step.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_035_finalize_nudge.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_036_banned_commands_and_lane_boundary.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_041_brief_coverage.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_046_brief_prompt.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_055_cli.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_055_doctor.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_055_init.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_055_profile_loading.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_055_profiles.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_055_recipes.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_055_schema_lock.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_055_templates.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_055_upgrade.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_actions.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_agent_error_guide.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_agents.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_aidlc.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_build_viz_page.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_cli.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_containers.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_copilot_auth.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_copilot_cli.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_deps.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_dry_run.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_e2e_fixtures.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_egress_proxy.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_graph.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_hostboundary.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_hostboundary_integration.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_isolation.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_isolation_integration.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_isolation_pbt.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_llm.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_loaders.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_module_contract.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_outputs.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_outputs_pbt.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_proc.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_publish.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_pypi_yank.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_qa_prompt.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_registry.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_repo_ascii.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_results.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_run_status.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_runs_js_duration_charts.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_runs_js_filters.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_runs_js_key_stats.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_runs_js_metrics.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_runs_layout.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_runs_layout_key_stats.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_sdk_compat.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_secrets_integration.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_secrets_pipeline.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_source_resolution.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_stages.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_step_workspace.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_sync_back.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_unit11.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_unit11_pbt.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_unit12_reporting.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_unit13_runs_viz.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_unit5_config.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_unit5_pbt.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_unit5_pure.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_vendor_carbon_wc.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_verdict.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_viz.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_viz_demo.py +0 -0
- {agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/tests/test_viz_layout.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-dev-loop
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.0rc3
|
|
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
|
|
@@ -44,6 +44,7 @@ Requires-Dist: hypothesis>=6.0; extra == "dev"
|
|
|
44
44
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
45
45
|
Requires-Dist: pip-audit>=2.0; extra == "dev"
|
|
46
46
|
Requires-Dist: pre-commit>=3.0; extra == "dev"
|
|
47
|
+
Requires-Dist: setuptools>=78.1.1; extra == "dev"
|
|
47
48
|
Provides-Extra: docs
|
|
48
49
|
Requires-Dist: mkdocs-material~=9.6; extra == "docs"
|
|
49
50
|
Requires-Dist: pymdown-extensions~=10.0; extra == "docs"
|
|
@@ -108,7 +109,7 @@ Docker engine does:
|
|
|
108
109
|
| --- | --- |
|
|
109
110
|
| Python | >= 3.12 |
|
|
110
111
|
| 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. |
|
|
111
|
-
| 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. Alternatively, `agentic-dev-loop copilot-login` authenticates a Copilot subscription (see [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/)). |
|
|
112
|
+
| 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. Alternatively, `agentic-dev-loop copilot-login` authenticates a Copilot subscription, and a Claude Pro or Max subscription runs on Anthropic's own endpoint after `agentic-dev-loop claude-login` (see [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/)). |
|
|
112
113
|
|
|
113
114
|
### Installation
|
|
114
115
|
|
|
@@ -181,7 +182,7 @@ policy, named LLM profiles - is in the
|
|
|
181
182
|
| [Architecture](https://lukedawilson.github.io/agentic-dev-loop/architecture/) | The five layers, one full run end to end, and the host-boundary security model |
|
|
182
183
|
| [CLI](https://lukedawilson.github.io/agentic-dev-loop/cli/) | Run flags, resuming, the live view, reports, container management, and onboarding commands |
|
|
183
184
|
| [pipeline.yaml](https://lukedawilson.github.io/agentic-dev-loop/pipeline/) | The complete configuration reference: steps, isolation, secrets, networking, dependency policy |
|
|
184
|
-
| [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/) | OpenAI-compatible endpoints (OpenAI, DeepSeek, and others)
|
|
185
|
+
| [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/) | OpenAI-compatible endpoints (OpenAI, DeepSeek, and others), the GitHub Copilot subscription, and the Claude subscription |
|
|
185
186
|
| [Authoring a loop](https://lukedawilson.github.io/agentic-dev-loop/authoring/) | From `init` to a committed pipeline: agent files, stage lineup, adaptation checklist |
|
|
186
187
|
| [Setup and troubleshooting](https://lukedawilson.github.io/agentic-dev-loop/setup/) | Docker engines, the dev image, caching, error codes |
|
|
187
188
|
| [Browser sandbox](https://lukedawilson.github.io/agentic-dev-loop/browser-sandbox/) | Running a browser inside the sandbox |
|
|
@@ -57,7 +57,7 @@ Docker engine does:
|
|
|
57
57
|
| --- | --- |
|
|
58
58
|
| Python | >= 3.12 |
|
|
59
59
|
| 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. |
|
|
60
|
-
| 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. Alternatively, `agentic-dev-loop copilot-login` authenticates a Copilot subscription (see [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/)). |
|
|
60
|
+
| 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. Alternatively, `agentic-dev-loop copilot-login` authenticates a Copilot subscription, and a Claude Pro or Max subscription runs on Anthropic's own endpoint after `agentic-dev-loop claude-login` (see [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/)). |
|
|
61
61
|
|
|
62
62
|
### Installation
|
|
63
63
|
|
|
@@ -130,7 +130,7 @@ policy, named LLM profiles - is in the
|
|
|
130
130
|
| [Architecture](https://lukedawilson.github.io/agentic-dev-loop/architecture/) | The five layers, one full run end to end, and the host-boundary security model |
|
|
131
131
|
| [CLI](https://lukedawilson.github.io/agentic-dev-loop/cli/) | Run flags, resuming, the live view, reports, container management, and onboarding commands |
|
|
132
132
|
| [pipeline.yaml](https://lukedawilson.github.io/agentic-dev-loop/pipeline/) | The complete configuration reference: steps, isolation, secrets, networking, dependency policy |
|
|
133
|
-
| [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/) | OpenAI-compatible endpoints (OpenAI, DeepSeek, and others)
|
|
133
|
+
| [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/) | OpenAI-compatible endpoints (OpenAI, DeepSeek, and others), the GitHub Copilot subscription, and the Claude subscription |
|
|
134
134
|
| [Authoring a loop](https://lukedawilson.github.io/agentic-dev-loop/authoring/) | From `init` to a committed pipeline: agent files, stage lineup, adaptation checklist |
|
|
135
135
|
| [Setup and troubleshooting](https://lukedawilson.github.io/agentic-dev-loop/setup/) | Docker engines, the dev image, caching, error codes |
|
|
136
136
|
| [Browser sandbox](https://lukedawilson.github.io/agentic-dev-loop/browser-sandbox/) | Running a browser inside the sandbox |
|
|
@@ -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.0rc3"
|
|
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"
|
|
@@ -84,6 +84,11 @@ dev = [
|
|
|
84
84
|
"pytest>=8.0",
|
|
85
85
|
"pip-audit>=2.0",
|
|
86
86
|
"pre-commit>=3.0",
|
|
87
|
+
# tests/test_viz_wheel_contents.py builds a wheel with
|
|
88
|
+
# --no-build-isolation so the suite never needs PyPI; the backend must be
|
|
89
|
+
# importable from this environment. Floor pinned past CVE-2025-47273
|
|
90
|
+
# (fixed in 78.1.1) so the restore step's pip-audit stays green.
|
|
91
|
+
"setuptools>=78.1.1",
|
|
87
92
|
]
|
|
88
93
|
docs = [
|
|
89
94
|
"mkdocs-material~=9.6",
|
|
@@ -903,7 +903,7 @@ def _custom_prompt_looks_like_path(value: str) -> bool:
|
|
|
903
903
|
"""040/D2: a value counts as path-shaped when it carries a path
|
|
904
904
|
separator or a file extension (a dot). A path-shaped value that names no
|
|
905
905
|
existing file is a hard error, never silent text."""
|
|
906
|
-
return "/" in value or "\\" in value or Path(value).suffix != ""
|
|
906
|
+
return "/" in value or "\\" in value or Path(value.rstrip(".")).suffix != ""
|
|
907
907
|
|
|
908
908
|
|
|
909
909
|
def resolve_custom_prompt(value: str, pipeline_dir: Path, step_name: str) -> str:
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"""Claude subscription OAuth PKCE flow (066).
|
|
2
|
+
|
|
3
|
+
The Claude subscription endpoint consumes a Claude Code OAuth access token.
|
|
4
|
+
``claude-login`` runs the same first-party PKCE flow and writes the token
|
|
5
|
+
file the engine's ``api_key_secret`` FileProvider reads; it never runs
|
|
6
|
+
during a pipeline run. Login only: refresh-on-read is a follow-up plan, so
|
|
7
|
+
the refresh token is persisted now and the file schema stays put.
|
|
8
|
+
|
|
9
|
+
The token exchange uses a system ``curl`` subprocess, not urllib: the
|
|
10
|
+
Cloudflare edge in front of platform.claude.com answers urllib with 403
|
|
11
|
+
1010 "Access denied based on your browser's signature", while system curl
|
|
12
|
+
reaches the API. A missing curl is a loud error, never a urllib fallback.
|
|
13
|
+
|
|
14
|
+
The default client id is Claude Code's own first-party OAuth app id, the
|
|
15
|
+
same borrow pattern the Copilot path uses with OpenCode's app, and is
|
|
16
|
+
overridable via ``AGENTIC_DEV_LOOP_CLAUDE_CLIENT_ID``.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import base64
|
|
22
|
+
import hashlib
|
|
23
|
+
import json
|
|
24
|
+
import os
|
|
25
|
+
import secrets
|
|
26
|
+
import subprocess
|
|
27
|
+
import threading
|
|
28
|
+
import urllib.parse
|
|
29
|
+
import webbrowser
|
|
30
|
+
from datetime import datetime, timedelta, timezone
|
|
31
|
+
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
|
|
34
|
+
AUTHORIZE_URL = "https://claude.com/cai/oauth/authorize"
|
|
35
|
+
TOKEN_ENDPOINT = "https://platform.claude.com/v1/oauth/token"
|
|
36
|
+
TOKEN_PATH = Path("~/.agentic-dev-loop/auth/claude.json")
|
|
37
|
+
|
|
38
|
+
CLAUDE_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e"
|
|
39
|
+
CLIENT_ID_ENV = "AGENTIC_DEV_LOOP_CLAUDE_CLIENT_ID"
|
|
40
|
+
SCOPES = (
|
|
41
|
+
"org:create_api_key user:profile user:inference "
|
|
42
|
+
"user:sessions:claude_code user:mcp_servers user:file_upload "
|
|
43
|
+
"user:plugins")
|
|
44
|
+
|
|
45
|
+
CURL_TIMEOUT = 60
|
|
46
|
+
CALLBACK_TIMEOUT = 300
|
|
47
|
+
REQUIRED_TOKEN_FIELDS = ("access_token", "refresh_token", "expires_in")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ClaudeAuthError(RuntimeError):
|
|
51
|
+
"""A loud fail-fast auth failure naming the operator's next step."""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def client_id() -> str:
|
|
55
|
+
"""The OAuth app id: the overridable env var, else the pinned default."""
|
|
56
|
+
return os.environ.get(CLIENT_ID_ENV) or CLAUDE_CLIENT_ID
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _b64url(raw: bytes) -> str:
|
|
60
|
+
return base64.urlsafe_b64encode(raw).rstrip(b"=").decode("ascii")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def pkce_pair(rng=os.urandom) -> tuple[str, str]:
|
|
64
|
+
"""A 32-byte PKCE verifier and its S256 challenge, base64url unpadded."""
|
|
65
|
+
verifier = _b64url(rng(32))
|
|
66
|
+
challenge = _b64url(hashlib.sha256(verifier.encode("ascii")).digest())
|
|
67
|
+
return verifier, challenge
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def authorize_url(redirect_uri: str, code_challenge: str, state: str,
|
|
71
|
+
client_id_value: str | None = None) -> str:
|
|
72
|
+
"""The captured authorize URL shape, parameter order included."""
|
|
73
|
+
params = [
|
|
74
|
+
("code", "true"),
|
|
75
|
+
("client_id", client_id_value or client_id()),
|
|
76
|
+
("response_type", "code"),
|
|
77
|
+
("redirect_uri", redirect_uri),
|
|
78
|
+
("scope", SCOPES),
|
|
79
|
+
("code_challenge", code_challenge),
|
|
80
|
+
("code_challenge_method", "S256"),
|
|
81
|
+
("state", state),
|
|
82
|
+
]
|
|
83
|
+
query = urllib.parse.urlencode(params, safe=":/")
|
|
84
|
+
return f"{AUTHORIZE_URL}?{query}"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _run_curl(argv: list[str]) -> subprocess.CompletedProcess:
|
|
88
|
+
try:
|
|
89
|
+
return subprocess.run(argv, capture_output=True, text=True,
|
|
90
|
+
timeout=CURL_TIMEOUT, check=False)
|
|
91
|
+
except subprocess.TimeoutExpired as e:
|
|
92
|
+
raise ClaudeAuthError(
|
|
93
|
+
"the Claude token endpoint did not respond within "
|
|
94
|
+
f"{CURL_TIMEOUT}s - retry `agentic-dev-loop claude-login`") from e
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _missing_curl() -> ClaudeAuthError:
|
|
98
|
+
return ClaudeAuthError(
|
|
99
|
+
"curl is required for the Claude token exchange but was not found "
|
|
100
|
+
"on PATH - install curl and run `agentic-dev-loop claude-login` again")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _parse_response(output: str, returncode: int, stderr: str,
|
|
104
|
+
token_endpoint: str) -> tuple[str, int]:
|
|
105
|
+
if "\n" not in output:
|
|
106
|
+
detail = output.strip() or stderr.strip() or f"curl exit {returncode}"
|
|
107
|
+
raise ClaudeAuthError(
|
|
108
|
+
f"curl did not return an HTTP status from {token_endpoint}: "
|
|
109
|
+
f"{detail}")
|
|
110
|
+
body, _, status_text = output.rpartition("\n")
|
|
111
|
+
try:
|
|
112
|
+
return body, int(status_text.strip())
|
|
113
|
+
except ValueError as e:
|
|
114
|
+
raise ClaudeAuthError(
|
|
115
|
+
f"could not read the HTTP status from curl output for "
|
|
116
|
+
f"{token_endpoint}: {status_text.strip() or 'empty'}") from e
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def exchange_token(code: str, redirect_uri: str, code_verifier: str,
|
|
120
|
+
state: str, *, token_endpoint: str = TOKEN_ENDPOINT,
|
|
121
|
+
curl_runner=None) -> dict:
|
|
122
|
+
"""Exchange the authorization code for tokens via system curl."""
|
|
123
|
+
body = json.dumps({
|
|
124
|
+
"grant_type": "authorization_code",
|
|
125
|
+
"code": code,
|
|
126
|
+
"redirect_uri": redirect_uri,
|
|
127
|
+
"client_id": client_id(),
|
|
128
|
+
"code_verifier": code_verifier,
|
|
129
|
+
"state": state,
|
|
130
|
+
}, separators=(",", ":"))
|
|
131
|
+
argv = [
|
|
132
|
+
"curl", "-sS",
|
|
133
|
+
"-X", "POST", token_endpoint,
|
|
134
|
+
"-H", "Content-Type: application/json",
|
|
135
|
+
"-H", "Accept: application/json",
|
|
136
|
+
"--data-binary", body,
|
|
137
|
+
"-w", "\n%{http_code}",
|
|
138
|
+
]
|
|
139
|
+
runner = curl_runner or _run_curl
|
|
140
|
+
try:
|
|
141
|
+
completed = runner(argv)
|
|
142
|
+
except FileNotFoundError as e:
|
|
143
|
+
raise _missing_curl() from e
|
|
144
|
+
body_text, status = _parse_response(
|
|
145
|
+
completed.stdout or "", completed.returncode,
|
|
146
|
+
completed.stderr or "", token_endpoint)
|
|
147
|
+
detail = body_text.strip()[:500]
|
|
148
|
+
if status == 429:
|
|
149
|
+
raise ClaudeAuthError(
|
|
150
|
+
"the token endpoint is rate limited (HTTP 429): "
|
|
151
|
+
f"{detail or 'rate_limit_error'}; retry in a few minutes by "
|
|
152
|
+
"running `agentic-dev-loop claude-login` again")
|
|
153
|
+
if status != 200:
|
|
154
|
+
raise ClaudeAuthError(
|
|
155
|
+
f"the token exchange failed (HTTP {status}): "
|
|
156
|
+
f"{detail or 'no response body'}")
|
|
157
|
+
try:
|
|
158
|
+
payload = json.loads(body_text)
|
|
159
|
+
except json.JSONDecodeError as e:
|
|
160
|
+
raise ClaudeAuthError(
|
|
161
|
+
"the token endpoint returned a non-JSON response (HTTP 200): "
|
|
162
|
+
f"{detail}") from e
|
|
163
|
+
if not isinstance(payload, dict):
|
|
164
|
+
raise ClaudeAuthError(
|
|
165
|
+
"the token endpoint returned a JSON value that is not an object")
|
|
166
|
+
missing = [name for name in REQUIRED_TOKEN_FIELDS
|
|
167
|
+
if not _present(payload.get(name))]
|
|
168
|
+
if missing:
|
|
169
|
+
raise ClaudeAuthError(
|
|
170
|
+
"the token endpoint response is missing required field(s): "
|
|
171
|
+
+ ", ".join(missing))
|
|
172
|
+
return payload
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _present(value) -> bool:
|
|
176
|
+
if isinstance(value, str):
|
|
177
|
+
return bool(value)
|
|
178
|
+
return isinstance(value, (int, float)) and not isinstance(value, bool)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _expires_in_seconds(value) -> float:
|
|
182
|
+
try:
|
|
183
|
+
return float(value)
|
|
184
|
+
except (TypeError, ValueError) as e:
|
|
185
|
+
raise ClaudeAuthError(
|
|
186
|
+
f"the token endpoint returned a non-numeric expires_in: {value!r}"
|
|
187
|
+
) from e
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def write_token(token: dict, token_path: Path | str | None = None) -> Path:
|
|
191
|
+
"""Write access token, refresh token, and absolute expiry with mode 600."""
|
|
192
|
+
access = token.get("access_token")
|
|
193
|
+
refresh = token.get("refresh_token")
|
|
194
|
+
if not isinstance(access, str) or not access:
|
|
195
|
+
raise ClaudeAuthError("the token payload has no access_token")
|
|
196
|
+
if not isinstance(refresh, str) or not refresh:
|
|
197
|
+
raise ClaudeAuthError("the token payload has no refresh_token")
|
|
198
|
+
expires_at = (datetime.now(timezone.utc)
|
|
199
|
+
+ timedelta(seconds=_expires_in_seconds(
|
|
200
|
+
token.get("expires_in"))))
|
|
201
|
+
payload = {
|
|
202
|
+
"access_token": access,
|
|
203
|
+
"refresh_token": refresh,
|
|
204
|
+
"expires_at": expires_at.isoformat(),
|
|
205
|
+
}
|
|
206
|
+
path = (Path(token_path).expanduser() if token_path
|
|
207
|
+
else TOKEN_PATH.expanduser())
|
|
208
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
209
|
+
text = json.dumps(payload, indent=2, sort_keys=True) + "\n"
|
|
210
|
+
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
|
|
211
|
+
with os.fdopen(fd, "w", encoding="utf-8") as handle:
|
|
212
|
+
handle.write(text)
|
|
213
|
+
os.chmod(path, 0o600)
|
|
214
|
+
return path
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class _CallbackServer(HTTPServer):
|
|
218
|
+
expected_state: str
|
|
219
|
+
result: dict[str, str]
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class _CallbackHandler(BaseHTTPRequestHandler):
|
|
223
|
+
def do_GET(self):
|
|
224
|
+
server = self.server
|
|
225
|
+
params = urllib.parse.parse_qs(
|
|
226
|
+
urllib.parse.urlsplit(self.path).query)
|
|
227
|
+
state = (params.get("state") or [""])[0]
|
|
228
|
+
if state != server.expected_state:
|
|
229
|
+
server.result["error"] = "state mismatch in the OAuth callback"
|
|
230
|
+
self._respond(400, "Claude login failed: state mismatch. "
|
|
231
|
+
"Close this window and run "
|
|
232
|
+
"`agentic-dev-loop claude-login` again.")
|
|
233
|
+
return
|
|
234
|
+
error = (params.get("error") or [""])[0]
|
|
235
|
+
if error:
|
|
236
|
+
server.result["error"] = error
|
|
237
|
+
self._respond(400, f"Claude login failed: {error}. Close this "
|
|
238
|
+
"window and run `agentic-dev-loop claude-login` "
|
|
239
|
+
"again.")
|
|
240
|
+
return
|
|
241
|
+
code = (params.get("code") or [""])[0]
|
|
242
|
+
if not code:
|
|
243
|
+
server.result["error"] = "the OAuth callback carried no code"
|
|
244
|
+
self._respond(400, "Claude login failed: no authorization code.")
|
|
245
|
+
return
|
|
246
|
+
server.result["code"] = code
|
|
247
|
+
self._respond(200, "Claude login complete. You can close this window.")
|
|
248
|
+
|
|
249
|
+
def _respond(self, status: int, message: str) -> None:
|
|
250
|
+
body = (message + "\n").encode("utf-8")
|
|
251
|
+
self.send_response(status)
|
|
252
|
+
self.send_header("Content-Type", "text/plain; charset=utf-8")
|
|
253
|
+
self.send_header("Content-Length", str(len(body)))
|
|
254
|
+
self.end_headers()
|
|
255
|
+
self.wfile.write(body)
|
|
256
|
+
|
|
257
|
+
def log_message(self, fmt, *args):
|
|
258
|
+
pass
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def login(token_path: Path | str | None = None, *, opener=None,
|
|
262
|
+
token_endpoint: str = TOKEN_ENDPOINT, curl_runner=None,
|
|
263
|
+
printer=print,
|
|
264
|
+
callback_timeout: float = CALLBACK_TIMEOUT) -> dict:
|
|
265
|
+
"""Run the PKCE flow and persist the token; never called by a pipeline."""
|
|
266
|
+
verifier, challenge = pkce_pair()
|
|
267
|
+
state = secrets.token_urlsafe(32)
|
|
268
|
+
result: dict[str, str] = {}
|
|
269
|
+
server = _CallbackServer(("127.0.0.1", 0), _CallbackHandler)
|
|
270
|
+
server.expected_state = state
|
|
271
|
+
server.result = result
|
|
272
|
+
port = server.server_address[1]
|
|
273
|
+
redirect_uri = f"http://localhost:{port}/callback"
|
|
274
|
+
url = authorize_url(redirect_uri, challenge, state)
|
|
275
|
+
open_browser = opener or webbrowser.open
|
|
276
|
+
printer(f"Open this URL to authorize Claude: {url}")
|
|
277
|
+
thread = threading.Thread(target=server.handle_request, daemon=True)
|
|
278
|
+
thread.start()
|
|
279
|
+
try:
|
|
280
|
+
open_browser(url)
|
|
281
|
+
thread.join(callback_timeout)
|
|
282
|
+
finally:
|
|
283
|
+
server.server_close()
|
|
284
|
+
if thread.is_alive():
|
|
285
|
+
raise ClaudeAuthError(
|
|
286
|
+
"timed out waiting for the browser callback - run "
|
|
287
|
+
"`agentic-dev-loop claude-login` again")
|
|
288
|
+
if result.get("error"):
|
|
289
|
+
raise ClaudeAuthError(
|
|
290
|
+
f"authorization failed: {result['error']} - run "
|
|
291
|
+
"`agentic-dev-loop claude-login` again")
|
|
292
|
+
code = result.get("code")
|
|
293
|
+
if not code:
|
|
294
|
+
raise ClaudeAuthError(
|
|
295
|
+
"the OAuth callback carried no authorization code - run "
|
|
296
|
+
"`agentic-dev-loop claude-login` again")
|
|
297
|
+
token = exchange_token(code, redirect_uri, verifier, state,
|
|
298
|
+
token_endpoint=token_endpoint,
|
|
299
|
+
curl_runner=curl_runner)
|
|
300
|
+
write_token(token, token_path)
|
|
301
|
+
return token
|
|
@@ -14,6 +14,9 @@ import threading
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
16
|
from agentic_dev_loop.core.config import PipelineConfig, load_config
|
|
17
|
+
from .claude_auth import TOKEN_PATH as CLAUDE_TOKEN_PATH
|
|
18
|
+
from .claude_auth import ClaudeAuthError
|
|
19
|
+
from .claude_auth import login as claude_login
|
|
17
20
|
from .copilot_auth import (TOKEN_PATH, CopilotAuthError, list_copilot_models,
|
|
18
21
|
login, read_token)
|
|
19
22
|
from .containers import containers_report
|
|
@@ -35,6 +38,7 @@ a loud error). Run `agentic-dev-loop <PIPELINE> --help` for
|
|
|
35
38
|
loader-contributed options (e.g. --plan, --aidlc-unit).
|
|
36
39
|
|
|
37
40
|
commands:
|
|
41
|
+
claude-login Run the Claude OAuth PKCE flow and store the token.
|
|
38
42
|
containers Inspect engine sandbox containers and networks.
|
|
39
43
|
copilot-login Run the GitHub device flow and store the Copilot OAuth token.
|
|
40
44
|
copilot-models List the Copilot models available to this token's tier.
|
|
@@ -192,8 +196,31 @@ def _print_containers_report(report) -> None:
|
|
|
192
196
|
f"run={run} pid={pid_s}")
|
|
193
197
|
|
|
194
198
|
|
|
195
|
-
def _token_path(value: str | None) -> Path:
|
|
196
|
-
return Path(value).expanduser() if value else
|
|
199
|
+
def _token_path(value: str | None, default: Path = TOKEN_PATH) -> Path:
|
|
200
|
+
return Path(value).expanduser() if value else default.expanduser()
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _claude_login_parser() -> argparse.ArgumentParser:
|
|
204
|
+
parser = argparse.ArgumentParser(
|
|
205
|
+
prog="agentic-dev-loop claude-login",
|
|
206
|
+
description="Run the Claude subscription OAuth flow and store the "
|
|
207
|
+
"token.")
|
|
208
|
+
parser.add_argument("--token-file", default=None,
|
|
209
|
+
help="token path (default: "
|
|
210
|
+
"~/.agentic-dev-loop/auth/claude.json)")
|
|
211
|
+
return parser
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _run_claude_login(argv: list[str]) -> int:
|
|
215
|
+
args = _claude_login_parser().parse_args(argv)
|
|
216
|
+
path = _token_path(args.token_file, CLAUDE_TOKEN_PATH)
|
|
217
|
+
try:
|
|
218
|
+
claude_login(token_path=path)
|
|
219
|
+
except ClaudeAuthError as e:
|
|
220
|
+
print(f"claude-login: {e}", file=sys.stderr)
|
|
221
|
+
return 1
|
|
222
|
+
print(f"Claude token written to {path}")
|
|
223
|
+
return 0
|
|
197
224
|
|
|
198
225
|
|
|
199
226
|
def _copilot_login_parser() -> argparse.ArgumentParser:
|
|
@@ -425,6 +452,8 @@ def main(argv: list[str] | None = None, *, keep_alive: bool = True) -> int:
|
|
|
425
452
|
return 2
|
|
426
453
|
print(_TOP_HELP)
|
|
427
454
|
return 0
|
|
455
|
+
if argv and argv[0] == "claude-login":
|
|
456
|
+
return _run_claude_login(argv[1:])
|
|
428
457
|
if argv and argv[0] == "containers":
|
|
429
458
|
return _run_containers(argv[1:])
|
|
430
459
|
if argv and argv[0] == "copilot-login":
|
|
@@ -48,6 +48,18 @@ def _reasoning_stripped_error(llm: LLM) -> RuntimeError:
|
|
|
48
48
|
)
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
def _with_billing_prefix(llm: LLM, out: list[dict]) -> list[dict]:
|
|
52
|
+
"""Claude subscription policy (provider_wire.py): the gateway demands an
|
|
53
|
+
``x-anthropic-billing-header`` entry in the FIRST system text block of
|
|
54
|
+
every request (else 429). The adapter-carried prefix lands as its own
|
|
55
|
+
system dict at index 0, ahead of the pipeline's real system prompt;
|
|
56
|
+
litellm preserves system-message order into the Messages API body."""
|
|
57
|
+
prefix = getattr(llm, "_agentic_dev_loop_system_prefix", None)
|
|
58
|
+
if prefix:
|
|
59
|
+
out.insert(0, {"role": "system", "content": prefix})
|
|
60
|
+
return out
|
|
61
|
+
|
|
62
|
+
|
|
51
63
|
if not getattr(_ORIGINAL_FORMAT_MESSAGES, "_agentic_dev_loop_reasoning_repair", False):
|
|
52
64
|
def _config_gated_reasoning_serializer(self, messages: list) -> list[dict]:
|
|
53
65
|
"""The engine-owned reasoning passback serializer (054 D8).
|
|
@@ -68,7 +80,7 @@ if not getattr(_ORIGINAL_FORMAT_MESSAGES, "_agentic_dev_loop_reasoning_repair",
|
|
|
68
80
|
raise _reasoning_stripped_error(self)
|
|
69
81
|
validate_string_tool_results(
|
|
70
82
|
messages, out, forced=bool(self.force_string_serializer))
|
|
71
|
-
return out
|
|
83
|
+
return _with_billing_prefix(self, out)
|
|
72
84
|
|
|
73
85
|
last = None
|
|
74
86
|
for msg, d in zip(messages, out):
|
|
@@ -87,7 +99,7 @@ if not getattr(_ORIGINAL_FORMAT_MESSAGES, "_agentic_dev_loop_reasoning_repair",
|
|
|
87
99
|
d["reasoning_content"] = rc
|
|
88
100
|
validate_string_tool_results(
|
|
89
101
|
messages, out, forced=bool(self.force_string_serializer))
|
|
90
|
-
return out
|
|
102
|
+
return _with_billing_prefix(self, out)
|
|
91
103
|
|
|
92
104
|
_config_gated_reasoning_serializer._agentic_dev_loop_reasoning_repair = True
|
|
93
105
|
LLM.format_messages_for_llm = _config_gated_reasoning_serializer
|
|
@@ -161,10 +173,11 @@ def build_llm(cfg: LlmConfig, reasoning_effort: str | None = None) -> LLM:
|
|
|
161
173
|
# off. reasoning_effort is always passed (None when unset) so the SDK
|
|
162
174
|
# "high" default cannot engage; absent effort = reasoning off.
|
|
163
175
|
effort = reasoning_effort if reasoning_effort is not None else cfg.reasoning_effort
|
|
164
|
-
#
|
|
176
|
+
# Gateway policy (provider_wire.py): the Copilot gateway silently drops
|
|
165
177
|
# ARRAY-encoded tool-result content, so Copilot-configured instances
|
|
166
|
-
# force the SDK's documented string content serializer.
|
|
167
|
-
#
|
|
178
|
+
# force the SDK's documented string content serializer. The Claude
|
|
179
|
+
# subscription endpoint keeps the SDK default (None = auto-detect by
|
|
180
|
+
# model registry) and carries the billing-header system prefix instead.
|
|
168
181
|
adapter = adapter_for(cfg.base_url)
|
|
169
182
|
llm = LLM(
|
|
170
183
|
model=cfg.model,
|
|
@@ -178,4 +191,6 @@ def build_llm(cfg: LlmConfig, reasoning_effort: str | None = None) -> LLM:
|
|
|
178
191
|
llm._agentic_dev_loop_reasoning_effort = effort
|
|
179
192
|
llm._agentic_dev_loop_merge_choices = (
|
|
180
193
|
adapter.merge_choices if adapter else False)
|
|
194
|
+
llm._agentic_dev_loop_system_prefix = (
|
|
195
|
+
adapter.system_prefix if adapter else None)
|
|
181
196
|
return llm
|
{agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/provider_wire.py
RENAMED
|
@@ -7,8 +7,9 @@ ARRAY-encoded tool-result content (probe-proven 2026-11-06: string tool
|
|
|
7
7
|
content is answered, array tool content is invisible to the model - see
|
|
8
8
|
aidlc-docs/audit.md). The SDK's own remedy is its documented
|
|
9
9
|
``force_string_serializer`` field on LLM, so this module is POLICY ONLY:
|
|
10
|
-
which gateway base URL requires which wire shape
|
|
11
|
-
policy
|
|
10
|
+
which gateway base URL requires which wire shape, plus the one Claude
|
|
11
|
+
subscription policy (the billing-header system prefix). ``build_llm`` applies
|
|
12
|
+
the policy to every instance it builds. Nothing is monkeypatched.
|
|
12
13
|
"""
|
|
13
14
|
|
|
14
15
|
from __future__ import annotations
|
|
@@ -17,20 +18,54 @@ from dataclasses import dataclass
|
|
|
17
18
|
|
|
18
19
|
from agentic_dev_loop.engine.copilot_auth import COPILOT_BASE_URL
|
|
19
20
|
|
|
21
|
+
# The Anthropic subscription endpoint. An llm block points its base_url at
|
|
22
|
+
# this exact value: litellm routes bare claude-* model names through its
|
|
23
|
+
# native Anthropic provider path (Messages API, Bearer auth auto-detected
|
|
24
|
+
# from a ``sk-ant-oat01-`` token), and the adapter keyed below engages.
|
|
25
|
+
# No /v1 suffix: litellm appends /v1/messages to a base URL that does not
|
|
26
|
+
# already end with it (a /v1 value would 404 on /v1/v1/messages).
|
|
27
|
+
CLAUDE_BASE_URL = "https://api.anthropic.com"
|
|
28
|
+
|
|
29
|
+
# Anthropic's gateway only accepts OAuth-subscription traffic that is shaped
|
|
30
|
+
# like a Claude Code request. The gate is the FIRST system text block: it
|
|
31
|
+
# must carry an ``x-anthropic-billing-header:`` entry, or the endpoint
|
|
32
|
+
# answers 429 rate_limit_error regardless of every other header and body
|
|
33
|
+
# field (probe-proven 2026-11-13 against the live endpoint: only the
|
|
34
|
+
# system field moved the replay between 200 and 429). The field values are
|
|
35
|
+
# unvalidated with one exception, cc_version: models that require a newer
|
|
36
|
+
# Claude Code are refused with claude_code_version_too_old, so pin the
|
|
37
|
+
# current CLI version and bump it when the gateway demands newer.
|
|
38
|
+
CLAUDE_BILLING_HEADER = (
|
|
39
|
+
"x-anthropic-billing-header: cc_version=2.1.323.c04; "
|
|
40
|
+
"cc_entrypoint=sdk-cli; cc_turn_origin=cli;"
|
|
41
|
+
)
|
|
42
|
+
|
|
20
43
|
|
|
21
44
|
@dataclass(frozen=True)
|
|
22
45
|
class WireAdapter:
|
|
23
|
-
"""
|
|
46
|
+
"""Provider policy ``build_llm`` applies to every instance it builds.
|
|
47
|
+
|
|
48
|
+
``system_prefix`` (Claude subscription): a system message prepended
|
|
49
|
+
ahead of the pipeline's real system prompt on every outgoing request."""
|
|
24
50
|
|
|
25
51
|
name: str
|
|
26
52
|
force_string_serializer: bool
|
|
27
53
|
merge_choices: bool = False
|
|
54
|
+
system_prefix: str | None = None
|
|
28
55
|
|
|
29
56
|
|
|
30
57
|
copilot_strings = WireAdapter(name="copilot-strings", force_string_serializer=True,
|
|
31
58
|
merge_choices=True)
|
|
32
59
|
|
|
33
|
-
|
|
60
|
+
claude_subscription = WireAdapter(name="claude-subscription",
|
|
61
|
+
force_string_serializer=False,
|
|
62
|
+
merge_choices=False,
|
|
63
|
+
system_prefix=CLAUDE_BILLING_HEADER)
|
|
64
|
+
|
|
65
|
+
WIRE_ADAPTERS: dict[str, WireAdapter] = {
|
|
66
|
+
COPILOT_BASE_URL: copilot_strings,
|
|
67
|
+
CLAUDE_BASE_URL: claude_subscription,
|
|
68
|
+
}
|
|
34
69
|
|
|
35
70
|
|
|
36
71
|
def adapter_for(base_url: str | None) -> WireAdapter | None:
|
|
@@ -44,6 +79,8 @@ def provider_name(base_url: str | None) -> str:
|
|
|
44
79
|
"""Display name of the LLM provider behind a base URL."""
|
|
45
80
|
if base_url is not None and base_url.rstrip("/") == COPILOT_BASE_URL:
|
|
46
81
|
return "Copilot"
|
|
82
|
+
if base_url is not None and base_url.rstrip("/") == CLAUDE_BASE_URL:
|
|
83
|
+
return "Claude"
|
|
47
84
|
return "OpenAI"
|
|
48
85
|
|
|
49
86
|
|
{agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop/engine/secrets.py
RENAMED
|
@@ -77,13 +77,15 @@ class FileProvider:
|
|
|
77
77
|
if not path.is_file():
|
|
78
78
|
raise SecretResolutionError(
|
|
79
79
|
f"secret file not found: {path} - run "
|
|
80
|
-
"`agentic-dev-loop copilot-login`
|
|
80
|
+
"`agentic-dev-loop copilot-login` (Copilot) or "
|
|
81
|
+
"`agentic-dev-loop claude-login` (Claude) to create it")
|
|
81
82
|
try:
|
|
82
83
|
text = path.read_text(encoding="utf-8")
|
|
83
84
|
except OSError as e:
|
|
84
85
|
raise SecretResolutionError(
|
|
85
|
-
f"secret file unreadable: {path}: {e} - run "
|
|
86
|
-
"`agentic-dev-loop copilot-login`
|
|
86
|
+
f"secret file unreadable: {path}: {e} - run the matching "
|
|
87
|
+
"login subcommand (`agentic-dev-loop copilot-login` or "
|
|
88
|
+
"`agentic-dev-loop claude-login`) to recreate it") from e
|
|
87
89
|
if json_key is None:
|
|
88
90
|
return text.strip()
|
|
89
91
|
try:
|
{agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/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.0rc3
|
|
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
|
|
@@ -44,6 +44,7 @@ Requires-Dist: hypothesis>=6.0; extra == "dev"
|
|
|
44
44
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
45
45
|
Requires-Dist: pip-audit>=2.0; extra == "dev"
|
|
46
46
|
Requires-Dist: pre-commit>=3.0; extra == "dev"
|
|
47
|
+
Requires-Dist: setuptools>=78.1.1; extra == "dev"
|
|
47
48
|
Provides-Extra: docs
|
|
48
49
|
Requires-Dist: mkdocs-material~=9.6; extra == "docs"
|
|
49
50
|
Requires-Dist: pymdown-extensions~=10.0; extra == "docs"
|
|
@@ -108,7 +109,7 @@ Docker engine does:
|
|
|
108
109
|
| --- | --- |
|
|
109
110
|
| Python | >= 3.12 |
|
|
110
111
|
| 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. |
|
|
111
|
-
| 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. Alternatively, `agentic-dev-loop copilot-login` authenticates a Copilot subscription (see [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/)). |
|
|
112
|
+
| 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. Alternatively, `agentic-dev-loop copilot-login` authenticates a Copilot subscription, and a Claude Pro or Max subscription runs on Anthropic's own endpoint after `agentic-dev-loop claude-login` (see [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/)). |
|
|
112
113
|
|
|
113
114
|
### Installation
|
|
114
115
|
|
|
@@ -181,7 +182,7 @@ policy, named LLM profiles - is in the
|
|
|
181
182
|
| [Architecture](https://lukedawilson.github.io/agentic-dev-loop/architecture/) | The five layers, one full run end to end, and the host-boundary security model |
|
|
182
183
|
| [CLI](https://lukedawilson.github.io/agentic-dev-loop/cli/) | Run flags, resuming, the live view, reports, container management, and onboarding commands |
|
|
183
184
|
| [pipeline.yaml](https://lukedawilson.github.io/agentic-dev-loop/pipeline/) | The complete configuration reference: steps, isolation, secrets, networking, dependency policy |
|
|
184
|
-
| [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/) | OpenAI-compatible endpoints (OpenAI, DeepSeek, and others)
|
|
185
|
+
| [LLM providers](https://lukedawilson.github.io/agentic-dev-loop/llm-providers/) | OpenAI-compatible endpoints (OpenAI, DeepSeek, and others), the GitHub Copilot subscription, and the Claude subscription |
|
|
185
186
|
| [Authoring a loop](https://lukedawilson.github.io/agentic-dev-loop/authoring/) | From `init` to a committed pipeline: agent files, stage lineup, adaptation checklist |
|
|
186
187
|
| [Setup and troubleshooting](https://lukedawilson.github.io/agentic-dev-loop/setup/) | Docker engines, the dev image, caching, error codes |
|
|
187
188
|
| [Browser sandbox](https://lukedawilson.github.io/agentic-dev-loop/browser-sandbox/) | Running a browser inside the sandbox |
|
{agentic_dev_loop-1.0.0rc2 → agentic_dev_loop-1.0.0rc3}/src/agentic_dev_loop.egg-info/SOURCES.txt
RENAMED
|
@@ -27,6 +27,7 @@ src/agentic_dev_loop/engine/allowlist.py
|
|
|
27
27
|
src/agentic_dev_loop/engine/brief_coverage.py
|
|
28
28
|
src/agentic_dev_loop/engine/brief_prompt.md
|
|
29
29
|
src/agentic_dev_loop/engine/brief_prompt.py
|
|
30
|
+
src/agentic_dev_loop/engine/claude_auth.py
|
|
30
31
|
src/agentic_dev_loop/engine/cli.py
|
|
31
32
|
src/agentic_dev_loop/engine/completion.py
|
|
32
33
|
src/agentic_dev_loop/engine/containers.py
|
|
@@ -159,6 +160,8 @@ tests/test_agent_error_guide.py
|
|
|
159
160
|
tests/test_agents.py
|
|
160
161
|
tests/test_aidlc.py
|
|
161
162
|
tests/test_build_viz_page.py
|
|
163
|
+
tests/test_claude_auth.py
|
|
164
|
+
tests/test_claude_cli.py
|
|
162
165
|
tests/test_cli.py
|
|
163
166
|
tests/test_config.py
|
|
164
167
|
tests/test_containers.py
|