agentpack-cli 0.3.4__tar.gz → 0.3.5__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.4 → agentpack_cli-0.3.5}/PKG-INFO +79 -10
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/README.md +78 -9
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/pyproject.toml +1 -1
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/__init__.py +1 -1
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/application/pack_service.py +4 -14
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/cli.py +4 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/doctor.py +16 -0
- agentpack_cli-0.3.5/src/agentpack/commands/guard.py +129 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/hook_cmd.py +77 -25
- agentpack_cli-0.3.5/src/agentpack/commands/migrate.py +182 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/pack.py +42 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/status.py +11 -17
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/config.py +3 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/context_pack.py +9 -0
- agentpack_cli-0.3.5/src/agentpack/core/task_freshness.py +79 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/data/agentpack.md +5 -5
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/installers/antigravity.py +5 -4
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/installers/claude.py +15 -1
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/installers/codex.py +5 -4
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/installers/cursor.py +12 -10
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/installers/windsurf.py +6 -5
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/integrations/agents.py +85 -9
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/integrations/vscode_tasks.py +11 -2
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/mcp_server.py +36 -29
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/renderers/markdown.py +38 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/.gitignore +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/LICENSE +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/adapters/__init__.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/adapters/antigravity.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/adapters/base.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/adapters/claude.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/adapters/codex.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/adapters/cursor.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/adapters/detect.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/adapters/generic.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/adapters/windsurf.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/__init__.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/dependency_graph.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/go_imports.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/java_imports.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/js_ts_imports.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/monorepo.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/naming_signals.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/python_imports.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/ranking.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/repo_map.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/role_inference.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/rust_imports.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/symbols.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/task_classifier.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/analysis/tests.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/application/__init__.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/__init__.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/_shared.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/benchmark.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/claude_cmd.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/diff.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/explain.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/init.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/install.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/mcp_cmd.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/monitor.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/quickstart.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/repair.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/scan.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/stats.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/summarize.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/tune.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/commands/watch.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/__init__.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/bootstrap.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/cache.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/diff.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/git.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/git_hooks.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/global_install.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/ignore.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/merkle.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/models.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/redactor.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/scanner.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/snapshot.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/token_estimator.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/core/vscode_tasks.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/installers/__init__.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/integrations/__init__.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/integrations/git_hooks.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/integrations/global_install.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/integrations/platform.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/renderers/__init__.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/renderers/compact.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/renderers/receipts.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/session/__init__.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/session/state.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/summaries/__init__.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/src/agentpack/summaries/base.py +0 -0
- {agentpack_cli-0.3.4 → agentpack_cli-0.3.5}/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.5
|
|
4
4
|
Summary: Local context engine for AI coding agents that ranks relevant files and builds task-focused context packs.
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -46,7 +46,7 @@ Description-Content-Type: text/markdown
|
|
|
46
46
|
[](https://opensource.org/licenses/MIT)
|
|
47
47
|
[](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
|
|
48
48
|
|
|
49
|
-
> **Status: alpha (v0.3.
|
|
49
|
+
> **Status: alpha (v0.3.5).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Public benchmark proof exists for the current suite, but broader repo coverage is still growing. API may change before 1.0.
|
|
50
50
|
>
|
|
51
51
|
> **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.
|
|
52
52
|
|
|
@@ -77,7 +77,7 @@ Use AgentPack when a repo is too large to paste and you want faster, more consis
|
|
|
77
77
|
- **Budget-aware compression**: emits `full`, `diff`, `symbols`, `skeleton`, or `summary` views instead of all-or-nothing file dumps.
|
|
78
78
|
- **Local code intelligence**: extracts roles, domains, entrypoints, definitions, dependencies, env reads, side effects, and external systems using static analysis.
|
|
79
79
|
- **Semantic repo map**: adds a compact module-level map before file context so agents orient faster.
|
|
80
|
-
- **Freshness and deltas**: records task source, git state, snapshot hashes, selected-file deltas,
|
|
80
|
+
- **Freshness and deltas**: records task source, git state, snapshot hashes, selected-file deltas, stale-context warnings, MCP auto-refresh signals, and a machine-readable `agentpack:freshness` block in markdown fallback artifacts.
|
|
81
81
|
- **Agent integrations**: installs Claude Code, Cursor, Windsurf, Codex, Antigravity, VS Code tasks, git hooks, and MCP configuration.
|
|
82
82
|
- **Local and measurable**: no API calls for scan, summarize, rank, pack, stats, or benchmark; quality is measured with expected-file evals.
|
|
83
83
|
|
|
@@ -188,7 +188,7 @@ AgentPack is best treated as a **ranked starting map**. It should reduce repeate
|
|
|
188
188
|
| Pack time | Seconds on a warm cache; first summarize pass is slower |
|
|
189
189
|
| Recall | Expected files appear near the top; validate with `agentpack benchmark --misses` |
|
|
190
190
|
| Precision | Good enough to reduce exploration; summaries and repo maps may still include noise |
|
|
191
|
-
| Freshness |
|
|
191
|
+
| Freshness | Task or repo-stale MCP reads auto-refresh; static packs are clearly marked by task, git, and snapshot checks |
|
|
192
192
|
|
|
193
193
|
Use real repo evals instead of trusting compression numbers:
|
|
194
194
|
|
|
@@ -246,12 +246,22 @@ This is the core reliability loop: pack, measure recall, inspect misses, then tu
|
|
|
246
246
|
For MCP-capable agents, the preferred workflow is pull-based:
|
|
247
247
|
|
|
248
248
|
1. Call `start_task(task)` when a new task begins. AgentPack writes `.agentpack/task.md`, packs context, and returns ranked markdown.
|
|
249
|
-
2. Call `get_context()` when you need the latest
|
|
249
|
+
2. Call `get_context()` when you need the latest pack. It blocks for one refresh if `.agentpack/task.md` or the repo snapshot changed since the last pack, and otherwise prepends a freshness header.
|
|
250
250
|
3. Call `get_delta_context()` after edits or hook hints to see what changed without loading the full pack.
|
|
251
251
|
4. Call `explain_file(path)` or `get_related_files(path)` when a file looks relevant or suspicious.
|
|
252
252
|
|
|
253
253
|
The CLI remains the setup/debug/release path. MCP is the best interactive path because the agent can ask for only the context it needs instead of relying on one static startup blob.
|
|
254
254
|
|
|
255
|
+
Markdown context files are fallback artifacts for CI, logs, manual review, and non-MCP agents. Every rendered pack includes a machine-readable `agentpack:freshness` comment; agents should treat `active_context: mcp` as the preferred path and refresh before using markdown when `refresh_required: true`.
|
|
256
|
+
|
|
257
|
+
For non-MCP agents, use the executable guard before editing:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
agentpack guard --agent auto --repair-stale --refresh-context
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`guard` checks pack freshness, task freshness, repo snapshot freshness, and installed agent rules/hooks. With `--repair-stale --refresh-context`, it repairs stale AgentPack rule files and refreshes missing or stale context before returning success. `agentpack pack` also self-heals stale AgentPack rule blocks for the active agent, so older installs that still run `pack` get upgraded opportunistically.
|
|
264
|
+
|
|
255
265
|
## Before / After Agent Behavior
|
|
256
266
|
|
|
257
267
|
Without AgentPack:
|
|
@@ -365,7 +375,7 @@ _*`--agent generic` outputs standard markdown. Claude adapter has richer instruc
|
|
|
365
375
|
|
|
366
376
|
- AgentPack cannot intercept prompts inside IDEs — Cursor/Windsurf rely on rules being followed.
|
|
367
377
|
- Claude wrapper (`agentpack claude`) is the most deterministic integration.
|
|
368
|
-
- If the task changes drastically mid-session,
|
|
378
|
+
- If the task changes drastically mid-session, Claude hooks update `.agentpack/task.md` and block once for fresh hints; plain repo edits still use background repack to keep prompts fast.
|
|
369
379
|
- AgentPack-selected files are ranked starting points, not absolute truth.
|
|
370
380
|
|
|
371
381
|
---
|
|
@@ -733,6 +743,36 @@ agentpack repair --agent all # repair every supported integration
|
|
|
733
743
|
|
|
734
744
|
---
|
|
735
745
|
|
|
746
|
+
### `agentpack guard`
|
|
747
|
+
|
|
748
|
+
Run the pre-edit safety gate an agent can execute instead of only reading instructions.
|
|
749
|
+
|
|
750
|
+
```bash
|
|
751
|
+
agentpack guard # check current agent + context
|
|
752
|
+
agentpack guard --refresh-context # refresh stale/missing context
|
|
753
|
+
agentpack guard --agent codex --repair-stale # repair stale Codex rules/hooks
|
|
754
|
+
agentpack guard --agent auto --repair-stale --refresh-context
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
This is the strongest non-native enforcement AgentPack can provide: tools that run commands get a failing exit code when context is unsafe, and an automatic repair/refresh path when allowed.
|
|
758
|
+
|
|
759
|
+
---
|
|
760
|
+
|
|
761
|
+
### `agentpack migrate`
|
|
762
|
+
|
|
763
|
+
Repair stale AgentPack integrations across existing repos after upgrading.
|
|
764
|
+
|
|
765
|
+
```bash
|
|
766
|
+
agentpack migrate --path . --agent auto
|
|
767
|
+
agentpack migrate --path ~/src --discover --agent all
|
|
768
|
+
agentpack migrate --path ~/src --discover --agent codex --refresh-context
|
|
769
|
+
agentpack migrate --path ~/src --discover --dry-run
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
Use this when older repos still have stale `.cursorrules`, `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `.windsurfrules`, VS Code tasks, or hook files. `--discover` scans nested repo folders, `--dry-run` reports without writing, and `--refresh-context` regenerates packs after repair.
|
|
773
|
+
|
|
774
|
+
---
|
|
775
|
+
|
|
736
776
|
### `agentpack summarize`
|
|
737
777
|
|
|
738
778
|
Build or refresh the offline summary cache. **No API calls, ever.**
|
|
@@ -881,18 +921,38 @@ Register in Claude Code settings (`~/.claude/settings.json`):
|
|
|
881
921
|
|---|---|
|
|
882
922
|
| `start_task(task, mode, budget, max_tokens)` | Recommended MCP-first entry point. Writes `.agentpack/task.md`, generates a ranked pack, and returns packed markdown. |
|
|
883
923
|
| `pack_context(task, mode, budget, max_tokens)` | Generate a ranked context pack. If `task` is provided, writes it to `.agentpack/task.md`; if omitted, reads `task.md` or infers from git. |
|
|
884
|
-
| `get_context()` | Return the latest
|
|
924
|
+
| `get_context()` | Return the latest pack. If `.agentpack/task.md` or the repo snapshot differs from the packed metadata, it auto-refreshes before returning; otherwise it prepends a freshness header. |
|
|
885
925
|
| `refresh()` | Refresh using the current `task.md` or git-inferred task. |
|
|
886
926
|
| `explain_file(path, task)` | Show score, inclusion mode, reasons, symbols, imports, and importers for one file. |
|
|
887
927
|
| `get_related_files(path, depth)` | Return import-graph neighbours and related tests for a file. |
|
|
888
928
|
| `get_delta_context(max_files)` | Return the latest selected-file delta plus top current selected files. Useful for cheap prompt-time refresh checks. |
|
|
889
929
|
| `get_stats()` | Return latest pack stats, savings, selection quality, excluded files, and benchmark-style signals. |
|
|
890
930
|
|
|
891
|
-
**Staleness detection:** `get_context()` compares the snapshot hash
|
|
931
|
+
**Staleness detection:** `get_context()` compares the current task file, snapshot hash, and git state against the latest pack metadata. If `.agentpack/task.md` or the repo snapshot changed, it blocks for a fresh pack and prepends:
|
|
932
|
+
|
|
933
|
+
```
|
|
934
|
+
> Context auto-refreshed because .agentpack/task.md differs from the packed task ...
|
|
892
935
|
```
|
|
893
|
-
|
|
936
|
+
|
|
937
|
+
If auto-refresh fails, it falls back to the cached context with a loud stale warning and asks the agent to call `pack_context()` again.
|
|
938
|
+
|
|
939
|
+
Static markdown cannot refresh itself, so rendered packs include a machine-readable fallback header:
|
|
940
|
+
|
|
941
|
+
```text
|
|
942
|
+
<!-- agentpack:freshness
|
|
943
|
+
{
|
|
944
|
+
"active_context": "mcp",
|
|
945
|
+
"fallback_context": "markdown",
|
|
946
|
+
"refresh_required": false,
|
|
947
|
+
"mcp_refresh_tool": "agentpack_get_context",
|
|
948
|
+
"cli_refresh_command": "agentpack pack --task auto",
|
|
949
|
+
"guard_command": "agentpack guard --agent auto --repair-stale --refresh-context"
|
|
950
|
+
}
|
|
951
|
+
-->
|
|
894
952
|
```
|
|
895
953
|
|
|
954
|
+
Claude prompt hooks also block once on clear task switches so first-turn hints are fresh. Non-MCP rule files and VS Code folder-open tasks use `agentpack guard --repair-stale --refresh-context` as the executable fallback. To prefer lower latency over first-turn freshness, set `blocking_task_refresh = false` under `[hooks]` in `.agentpack/config.toml`.
|
|
955
|
+
|
|
896
956
|
**Smart truncation:** `start_task()` and `pack_context()` keep headers intact and trim file content blocks to fit the token budget, appending a note about how many files were omitted.
|
|
897
957
|
|
|
898
958
|
Zero API calls — all analysis is offline. Summary cache keyed by file hash: cold run parallelises AST parsing across CPU cores; warm cache hits are instant.
|
|
@@ -1444,6 +1504,13 @@ src/agentpack/
|
|
|
1444
1504
|
vscode_tasks.py # install/remove .vscode/tasks.json entries
|
|
1445
1505
|
global_install.py # global: git template hooks + shell rc hook
|
|
1446
1506
|
|
|
1507
|
+
../native-integrations/ # tracked native-enforcement skeletons and blocked-status stubs
|
|
1508
|
+
status.json # machine-readable native host enforcement status
|
|
1509
|
+
cursor-extension/ # VS Code-style Cursor guard skeleton
|
|
1510
|
+
windsurf-extension/ # VS Code-style Windsurf guard skeleton
|
|
1511
|
+
claude-native/ # blocked native stub pending mandatory host API
|
|
1512
|
+
codex-native/ # blocked native stub pending mandatory host API
|
|
1513
|
+
|
|
1447
1514
|
renderers/
|
|
1448
1515
|
markdown.py # renders pre-redacted ContextPack to markdown, including freshness/map/delta
|
|
1449
1516
|
compact.py # compact protocol format for session context files
|
|
@@ -1496,7 +1563,8 @@ src/agentpack/
|
|
|
1496
1563
|
- **`integrations/` vs `core/`**: git hooks, shell rc patching, and VS Code tasks are infrastructure concerns — they live in `integrations/`, not `core/`. `core/` is pure domain logic.
|
|
1497
1564
|
- **Adapters render; installers configure**: `adapters/` knows how to write a context file for an agent. `installers/` knows how to configure the agent's tool (CLAUDE.md, .cursorrules, settings.json). They are separate concerns and separate classes.
|
|
1498
1565
|
- **Agent integration contract is shared**: `integrations/agents.py` defines install, audit, and repair behavior for Claude, Cursor, Windsurf, Codex, Antigravity, and Generic. `install`, `repair`, `doctor --agent all`, and release verification use the same contract.
|
|
1499
|
-
- **MCP is the interactive path**: `start_task()` writes task state and returns a fresh pack, while `get_context()
|
|
1566
|
+
- **MCP is the interactive path**: `start_task()` writes task state and returns a fresh pack, while `get_context()` auto-refreshes stale task or repo-snapshot context and `get_delta_context()`, `explain_file()`, and `get_related_files()` let agents pull follow-up context on demand.
|
|
1567
|
+
- **Native enforcement status is explicit**: `native-integrations/status.json` tracks host skeletons and blockers. Entries stay `guarded`, not `enforced`, until a host exposes mandatory pre-edit/pre-tool hooks that can block failed guard checks.
|
|
1500
1568
|
|
|
1501
1569
|
---
|
|
1502
1570
|
|
|
@@ -1521,6 +1589,7 @@ src/agentpack/
|
|
|
1521
1589
|
- **Secret redaction**: covers AWS keys, GitHub tokens, OpenAI/Anthropic keys, JWTs, and private key blocks. Not a substitute for a dedicated secrets scanner on sensitive repos.
|
|
1522
1590
|
- **Token estimates**: uses tiktoken `cl100k_base` — approximate, not exact for Claude's billing.
|
|
1523
1591
|
- **Large repos (>5k files)**: global auto-bootstrap is skipped for repos over 5,000 files to avoid hangs. Run `agentpack init` explicitly in large codebases.
|
|
1592
|
+
- **Native hard enforcement**: tracked skeletons exist under `native-integrations/`, but all hosts remain `guarded` until their native APIs can guarantee mandatory pre-edit/pre-tool execution and block failed guard checks.
|
|
1524
1593
|
|
|
1525
1594
|
---
|
|
1526
1595
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://opensource.org/licenses/MIT)
|
|
8
8
|
[](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
|
|
9
9
|
|
|
10
|
-
> **Status: alpha (v0.3.
|
|
10
|
+
> **Status: alpha (v0.3.5).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Public benchmark proof exists for the current suite, but broader repo coverage is still growing. API may change before 1.0.
|
|
11
11
|
>
|
|
12
12
|
> **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.
|
|
13
13
|
|
|
@@ -38,7 +38,7 @@ Use AgentPack when a repo is too large to paste and you want faster, more consis
|
|
|
38
38
|
- **Budget-aware compression**: emits `full`, `diff`, `symbols`, `skeleton`, or `summary` views instead of all-or-nothing file dumps.
|
|
39
39
|
- **Local code intelligence**: extracts roles, domains, entrypoints, definitions, dependencies, env reads, side effects, and external systems using static analysis.
|
|
40
40
|
- **Semantic repo map**: adds a compact module-level map before file context so agents orient faster.
|
|
41
|
-
- **Freshness and deltas**: records task source, git state, snapshot hashes, selected-file deltas,
|
|
41
|
+
- **Freshness and deltas**: records task source, git state, snapshot hashes, selected-file deltas, stale-context warnings, MCP auto-refresh signals, and a machine-readable `agentpack:freshness` block in markdown fallback artifacts.
|
|
42
42
|
- **Agent integrations**: installs Claude Code, Cursor, Windsurf, Codex, Antigravity, VS Code tasks, git hooks, and MCP configuration.
|
|
43
43
|
- **Local and measurable**: no API calls for scan, summarize, rank, pack, stats, or benchmark; quality is measured with expected-file evals.
|
|
44
44
|
|
|
@@ -149,7 +149,7 @@ AgentPack is best treated as a **ranked starting map**. It should reduce repeate
|
|
|
149
149
|
| Pack time | Seconds on a warm cache; first summarize pass is slower |
|
|
150
150
|
| Recall | Expected files appear near the top; validate with `agentpack benchmark --misses` |
|
|
151
151
|
| Precision | Good enough to reduce exploration; summaries and repo maps may still include noise |
|
|
152
|
-
| Freshness |
|
|
152
|
+
| Freshness | Task or repo-stale MCP reads auto-refresh; static packs are clearly marked by task, git, and snapshot checks |
|
|
153
153
|
|
|
154
154
|
Use real repo evals instead of trusting compression numbers:
|
|
155
155
|
|
|
@@ -207,12 +207,22 @@ This is the core reliability loop: pack, measure recall, inspect misses, then tu
|
|
|
207
207
|
For MCP-capable agents, the preferred workflow is pull-based:
|
|
208
208
|
|
|
209
209
|
1. Call `start_task(task)` when a new task begins. AgentPack writes `.agentpack/task.md`, packs context, and returns ranked markdown.
|
|
210
|
-
2. Call `get_context()` when you need the latest
|
|
210
|
+
2. Call `get_context()` when you need the latest pack. It blocks for one refresh if `.agentpack/task.md` or the repo snapshot changed since the last pack, and otherwise prepends a freshness header.
|
|
211
211
|
3. Call `get_delta_context()` after edits or hook hints to see what changed without loading the full pack.
|
|
212
212
|
4. Call `explain_file(path)` or `get_related_files(path)` when a file looks relevant or suspicious.
|
|
213
213
|
|
|
214
214
|
The CLI remains the setup/debug/release path. MCP is the best interactive path because the agent can ask for only the context it needs instead of relying on one static startup blob.
|
|
215
215
|
|
|
216
|
+
Markdown context files are fallback artifacts for CI, logs, manual review, and non-MCP agents. Every rendered pack includes a machine-readable `agentpack:freshness` comment; agents should treat `active_context: mcp` as the preferred path and refresh before using markdown when `refresh_required: true`.
|
|
217
|
+
|
|
218
|
+
For non-MCP agents, use the executable guard before editing:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
agentpack guard --agent auto --repair-stale --refresh-context
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`guard` checks pack freshness, task freshness, repo snapshot freshness, and installed agent rules/hooks. With `--repair-stale --refresh-context`, it repairs stale AgentPack rule files and refreshes missing or stale context before returning success. `agentpack pack` also self-heals stale AgentPack rule blocks for the active agent, so older installs that still run `pack` get upgraded opportunistically.
|
|
225
|
+
|
|
216
226
|
## Before / After Agent Behavior
|
|
217
227
|
|
|
218
228
|
Without AgentPack:
|
|
@@ -326,7 +336,7 @@ _*`--agent generic` outputs standard markdown. Claude adapter has richer instruc
|
|
|
326
336
|
|
|
327
337
|
- AgentPack cannot intercept prompts inside IDEs — Cursor/Windsurf rely on rules being followed.
|
|
328
338
|
- Claude wrapper (`agentpack claude`) is the most deterministic integration.
|
|
329
|
-
- If the task changes drastically mid-session,
|
|
339
|
+
- If the task changes drastically mid-session, Claude hooks update `.agentpack/task.md` and block once for fresh hints; plain repo edits still use background repack to keep prompts fast.
|
|
330
340
|
- AgentPack-selected files are ranked starting points, not absolute truth.
|
|
331
341
|
|
|
332
342
|
---
|
|
@@ -694,6 +704,36 @@ agentpack repair --agent all # repair every supported integration
|
|
|
694
704
|
|
|
695
705
|
---
|
|
696
706
|
|
|
707
|
+
### `agentpack guard`
|
|
708
|
+
|
|
709
|
+
Run the pre-edit safety gate an agent can execute instead of only reading instructions.
|
|
710
|
+
|
|
711
|
+
```bash
|
|
712
|
+
agentpack guard # check current agent + context
|
|
713
|
+
agentpack guard --refresh-context # refresh stale/missing context
|
|
714
|
+
agentpack guard --agent codex --repair-stale # repair stale Codex rules/hooks
|
|
715
|
+
agentpack guard --agent auto --repair-stale --refresh-context
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
This is the strongest non-native enforcement AgentPack can provide: tools that run commands get a failing exit code when context is unsafe, and an automatic repair/refresh path when allowed.
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
### `agentpack migrate`
|
|
723
|
+
|
|
724
|
+
Repair stale AgentPack integrations across existing repos after upgrading.
|
|
725
|
+
|
|
726
|
+
```bash
|
|
727
|
+
agentpack migrate --path . --agent auto
|
|
728
|
+
agentpack migrate --path ~/src --discover --agent all
|
|
729
|
+
agentpack migrate --path ~/src --discover --agent codex --refresh-context
|
|
730
|
+
agentpack migrate --path ~/src --discover --dry-run
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
Use this when older repos still have stale `.cursorrules`, `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `.windsurfrules`, VS Code tasks, or hook files. `--discover` scans nested repo folders, `--dry-run` reports without writing, and `--refresh-context` regenerates packs after repair.
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
697
737
|
### `agentpack summarize`
|
|
698
738
|
|
|
699
739
|
Build or refresh the offline summary cache. **No API calls, ever.**
|
|
@@ -842,18 +882,38 @@ Register in Claude Code settings (`~/.claude/settings.json`):
|
|
|
842
882
|
|---|---|
|
|
843
883
|
| `start_task(task, mode, budget, max_tokens)` | Recommended MCP-first entry point. Writes `.agentpack/task.md`, generates a ranked pack, and returns packed markdown. |
|
|
844
884
|
| `pack_context(task, mode, budget, max_tokens)` | Generate a ranked context pack. If `task` is provided, writes it to `.agentpack/task.md`; if omitted, reads `task.md` or infers from git. |
|
|
845
|
-
| `get_context()` | Return the latest
|
|
885
|
+
| `get_context()` | Return the latest pack. If `.agentpack/task.md` or the repo snapshot differs from the packed metadata, it auto-refreshes before returning; otherwise it prepends a freshness header. |
|
|
846
886
|
| `refresh()` | Refresh using the current `task.md` or git-inferred task. |
|
|
847
887
|
| `explain_file(path, task)` | Show score, inclusion mode, reasons, symbols, imports, and importers for one file. |
|
|
848
888
|
| `get_related_files(path, depth)` | Return import-graph neighbours and related tests for a file. |
|
|
849
889
|
| `get_delta_context(max_files)` | Return the latest selected-file delta plus top current selected files. Useful for cheap prompt-time refresh checks. |
|
|
850
890
|
| `get_stats()` | Return latest pack stats, savings, selection quality, excluded files, and benchmark-style signals. |
|
|
851
891
|
|
|
852
|
-
**Staleness detection:** `get_context()` compares the snapshot hash
|
|
892
|
+
**Staleness detection:** `get_context()` compares the current task file, snapshot hash, and git state against the latest pack metadata. If `.agentpack/task.md` or the repo snapshot changed, it blocks for a fresh pack and prepends:
|
|
893
|
+
|
|
894
|
+
```
|
|
895
|
+
> Context auto-refreshed because .agentpack/task.md differs from the packed task ...
|
|
853
896
|
```
|
|
854
|
-
|
|
897
|
+
|
|
898
|
+
If auto-refresh fails, it falls back to the cached context with a loud stale warning and asks the agent to call `pack_context()` again.
|
|
899
|
+
|
|
900
|
+
Static markdown cannot refresh itself, so rendered packs include a machine-readable fallback header:
|
|
901
|
+
|
|
902
|
+
```text
|
|
903
|
+
<!-- agentpack:freshness
|
|
904
|
+
{
|
|
905
|
+
"active_context": "mcp",
|
|
906
|
+
"fallback_context": "markdown",
|
|
907
|
+
"refresh_required": false,
|
|
908
|
+
"mcp_refresh_tool": "agentpack_get_context",
|
|
909
|
+
"cli_refresh_command": "agentpack pack --task auto",
|
|
910
|
+
"guard_command": "agentpack guard --agent auto --repair-stale --refresh-context"
|
|
911
|
+
}
|
|
912
|
+
-->
|
|
855
913
|
```
|
|
856
914
|
|
|
915
|
+
Claude prompt hooks also block once on clear task switches so first-turn hints are fresh. Non-MCP rule files and VS Code folder-open tasks use `agentpack guard --repair-stale --refresh-context` as the executable fallback. To prefer lower latency over first-turn freshness, set `blocking_task_refresh = false` under `[hooks]` in `.agentpack/config.toml`.
|
|
916
|
+
|
|
857
917
|
**Smart truncation:** `start_task()` and `pack_context()` keep headers intact and trim file content blocks to fit the token budget, appending a note about how many files were omitted.
|
|
858
918
|
|
|
859
919
|
Zero API calls — all analysis is offline. Summary cache keyed by file hash: cold run parallelises AST parsing across CPU cores; warm cache hits are instant.
|
|
@@ -1405,6 +1465,13 @@ src/agentpack/
|
|
|
1405
1465
|
vscode_tasks.py # install/remove .vscode/tasks.json entries
|
|
1406
1466
|
global_install.py # global: git template hooks + shell rc hook
|
|
1407
1467
|
|
|
1468
|
+
../native-integrations/ # tracked native-enforcement skeletons and blocked-status stubs
|
|
1469
|
+
status.json # machine-readable native host enforcement status
|
|
1470
|
+
cursor-extension/ # VS Code-style Cursor guard skeleton
|
|
1471
|
+
windsurf-extension/ # VS Code-style Windsurf guard skeleton
|
|
1472
|
+
claude-native/ # blocked native stub pending mandatory host API
|
|
1473
|
+
codex-native/ # blocked native stub pending mandatory host API
|
|
1474
|
+
|
|
1408
1475
|
renderers/
|
|
1409
1476
|
markdown.py # renders pre-redacted ContextPack to markdown, including freshness/map/delta
|
|
1410
1477
|
compact.py # compact protocol format for session context files
|
|
@@ -1457,7 +1524,8 @@ src/agentpack/
|
|
|
1457
1524
|
- **`integrations/` vs `core/`**: git hooks, shell rc patching, and VS Code tasks are infrastructure concerns — they live in `integrations/`, not `core/`. `core/` is pure domain logic.
|
|
1458
1525
|
- **Adapters render; installers configure**: `adapters/` knows how to write a context file for an agent. `installers/` knows how to configure the agent's tool (CLAUDE.md, .cursorrules, settings.json). They are separate concerns and separate classes.
|
|
1459
1526
|
- **Agent integration contract is shared**: `integrations/agents.py` defines install, audit, and repair behavior for Claude, Cursor, Windsurf, Codex, Antigravity, and Generic. `install`, `repair`, `doctor --agent all`, and release verification use the same contract.
|
|
1460
|
-
- **MCP is the interactive path**: `start_task()` writes task state and returns a fresh pack, while `get_context()
|
|
1527
|
+
- **MCP is the interactive path**: `start_task()` writes task state and returns a fresh pack, while `get_context()` auto-refreshes stale task or repo-snapshot context and `get_delta_context()`, `explain_file()`, and `get_related_files()` let agents pull follow-up context on demand.
|
|
1528
|
+
- **Native enforcement status is explicit**: `native-integrations/status.json` tracks host skeletons and blockers. Entries stay `guarded`, not `enforced`, until a host exposes mandatory pre-edit/pre-tool hooks that can block failed guard checks.
|
|
1461
1529
|
|
|
1462
1530
|
---
|
|
1463
1531
|
|
|
@@ -1482,6 +1550,7 @@ src/agentpack/
|
|
|
1482
1550
|
- **Secret redaction**: covers AWS keys, GitHub tokens, OpenAI/Anthropic keys, JWTs, and private key blocks. Not a substitute for a dedicated secrets scanner on sensitive repos.
|
|
1483
1551
|
- **Token estimates**: uses tiktoken `cl100k_base` — approximate, not exact for Claude's billing.
|
|
1484
1552
|
- **Large repos (>5k files)**: global auto-bootstrap is skipped for repos over 5,000 files to avoid hangs. Run `agentpack init` explicitly in large codebases.
|
|
1553
|
+
- **Native hard enforcement**: tracked skeletons exist under `native-integrations/`, but all hosts remain `guarded` until their native APIs can guarantee mandatory pre-edit/pre-tool execution and block failed guard checks.
|
|
1485
1554
|
|
|
1486
1555
|
---
|
|
1487
1556
|
|
|
@@ -15,6 +15,7 @@ from agentpack.core.diff import diff_snapshots
|
|
|
15
15
|
from agentpack.core import git
|
|
16
16
|
from agentpack.core.context_pack import select_files, save_pack_metadata, load_pack_metadata
|
|
17
17
|
from agentpack.core.models import ContextPack, DependencyGraph, FileInfo, ScanResult, SelectedFile, Receipt
|
|
18
|
+
from agentpack.core.task_freshness import read_task_md, task_metadata
|
|
18
19
|
from agentpack.core.token_estimator import estimate_tokens
|
|
19
20
|
from agentpack.renderers.markdown import render_generic
|
|
20
21
|
from agentpack.analysis.ranking import (
|
|
@@ -851,19 +852,7 @@ def _change_source(root: Path, since: str | None, snapshot_changed: set[str], gi
|
|
|
851
852
|
|
|
852
853
|
|
|
853
854
|
def _task_md_body(root: Path) -> str | None:
|
|
854
|
-
|
|
855
|
-
if not task_md_path.exists():
|
|
856
|
-
return None
|
|
857
|
-
try:
|
|
858
|
-
content = task_md_path.read_text(encoding="utf-8").strip()
|
|
859
|
-
except OSError:
|
|
860
|
-
return None
|
|
861
|
-
lines = [ln for ln in content.splitlines() if ln.strip() and not ln.startswith("#")]
|
|
862
|
-
body = lines[0].strip() if lines else ""
|
|
863
|
-
placeholder = "Write or update the current coding task here."
|
|
864
|
-
if body and placeholder not in body:
|
|
865
|
-
return body
|
|
866
|
-
return None
|
|
855
|
+
return read_task_md(root)
|
|
867
856
|
|
|
868
857
|
|
|
869
858
|
def _build_freshness_metadata(
|
|
@@ -885,6 +874,7 @@ def _build_freshness_metadata(
|
|
|
885
874
|
"task_class_signals": plan.task_class_signals,
|
|
886
875
|
"dirty_files_count": len(dirty),
|
|
887
876
|
}
|
|
877
|
+
metadata.update(task_metadata(root, request.task))
|
|
888
878
|
if plan.workspace:
|
|
889
879
|
metadata["workspace"] = plan.workspace
|
|
890
880
|
if plan.workspace_roots:
|
|
@@ -909,7 +899,7 @@ def _freshness_warnings(root: Path, request: PackRequest, freshness: dict[str, A
|
|
|
909
899
|
task_md = freshness.get("task_md")
|
|
910
900
|
if task_md and task_md != request.task:
|
|
911
901
|
warnings.append(
|
|
912
|
-
".agentpack/task.md differs from the packed task;
|
|
902
|
+
".agentpack/task.md differs from the packed task; AgentPack-controlled context reads should auto-refresh, or run `agentpack pack --task auto`."
|
|
913
903
|
)
|
|
914
904
|
if freshness.get("changed_files_source") == "no live changes; ranking used task keywords and history":
|
|
915
905
|
warnings.append("No live changed files were detected; treat selected files as keyword-based hints.")
|
|
@@ -7,10 +7,12 @@ from agentpack.commands import (
|
|
|
7
7
|
diff,
|
|
8
8
|
doctor,
|
|
9
9
|
explain,
|
|
10
|
+
guard,
|
|
10
11
|
hook_cmd,
|
|
11
12
|
init,
|
|
12
13
|
install,
|
|
13
14
|
mcp_cmd,
|
|
15
|
+
migrate,
|
|
14
16
|
monitor,
|
|
15
17
|
pack,
|
|
16
18
|
quickstart,
|
|
@@ -51,8 +53,10 @@ for mod in [
|
|
|
51
53
|
pack,
|
|
52
54
|
install,
|
|
53
55
|
repair,
|
|
56
|
+
migrate,
|
|
54
57
|
monitor,
|
|
55
58
|
explain,
|
|
59
|
+
guard,
|
|
56
60
|
doctor,
|
|
57
61
|
tune,
|
|
58
62
|
watch,
|
|
@@ -18,6 +18,7 @@ from agentpack.integrations.global_install import (
|
|
|
18
18
|
)
|
|
19
19
|
from agentpack.commands._shared import console, _root
|
|
20
20
|
from agentpack.core.context_pack import load_pack_metadata
|
|
21
|
+
from agentpack.core.task_freshness import task_freshness
|
|
21
22
|
from agentpack.integrations.agents import SUPPORTED_AGENTS, check_agent_integration, expand_agents
|
|
22
23
|
|
|
23
24
|
|
|
@@ -126,6 +127,14 @@ def register(app: typer.Typer) -> None:
|
|
|
126
127
|
age = time.time() - context_path.stat().st_mtime
|
|
127
128
|
age_str = f"{int(age // 3600)}h {int((age % 3600) // 60)}m" if age > 3600 else f"{int(age // 60)}m"
|
|
128
129
|
console.print(f" [green]✓[/] context pack present (age: {age_str})")
|
|
130
|
+
task_state = task_freshness(root, load_pack_metadata(root))
|
|
131
|
+
if task_state.is_stale:
|
|
132
|
+
console.print(
|
|
133
|
+
" [yellow]![/] task context stale — "
|
|
134
|
+
f"packed: {task_state.packed_task}; current: {task_state.current_task}. "
|
|
135
|
+
"MCP get_context auto-refreshes this, or run: agentpack pack --task auto"
|
|
136
|
+
)
|
|
137
|
+
ok = False
|
|
129
138
|
else:
|
|
130
139
|
console.print(" [yellow]![/] No context pack yet — write .agentpack/task.md, then run: agentpack pack --task auto")
|
|
131
140
|
|
|
@@ -236,13 +245,20 @@ def register(app: typer.Typer) -> None:
|
|
|
236
245
|
console.print(f" [dim]Auto-detected agent: {agents[0]}[/]")
|
|
237
246
|
for selected in agents:
|
|
238
247
|
console.print(f" [bold]{selected}[/]")
|
|
248
|
+
selected_ok = True
|
|
239
249
|
for check in check_agent_integration(root, selected):
|
|
240
250
|
if check.ok:
|
|
241
251
|
console.print(f" [green]✓[/] {check.label}: {check.detail}")
|
|
242
252
|
continue
|
|
243
253
|
fix = f" — run: {check.fix}" if check.fix else ""
|
|
244
254
|
console.print(f" [red]✗[/] {check.label}: {check.detail}{fix}")
|
|
255
|
+
selected_ok = False
|
|
245
256
|
ok = False
|
|
257
|
+
if not selected_ok:
|
|
258
|
+
console.print(
|
|
259
|
+
f" [yellow]![/] executable guard repair: "
|
|
260
|
+
f"agentpack guard --agent {selected} --repair-stale --refresh-context"
|
|
261
|
+
)
|
|
246
262
|
|
|
247
263
|
# --- Release hygiene ---
|
|
248
264
|
console.print("\n[bold]Release hygiene[/]")
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from agentpack.commands._shared import console, _root, run_refresh
|
|
6
|
+
from agentpack.core.config import load_config
|
|
7
|
+
from agentpack.core.context_pack import load_pack_metadata
|
|
8
|
+
from agentpack.core.ignore import load_spec
|
|
9
|
+
from agentpack.core.scanner import scan
|
|
10
|
+
from agentpack.core.snapshot import build_snapshot
|
|
11
|
+
from agentpack.core.task_freshness import task_freshness
|
|
12
|
+
from agentpack.application.pack_service import AdapterRegistry
|
|
13
|
+
from agentpack.integrations.agents import (
|
|
14
|
+
SUPPORTED_AGENTS,
|
|
15
|
+
check_agent_integration,
|
|
16
|
+
expand_agents,
|
|
17
|
+
install_agent_integration,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def register(app: typer.Typer) -> None:
|
|
22
|
+
@app.command()
|
|
23
|
+
def guard(
|
|
24
|
+
agent: str = typer.Option(
|
|
25
|
+
"auto",
|
|
26
|
+
"--agent",
|
|
27
|
+
help=f"Agent integration to guard ({' | '.join(SUPPORTED_AGENTS)}).",
|
|
28
|
+
),
|
|
29
|
+
repair_stale: bool = typer.Option(
|
|
30
|
+
False,
|
|
31
|
+
"--repair-stale",
|
|
32
|
+
help="Repair stale/missing AgentPack rule and hook files before returning.",
|
|
33
|
+
),
|
|
34
|
+
refresh_context: bool = typer.Option(
|
|
35
|
+
False,
|
|
36
|
+
"--refresh-context",
|
|
37
|
+
help="Refresh the context pack when it is missing or stale.",
|
|
38
|
+
),
|
|
39
|
+
mode: str = typer.Option("balanced", "--mode", help="Refresh mode (minimal|balanced|deep)."),
|
|
40
|
+
budget: int = typer.Option(0, "--budget", help="Refresh token budget (0 = config default)."),
|
|
41
|
+
) -> None:
|
|
42
|
+
"""Executable pre-edit gate for agents before they trust packed context."""
|
|
43
|
+
if agent not in SUPPORTED_AGENTS:
|
|
44
|
+
console.print(f"[yellow]Unknown agent: {agent}. Supported: {', '.join(SUPPORTED_AGENTS)}[/]")
|
|
45
|
+
raise typer.Exit(1)
|
|
46
|
+
if mode not in ("minimal", "balanced", "deep"):
|
|
47
|
+
console.print(f"[red]Invalid mode: {mode}. Use minimal|balanced|deep.[/]")
|
|
48
|
+
raise typer.Exit(1)
|
|
49
|
+
|
|
50
|
+
root = _root()
|
|
51
|
+
agents = expand_agents(agent, root)
|
|
52
|
+
ok = True
|
|
53
|
+
|
|
54
|
+
for selected in agents:
|
|
55
|
+
checks = check_agent_integration(root, selected)
|
|
56
|
+
failing = [check for check in checks if not check.ok]
|
|
57
|
+
if failing and repair_stale and selected != "generic":
|
|
58
|
+
_repair_agent(root, selected)
|
|
59
|
+
checks = check_agent_integration(root, selected)
|
|
60
|
+
failing = [check for check in checks if not check.ok]
|
|
61
|
+
|
|
62
|
+
if failing:
|
|
63
|
+
ok = False
|
|
64
|
+
console.print(f"[yellow]Agent integration needs repair: {selected}[/]")
|
|
65
|
+
for check in failing:
|
|
66
|
+
fix = f" Run: {check.fix}" if check.fix else ""
|
|
67
|
+
console.print(f" [yellow]![/] {check.label}: {check.detail}.{fix}")
|
|
68
|
+
else:
|
|
69
|
+
console.print(f"[green]✓[/] Agent integration current: {selected}")
|
|
70
|
+
|
|
71
|
+
context_ok, context_reason = _context_is_fresh(root)
|
|
72
|
+
if not context_ok and refresh_context:
|
|
73
|
+
selected_agent = agents[0] if agents else "generic"
|
|
74
|
+
console.print(f"[yellow]Refreshing context: {context_reason}[/]")
|
|
75
|
+
stats = run_refresh(root, selected_agent, mode, budget)
|
|
76
|
+
if stats is None:
|
|
77
|
+
ok = False
|
|
78
|
+
else:
|
|
79
|
+
context_ok, context_reason = _context_is_fresh(root)
|
|
80
|
+
|
|
81
|
+
if context_ok:
|
|
82
|
+
console.print("[green]✓[/] Context pack fresh")
|
|
83
|
+
else:
|
|
84
|
+
ok = False
|
|
85
|
+
console.print(f"[yellow]Context pack unsafe: {context_reason}[/]")
|
|
86
|
+
console.print(" Run: agentpack guard --repair-stale --refresh-context")
|
|
87
|
+
|
|
88
|
+
if not ok:
|
|
89
|
+
raise typer.Exit(1)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _repair_agent(root, agent: str) -> None:
|
|
93
|
+
from agentpack.commands.install import _install_slash_command
|
|
94
|
+
|
|
95
|
+
console.print(f"[yellow]Repairing AgentPack integration: {agent}[/]")
|
|
96
|
+
install_agent_integration(
|
|
97
|
+
root,
|
|
98
|
+
agent,
|
|
99
|
+
global_install=False,
|
|
100
|
+
install_slash_command=_install_slash_command,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _context_is_fresh(root) -> tuple[bool, str]:
|
|
105
|
+
meta = load_pack_metadata(root)
|
|
106
|
+
if not meta:
|
|
107
|
+
return False, "missing context pack metadata"
|
|
108
|
+
|
|
109
|
+
task_state = task_freshness(root, meta)
|
|
110
|
+
if task_state.is_stale:
|
|
111
|
+
return False, ".agentpack/task.md differs from packed task"
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
cfg = load_config(root)
|
|
115
|
+
ignore_spec = load_spec(root / cfg.project.ignore_file)
|
|
116
|
+
scan_result = scan(
|
|
117
|
+
root,
|
|
118
|
+
ignore_spec,
|
|
119
|
+
cfg.context.max_file_tokens,
|
|
120
|
+
always_skip_paths=AdapterRegistry.generated_output_paths(root, cfg),
|
|
121
|
+
)
|
|
122
|
+
current = build_snapshot(scan_result.packable)
|
|
123
|
+
except Exception as exc:
|
|
124
|
+
return False, f"could not compute repo snapshot: {exc}"
|
|
125
|
+
|
|
126
|
+
if current["root_hash"] != meta.get("snapshot_root_hash"):
|
|
127
|
+
return False, "repo snapshot differs from packed snapshot"
|
|
128
|
+
|
|
129
|
+
return True, "fresh"
|