agentpack-cli 0.3.22__tar.gz → 0.3.23__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.
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/PKG-INFO +10 -9
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/README.md +9 -8
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/pyproject.toml +1 -1
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/__init__.py +1 -1
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/ci_cmd.py +10 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/workflow_cmd.py +215 -8
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/config.py +5 -0
- agentpack_cli-0.3.23/src/agentpack/core/loop_protocol.py +873 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/dashboard/collectors.py +23 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/dashboard/models.py +11 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/dashboard/renderers.py +8 -2
- agentpack_cli-0.3.22/src/agentpack/core/loop_protocol.py +0 -349
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/.gitignore +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/LICENSE +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/antigravity.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/base.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/claude.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/codex.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/cursor.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/detect.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/generic.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/windsurf.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/dependency_graph.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/go_imports.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/java_imports.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/js_ts_imports.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/monorepo.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/naming_signals.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/python_ast.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/python_imports.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/ranking.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/repo_map.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/role_inference.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/rust_imports.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/symbols.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/task_classifier.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/tests.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/application/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/application/pack_service.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/cli.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/_shared.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/benchmark.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/claude_cmd.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/compress_output.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/dashboard.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/dev_check.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/diagnose_selection.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/diff.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/doctor.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/eval_cmd.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/explain.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/guard.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/hook_cmd.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/ignore_cmd.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/init.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/install.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/learn.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/mcp_cmd.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/memory.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/migrate.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/monitor.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/next_cmd.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/pack.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/perf.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/quickstart.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/release_check.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/release_cmd.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/repair.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/retrieve.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/route.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/scan.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/skills.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/start_cmd.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/state_cmd.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/stats.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/status.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/summarize.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/task_cmd.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/threads.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/tune.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/verify_wheel.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/watch.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/wrap.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/bootstrap.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/cache.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/changed_paths.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/context_pack.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/diff.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/evals.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/execution_state.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/git.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/git_hooks.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/global_install.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/ignore.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/merkle.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/models.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/modes.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/pack_registry.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/redactor.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/scanner.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/snapshot.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/task_freshness.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/thread_context.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/token_estimator.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/vscode_tasks.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/dashboard/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/data/agentpack.md +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/antigravity.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/claude.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/codex.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/cursor.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/windsurf.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/agents.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/git_hooks.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/global_install.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/platform.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/vscode_tasks.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/collector.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/extractor.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/feedback.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/lesson_ranker.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/models.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/provider.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/quality.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/renderers.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/skill_map.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/mcp_server.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/output_compression/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/output_compression/core.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/renderers/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/renderers/compact.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/renderers/markdown.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/renderers/receipts.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/discovery.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/models.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/parser.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/prompt_builder.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/scoring.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/service.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/skills_index.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/session/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/session/events.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/session/state.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/summaries/__init__.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/summaries/base.py +0 -0
- {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/summaries/offline.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentpack-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.23
|
|
4
4
|
Summary: Local context engine for AI coding agents that ranks relevant repo files and builds compact task-focused context packs for Claude Code, Codex, Cursor, Windsurf, MCP, and CI workflows.
|
|
5
5
|
Project-URL: Homepage, https://github.com/vishal2612200/agentpack
|
|
6
6
|
Project-URL: Documentation, https://vishal2612200.github.io/agentpack/
|
|
@@ -77,19 +77,20 @@ pipx run --spec agentpack-cli agentpack route --task "fix auth token expiry"
|
|
|
77
77
|
|
|
78
78
|

|
|
79
79
|
|
|
80
|
-
> **Status: alpha (v0.3.
|
|
80
|
+
> **Status: alpha (v0.3.23).** Works, tested, and used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Current benchmarks are useful regression checks, not broad proof that AgentPack improves coding-agent success. API may change before 1.0.
|
|
81
81
|
>
|
|
82
82
|
> **Platform note:** macOS, Linux, and Windows are supported. Windows support targets PowerShell plus Git for Windows. `cmd.exe` and bare Git setups are not a supported path yet.
|
|
83
83
|
>
|
|
84
84
|
> **Name note:** PyPI package is `agentpack-cli`, npm package is `@vishal2612200/agentpack`, and the command is `agentpack`. This project is unrelated to AgentPack dataset papers or other repos with the same name.
|
|
85
85
|
|
|
86
|
-
## What's New in 0.3.
|
|
86
|
+
## What's New in 0.3.23
|
|
87
87
|
|
|
88
|
-
`0.3.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
`0.3.23` is a guarded-loop hardening release. It keeps AgentPack's core promise
|
|
89
|
+
focused on local context and workflow evidence while making `agentpack work --run`
|
|
90
|
+
an optional proof harness around existing agents. The loop now has known runner
|
|
91
|
+
adapters, smoke checks, phase/diff/risk/acceptance artifacts, rollback patches,
|
|
92
|
+
metrics, and stricter finish gates. The prior expanded public-suite baseline
|
|
93
|
+
remains **66.0% recall / 51.1% token precision** across 108 scored public cases.
|
|
93
94
|
|
|
94
95
|
## Core Workflow
|
|
95
96
|
|
|
@@ -245,7 +246,7 @@ agentpack status
|
|
|
245
246
|
agentpack finish --since main
|
|
246
247
|
```
|
|
247
248
|
|
|
248
|
-
Use `agentpack quickstart --task "..." --write` when you want AgentPack to print the next commands and write the task file for you. Use `agentpack start "..." --pack-only` when you want only a fresh pack and not the guard path.
|
|
249
|
+
Use `agentpack quickstart --task "..." --write` when you want AgentPack to print the next commands and write the task file for you. Use `agentpack start "..." --pack-only` when you want only a fresh pack and not the guard path. Optional guardrail: `agentpack work --run` is a proof harness around existing agents, not AgentPack's default workflow or an autonomous coding agent.
|
|
249
250
|
|
|
250
251
|
### Learn from AI-assisted work
|
|
251
252
|
|
|
@@ -30,19 +30,20 @@ pipx run --spec agentpack-cli agentpack route --task "fix auth token expiry"
|
|
|
30
30
|
|
|
31
31
|

|
|
32
32
|
|
|
33
|
-
> **Status: alpha (v0.3.
|
|
33
|
+
> **Status: alpha (v0.3.23).** Works, tested, and used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Current benchmarks are useful regression checks, not broad proof that AgentPack improves coding-agent success. API may change before 1.0.
|
|
34
34
|
>
|
|
35
35
|
> **Platform note:** macOS, Linux, and Windows are supported. Windows support targets PowerShell plus Git for Windows. `cmd.exe` and bare Git setups are not a supported path yet.
|
|
36
36
|
>
|
|
37
37
|
> **Name note:** PyPI package is `agentpack-cli`, npm package is `@vishal2612200/agentpack`, and the command is `agentpack`. This project is unrelated to AgentPack dataset papers or other repos with the same name.
|
|
38
38
|
|
|
39
|
-
## What's New in 0.3.
|
|
39
|
+
## What's New in 0.3.23
|
|
40
40
|
|
|
41
|
-
`0.3.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
`0.3.23` is a guarded-loop hardening release. It keeps AgentPack's core promise
|
|
42
|
+
focused on local context and workflow evidence while making `agentpack work --run`
|
|
43
|
+
an optional proof harness around existing agents. The loop now has known runner
|
|
44
|
+
adapters, smoke checks, phase/diff/risk/acceptance artifacts, rollback patches,
|
|
45
|
+
metrics, and stricter finish gates. The prior expanded public-suite baseline
|
|
46
|
+
remains **66.0% recall / 51.1% token precision** across 108 scored public cases.
|
|
46
47
|
|
|
47
48
|
## Core Workflow
|
|
48
49
|
|
|
@@ -198,7 +199,7 @@ agentpack status
|
|
|
198
199
|
agentpack finish --since main
|
|
199
200
|
```
|
|
200
201
|
|
|
201
|
-
Use `agentpack quickstart --task "..." --write` when you want AgentPack to print the next commands and write the task file for you. Use `agentpack start "..." --pack-only` when you want only a fresh pack and not the guard path.
|
|
202
|
+
Use `agentpack quickstart --task "..." --write` when you want AgentPack to print the next commands and write the task file for you. Use `agentpack start "..." --pack-only` when you want only a fresh pack and not the guard path. Optional guardrail: `agentpack work --run` is a proof harness around existing agents, not AgentPack's default workflow or an autonomous coding agent.
|
|
202
203
|
|
|
203
204
|
### Learn from AI-assisted work
|
|
204
205
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "agentpack-cli"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.23"
|
|
4
4
|
description = "Local context engine for AI coding agents that ranks relevant repo files and builds compact task-focused context packs for Claude Code, Codex, Cursor, Windsurf, MCP, and CI workflows."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -64,6 +64,16 @@ jobs:
|
|
|
64
64
|
- run: python -m pip install -e ".[dev]"
|
|
65
65
|
- run: python -m agentpack.cli dev-check
|
|
66
66
|
|
|
67
|
+
loop-smoke:
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@v4
|
|
71
|
+
- uses: actions/setup-python@v5
|
|
72
|
+
with:
|
|
73
|
+
python-version: "3.11"
|
|
74
|
+
- run: python -m pip install -e ".[dev]"
|
|
75
|
+
- run: python -m agentpack.cli loop-smoke --json
|
|
76
|
+
|
|
67
77
|
release-gate:
|
|
68
78
|
runs-on: ubuntu-latest
|
|
69
79
|
if: github.event_name == 'push'
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import subprocess
|
|
5
|
+
import tempfile
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Any
|
|
7
8
|
|
|
@@ -17,6 +18,7 @@ from agentpack.core.loop_protocol import (
|
|
|
17
18
|
initialize_loop,
|
|
18
19
|
load_loop_state,
|
|
19
20
|
mark_done,
|
|
21
|
+
resolve_runner_adapter,
|
|
20
22
|
run_loop,
|
|
21
23
|
)
|
|
22
24
|
from agentpack.core.thread_context import resolve_thread_option
|
|
@@ -35,11 +37,13 @@ def register(app: typer.Typer) -> None:
|
|
|
35
37
|
pack_only: bool = typer.Option(False, "--pack-only", help="Run pack directly instead of guard."),
|
|
36
38
|
no_init: bool = typer.Option(False, "--no-init", help="Do not initialize the repo when .agentpack/config.toml is missing."),
|
|
37
39
|
no_next: bool = typer.Option(False, "--no-next", help="Do not print next-step diagnostics after context refresh."),
|
|
38
|
-
run_loop_requested: bool = typer.Option(False, "--run", help="Run the
|
|
39
|
-
dry_run: bool = typer.Option(False, "--dry-run", help="Plan
|
|
40
|
-
runner: str = typer.Option("", "--runner", help="Generic shell command for the
|
|
40
|
+
run_loop_requested: bool = typer.Option(False, "--run", help="Run the optional guarded loop after preparing context."),
|
|
41
|
+
dry_run: bool = typer.Option(False, "--dry-run", help="Plan guarded-loop execution without running the configured runner."),
|
|
42
|
+
runner: str = typer.Option("", "--runner", help="Generic shell command for the optional guarded-loop runner."),
|
|
43
|
+
runner_adapter: str = typer.Option("", "--runner-adapter", help="Resolve runner command from a known adapter: claude, codex, cursor."),
|
|
41
44
|
max_iterations: int = typer.Option(0, "--max-iterations", help="Override [loop].max_iterations for this run."),
|
|
42
|
-
verify: list[str] = typer.Option([], "--verify", help="Verification command for
|
|
45
|
+
verify: list[str] = typer.Option([], "--verify", help="Verification command for the guarded loop. Repeatable."),
|
|
46
|
+
acceptance: list[str] = typer.Option([], "--acceptance", help="Semantic acceptance check for runner contract. Repeatable."),
|
|
43
47
|
json_output: bool = typer.Option(False, "--json", help="Emit JSON."),
|
|
44
48
|
) -> None:
|
|
45
49
|
"""Initialize if needed, write a task, refresh context, and show next steps."""
|
|
@@ -73,10 +77,13 @@ def register(app: typer.Typer) -> None:
|
|
|
73
77
|
root,
|
|
74
78
|
task_text,
|
|
75
79
|
cfg.loop,
|
|
76
|
-
runner_override=runner,
|
|
80
|
+
runner_override=runner or _resolve_runner_adapter(runner_adapter, root),
|
|
77
81
|
max_iterations_override=max_iterations,
|
|
78
82
|
verification_overrides=list(verify) if verify else None,
|
|
83
|
+
acceptance_overrides=list(acceptance) if acceptance else None,
|
|
79
84
|
)
|
|
85
|
+
if runner_adapter:
|
|
86
|
+
state.runner_adapter = runner_adapter
|
|
80
87
|
if dry_run:
|
|
81
88
|
loop_plan = dry_run_plan(root, state).model_dump(mode="json")
|
|
82
89
|
_finish(stages, json_output, loop_plan=loop_plan)
|
|
@@ -105,6 +112,7 @@ def register(app: typer.Typer) -> None:
|
|
|
105
112
|
skip_benchmark_capture: bool = typer.Option(False, "--skip-benchmark-capture", help="Skip benchmark case capture."),
|
|
106
113
|
archive_thread: bool = typer.Option(False, "--archive-thread", help="Archive the thread after marking state done."),
|
|
107
114
|
allow_empty_capture: bool = typer.Option(False, "--allow-empty-capture", help="Allow benchmark capture with no expected files."),
|
|
115
|
+
allow_high_risk: bool = typer.Option(False, "--allow-high-risk", help="Allow finish after inspecting a high-risk Ralph Loop diff."),
|
|
108
116
|
json_output: bool = typer.Option(False, "--json", help="Emit JSON."),
|
|
109
117
|
) -> None:
|
|
110
118
|
"""Run finish checks, capture benchmark evidence, and mark work done."""
|
|
@@ -115,7 +123,7 @@ def register(app: typer.Typer) -> None:
|
|
|
115
123
|
finish_task = task or _read_task(root, thread) or (loop_state.task if loop_state else "")
|
|
116
124
|
loop_applies = loop_state is not None and cfg.loop.enabled and (not finish_task or finish_task == loop_state.task)
|
|
117
125
|
if loop_applies:
|
|
118
|
-
blockers = _loop_finish_blockers(root, cfg.loop, loop_state, thread)
|
|
126
|
+
blockers = _loop_finish_blockers(root, cfg.loop, loop_state, thread, allow_empty_diff=allow_empty_capture, allow_high_risk=allow_high_risk)
|
|
119
127
|
if blockers:
|
|
120
128
|
_finish_blocked(blockers, json_output)
|
|
121
129
|
raise typer.Exit(1)
|
|
@@ -146,6 +154,106 @@ def register(app: typer.Typer) -> None:
|
|
|
146
154
|
stages.append(_run("threads-archive", cli_module_argv("threads", "archive", thread_id, "--summary", summary), root))
|
|
147
155
|
_finish(stages, json_output)
|
|
148
156
|
|
|
157
|
+
@app.command("loop-smoke")
|
|
158
|
+
def loop_smoke(
|
|
159
|
+
runner: str = typer.Option("", "--runner", help="Runner command to test against a tiny fixture repo."),
|
|
160
|
+
runner_adapter: str = typer.Option("", "--runner-adapter", help="Resolve runner command from a known adapter."),
|
|
161
|
+
json_output: bool = typer.Option(False, "--json", help="Emit JSON."),
|
|
162
|
+
) -> None:
|
|
163
|
+
"""Run an optional guarded-loop smoke test in a temporary fixture repo."""
|
|
164
|
+
with tempfile.TemporaryDirectory(prefix="agentpack-loop-smoke-") as raw:
|
|
165
|
+
root = Path(raw)
|
|
166
|
+
_seed_loop_smoke_repo(root)
|
|
167
|
+
resolved_runner = runner or _resolve_runner_adapter(runner_adapter, root) or _deterministic_smoke_runner(root)
|
|
168
|
+
state = initialize_loop(
|
|
169
|
+
root,
|
|
170
|
+
"make the smoke test pass by changing app.py value to 2",
|
|
171
|
+
load_config(root).loop,
|
|
172
|
+
runner_override=resolved_runner,
|
|
173
|
+
verification_overrides=["python -m pytest -q"],
|
|
174
|
+
acceptance_overrides=["smoke test passes"],
|
|
175
|
+
max_iterations_override=2,
|
|
176
|
+
)
|
|
177
|
+
summary = run_loop(root, state, refresh=lambda: LoopCommandResult(command="smoke-refresh", returncode=0, output_excerpt="ok"))
|
|
178
|
+
payload = {
|
|
179
|
+
"passed": summary.status == "ready_to_finish",
|
|
180
|
+
"summary": summary.model_dump(mode="json"),
|
|
181
|
+
"runner": resolved_runner,
|
|
182
|
+
}
|
|
183
|
+
latest = load_loop_state(root)
|
|
184
|
+
if latest is not None and latest.last_runner is not None:
|
|
185
|
+
payload["runner_output_excerpt"] = latest.last_runner.output_excerpt
|
|
186
|
+
if latest is not None:
|
|
187
|
+
payload["failure_class"] = latest.failure_class
|
|
188
|
+
if json_output:
|
|
189
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
190
|
+
else:
|
|
191
|
+
marker = "[green]✓[/]" if payload["passed"] else "[red]✗[/]"
|
|
192
|
+
console.print(f"{marker} loop smoke {summary.status}")
|
|
193
|
+
console.print(f"runner: [bold]{resolved_runner}[/]")
|
|
194
|
+
if summary.status != "ready_to_finish":
|
|
195
|
+
raise typer.Exit(1)
|
|
196
|
+
|
|
197
|
+
@app.command("loop-rollback")
|
|
198
|
+
def loop_rollback(
|
|
199
|
+
iteration: int = typer.Option(0, "--iteration", help="Rollback patch iteration (0 = latest recorded)."),
|
|
200
|
+
json_output: bool = typer.Option(False, "--json", help="Emit JSON."),
|
|
201
|
+
) -> None:
|
|
202
|
+
"""Restore the worktree to the latest recorded guarded-loop rollback patch."""
|
|
203
|
+
root = _root()
|
|
204
|
+
state = load_loop_state(root)
|
|
205
|
+
patch = _loop_rollback_patch(root, state, iteration)
|
|
206
|
+
payload = {"patch": str(patch.relative_to(root)) if patch else "", "applied": False}
|
|
207
|
+
current = subprocess.run(["git", "diff", "--binary"], cwd=root, capture_output=True, text=True)
|
|
208
|
+
if current.stdout.strip():
|
|
209
|
+
reverse = subprocess.run(["git", "apply", "-R", "-"], input=current.stdout, cwd=root, capture_output=True, text=True)
|
|
210
|
+
if reverse.returncode != 0:
|
|
211
|
+
payload["reason"] = reverse.stderr.strip() or "failed to reverse current diff"
|
|
212
|
+
if json_output:
|
|
213
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
214
|
+
return
|
|
215
|
+
console.print(f"[red]Rollback failed:[/] {payload['reason']}")
|
|
216
|
+
raise typer.Exit(1)
|
|
217
|
+
payload["applied"] = True
|
|
218
|
+
elif not patch:
|
|
219
|
+
payload["reason"] = "no rollback patch found and worktree has no tracked diff"
|
|
220
|
+
if json_output:
|
|
221
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
222
|
+
return
|
|
223
|
+
console.print("[yellow]No rollback patch found and worktree has no tracked diff.[/]")
|
|
224
|
+
return
|
|
225
|
+
if not patch:
|
|
226
|
+
if json_output:
|
|
227
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
228
|
+
return
|
|
229
|
+
console.print("[green]✓[/] Reversed current tracked diff")
|
|
230
|
+
return
|
|
231
|
+
apply_result = subprocess.run(["git", "apply", str(patch)], cwd=root, capture_output=True, text=True)
|
|
232
|
+
payload["applied"] = apply_result.returncode == 0
|
|
233
|
+
if apply_result.returncode != 0:
|
|
234
|
+
payload["reason"] = apply_result.stderr.strip() or "failed to apply rollback patch"
|
|
235
|
+
if json_output:
|
|
236
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
237
|
+
return
|
|
238
|
+
console.print(f"[red]Rollback failed:[/] {payload['reason']}")
|
|
239
|
+
raise typer.Exit(1)
|
|
240
|
+
if json_output:
|
|
241
|
+
typer.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
242
|
+
return
|
|
243
|
+
console.print(f"[green]✓[/] Applied rollback patch {payload['patch']}")
|
|
244
|
+
|
|
245
|
+
@app.command("loop-metrics")
|
|
246
|
+
def loop_metrics(json_output: bool = typer.Option(False, "--json", help="Emit JSON.")) -> None:
|
|
247
|
+
"""Summarize guarded-loop outcomes over time."""
|
|
248
|
+
root = _root()
|
|
249
|
+
rows = _read_loop_metrics(root)
|
|
250
|
+
summary = _summarize_loop_metrics(rows)
|
|
251
|
+
if json_output:
|
|
252
|
+
typer.echo(json.dumps(summary, indent=2, sort_keys=True))
|
|
253
|
+
return
|
|
254
|
+
console.print(f"Runs: [bold]{summary['runs']}[/]")
|
|
255
|
+
console.print(f"Ready: [green]{summary['ready_to_finish']}[/] Blocked: [yellow]{summary['blocked']}[/] Done: [green]{summary['done']}[/]")
|
|
256
|
+
|
|
149
257
|
|
|
150
258
|
def _run(name: str, command: list[str], root: Path) -> dict[str, Any]:
|
|
151
259
|
result = subprocess.run(command, cwd=root, capture_output=True, text=True)
|
|
@@ -190,8 +298,19 @@ def _finish(
|
|
|
190
298
|
raise typer.Exit(1)
|
|
191
299
|
|
|
192
300
|
|
|
193
|
-
def _loop_finish_blockers(
|
|
194
|
-
|
|
301
|
+
def _loop_finish_blockers(
|
|
302
|
+
root: Path,
|
|
303
|
+
loop_cfg,
|
|
304
|
+
loop_state,
|
|
305
|
+
thread: str,
|
|
306
|
+
*,
|
|
307
|
+
allow_empty_diff: bool = False,
|
|
308
|
+
allow_high_risk: bool = False,
|
|
309
|
+
) -> list[dict[str, Any]]:
|
|
310
|
+
blockers = [
|
|
311
|
+
blocker.model_dump(mode="json")
|
|
312
|
+
for blocker in finish_blockers(root, loop_cfg, loop_state, allow_empty_diff=allow_empty_diff, allow_high_risk=allow_high_risk)
|
|
313
|
+
]
|
|
195
314
|
fresh, reason = _context_is_fresh(root, thread_id=resolve_thread_option(thread))
|
|
196
315
|
if not fresh:
|
|
197
316
|
blockers.append(
|
|
@@ -204,6 +323,94 @@ def _loop_finish_blockers(root: Path, loop_cfg, loop_state, thread: str) -> list
|
|
|
204
323
|
return blockers
|
|
205
324
|
|
|
206
325
|
|
|
326
|
+
def _resolve_runner_adapter(adapter: str, root: Path) -> str:
|
|
327
|
+
if not adapter:
|
|
328
|
+
return ""
|
|
329
|
+
command = resolve_runner_adapter(adapter, root)
|
|
330
|
+
if not command:
|
|
331
|
+
console.print(f"[red]Runner adapter unavailable:[/] {adapter}")
|
|
332
|
+
raise typer.Exit(1)
|
|
333
|
+
return command
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def _seed_loop_smoke_repo(root: Path) -> None:
|
|
337
|
+
subprocess.run(["git", "init"], cwd=root, check=True, capture_output=True, text=True)
|
|
338
|
+
(root / ".agentpack").mkdir()
|
|
339
|
+
(root / ".agentpack" / "config.toml").write_text("[context]\n[loop]\nrequire_clean_tree = false\n", encoding="utf-8")
|
|
340
|
+
(root / ".agentpack" / "task.md").write_text("make smoke test pass\n", encoding="utf-8")
|
|
341
|
+
(root / "app.py").write_text("VALUE = 1\n", encoding="utf-8")
|
|
342
|
+
(root / "test_app.py").write_text("from app import VALUE\n\n\ndef test_value():\n assert VALUE == 2\n", encoding="utf-8")
|
|
343
|
+
subprocess.run(["git", "add", "app.py", "test_app.py"], cwd=root, check=True, capture_output=True, text=True)
|
|
344
|
+
subprocess.run(
|
|
345
|
+
["git", "-c", "user.email=test@example.com", "-c", "user.name=Test User", "commit", "-m", "init"],
|
|
346
|
+
cwd=root,
|
|
347
|
+
check=True,
|
|
348
|
+
capture_output=True,
|
|
349
|
+
text=True,
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def _deterministic_smoke_runner(root: Path) -> str:
|
|
354
|
+
script = root / "smoke_runner.py"
|
|
355
|
+
script.write_text(
|
|
356
|
+
"from pathlib import Path\n"
|
|
357
|
+
"Path('app.py').write_text('VALUE = 2\\n', encoding='utf-8')\n"
|
|
358
|
+
"print('{\"status\":\"changed\",\"summary\":\"updated app.py\",\"files_changed\":[\"app.py\"],\"acceptance\":{\"smoke test passes\":\"pass\"}}')\n",
|
|
359
|
+
encoding="utf-8",
|
|
360
|
+
)
|
|
361
|
+
return "python smoke_runner.py"
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def _loop_rollback_patch(root: Path, state, iteration: int) -> Path | None:
|
|
365
|
+
if iteration > 0:
|
|
366
|
+
candidate = root / ".agentpack" / "loop_rollback" / f"iteration-{iteration}-before.patch"
|
|
367
|
+
return candidate if candidate.exists() else None
|
|
368
|
+
if state is not None and state.rollback_patch:
|
|
369
|
+
candidate = root / state.rollback_patch
|
|
370
|
+
if candidate.exists():
|
|
371
|
+
return candidate
|
|
372
|
+
patches = sorted((root / ".agentpack" / "loop_rollback").glob("iteration-*-before.patch"))
|
|
373
|
+
return patches[-1] if patches else None
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _read_loop_metrics(root: Path) -> list[dict[str, Any]]:
|
|
377
|
+
path = root / ".agentpack" / "loop_metrics.jsonl"
|
|
378
|
+
if not path.exists():
|
|
379
|
+
return []
|
|
380
|
+
rows: list[dict[str, Any]] = []
|
|
381
|
+
for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
|
|
382
|
+
try:
|
|
383
|
+
value = json.loads(line)
|
|
384
|
+
except json.JSONDecodeError:
|
|
385
|
+
continue
|
|
386
|
+
if isinstance(value, dict):
|
|
387
|
+
rows.append(value)
|
|
388
|
+
return rows[-500:]
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _summarize_loop_metrics(rows: list[dict[str, Any]]) -> dict[str, Any]:
|
|
392
|
+
outcomes: dict[str, int] = {}
|
|
393
|
+
failure_classes: dict[str, int] = {}
|
|
394
|
+
total_iterations = 0
|
|
395
|
+
for row in rows:
|
|
396
|
+
outcome = str(row.get("outcome") or "unknown")
|
|
397
|
+
outcomes[outcome] = outcomes.get(outcome, 0) + 1
|
|
398
|
+
failure_class = str(row.get("failure_class") or "")
|
|
399
|
+
if failure_class:
|
|
400
|
+
failure_classes[failure_class] = failure_classes.get(failure_class, 0) + 1
|
|
401
|
+
total_iterations += int(row.get("iterations") or 0)
|
|
402
|
+
runs = len(rows)
|
|
403
|
+
return {
|
|
404
|
+
"runs": runs,
|
|
405
|
+
"ready_to_finish": outcomes.get("ready_to_finish", 0),
|
|
406
|
+
"blocked": outcomes.get("blocked", 0),
|
|
407
|
+
"done": outcomes.get("done", 0),
|
|
408
|
+
"outcomes": outcomes,
|
|
409
|
+
"failure_classes": failure_classes,
|
|
410
|
+
"avg_iterations": round(total_iterations / runs, 2) if runs else 0,
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
|
|
207
414
|
def _finish_blocked(blockers: list[dict[str, Any]], json_output: bool) -> None:
|
|
208
415
|
if json_output:
|
|
209
416
|
typer.echo(json.dumps({"passed": False, "stages": [], "loop_blockers": blockers}, indent=2, sort_keys=True))
|
|
@@ -76,8 +76,11 @@ class LearningConfig(BaseModel):
|
|
|
76
76
|
class LoopConfig(BaseModel):
|
|
77
77
|
enabled: bool = True
|
|
78
78
|
runner: str = ""
|
|
79
|
+
runner_adapter: str = ""
|
|
80
|
+
runner_prompt_output: str = ".agentpack/loop_runner_prompt.md"
|
|
79
81
|
max_iterations: int = 10
|
|
80
82
|
verification_commands: list[str] = Field(default_factory=list)
|
|
83
|
+
acceptance_checks: list[str] = Field(default_factory=list)
|
|
81
84
|
require_verification: bool = True
|
|
82
85
|
require_progress_update: bool = True
|
|
83
86
|
require_clean_tree: bool = True
|
|
@@ -86,6 +89,8 @@ class LoopConfig(BaseModel):
|
|
|
86
89
|
runner_timeout_seconds: int = 600
|
|
87
90
|
verification_timeout_seconds: int = 600
|
|
88
91
|
max_repeated_failures: int = 3
|
|
92
|
+
risk_sensitive_globs: list[str] = Field(default_factory=list)
|
|
93
|
+
risk_high_file_count: int = 20
|
|
89
94
|
|
|
90
95
|
|
|
91
96
|
class RuntimeConfig(BaseModel):
|