agentpack-cli 0.1.11__tar.gz → 0.1.13__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.1.11 → agentpack_cli-0.1.13}/PKG-INFO +14 -35
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/README.md +13 -34
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/pyproject.toml +1 -1
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/__init__.py +1 -1
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/cli.py +2 -2
- agentpack_cli-0.1.13/src/agentpack/commands/_shared.py +105 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/claude_cmd.py +4 -9
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/watch.py +40 -4
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/mcp_server.py +2 -2
- agentpack_cli-0.1.11/src/agentpack/commands/_shared.py +0 -13
- agentpack_cli-0.1.11/src/agentpack/commands/session.py +0 -234
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/.gitignore +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/LICENSE +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/__init__.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/antigravity.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/base.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/claude.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/codex.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/cursor.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/detect.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/generic.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/windsurf.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/__init__.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/dependency_graph.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/go_imports.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/java_imports.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/js_ts_imports.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/python_imports.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/ranking.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/rust_imports.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/symbols.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/tests.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/application/__init__.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/application/pack_service.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/__init__.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/benchmark.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/diff.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/doctor.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/explain.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/init.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/install.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/mcp_cmd.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/monitor.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/pack.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/scan.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/stats.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/status.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/summarize.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/__init__.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/bootstrap.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/cache.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/config.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/context_pack.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/diff.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/git.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/git_hooks.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/global_install.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/ignore.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/merkle.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/models.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/redactor.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/scanner.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/snapshot.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/token_estimator.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/vscode_tasks.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/data/agentpack.md +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/__init__.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/antigravity.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/claude.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/codex.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/cursor.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/windsurf.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/integrations/__init__.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/integrations/git_hooks.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/integrations/global_install.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/integrations/vscode_tasks.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/renderers/__init__.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/renderers/compact.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/renderers/markdown.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/renderers/receipts.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/session/__init__.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/session/state.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/summaries/__init__.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/summaries/base.py +0 -0
- {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/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.1.
|
|
3
|
+
Version: 0.1.13
|
|
4
4
|
Summary: Token-aware context packing for AI coding agents — Claude, Cursor, Windsurf, and Codex
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -44,7 +44,7 @@ Description-Content-Type: text/markdown
|
|
|
44
44
|
[](https://opensource.org/licenses/MIT)
|
|
45
45
|
[](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
|
|
46
46
|
|
|
47
|
-
> **Status: alpha (v0.1.
|
|
47
|
+
> **Status: alpha (v0.1.11).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Not yet validated across a wide range of repos. API may change before 1.0.
|
|
48
48
|
>
|
|
49
49
|
> **Platform note:** macOS and Linux are fully supported. Windows support is not yet implemented (git hooks use POSIX shell; the Claude Code session hooks use `python3`/`rm -f`). Contributions welcome.
|
|
50
50
|
|
|
@@ -235,17 +235,13 @@ agentpack watch # auto-resumes session, refreshes context on file/tas
|
|
|
235
235
|
Then open Claude Code / Cursor / Codex and write your coding task normally.
|
|
236
236
|
|
|
237
237
|
- AgentPack keeps `.agentpack/context.md` and `.agentpack/context.claude.md` fresh while `watch` is running.
|
|
238
|
-
- To change the task:
|
|
239
|
-
- Check session state: `agentpack session status`
|
|
240
|
-
- Force a refresh: `agentpack session refresh`
|
|
241
|
-
- Stop: `agentpack session stop`
|
|
238
|
+
- To change the task: edit `.agentpack/task.md` directly, or tell Claude — it updates the file itself. `watch` picks up the change automatically.
|
|
242
239
|
|
|
243
240
|
### Agent integration matrix
|
|
244
241
|
|
|
245
242
|
| Agent | Automation level | Method |
|
|
246
243
|
|---|---|---|
|
|
247
244
|
| Claude Code (hook) | Highest | `UserPromptSubmit` hook auto-injects context |
|
|
248
|
-
| Claude Code (session) | High | `init` + `watch` + read `context.md` |
|
|
249
245
|
| Codex | Medium | `AGENTS.md` + `init` + `watch` |
|
|
250
246
|
| Cursor | Medium | `.cursor/rules/agentpack.mdc` + `init` + `watch` |
|
|
251
247
|
| Windsurf | Medium | `.windsurfrules` + `init` + `watch` |
|
|
@@ -404,8 +400,8 @@ Token counts use tiktoken `cl100k_base` — a close approximation to Claude's ac
|
|
|
404
400
|
|
|
405
401
|
agentpack uses two workflows:
|
|
406
402
|
|
|
407
|
-
- **`ci.yml`** — runs tests
|
|
408
|
-
- **`
|
|
403
|
+
- **`ci.yml`** — runs tests (Python 3.10–3.13) + ruff lint + 80% coverage gate on every push and PR to `main`
|
|
404
|
+
- **`publish.yml`** — runs on every `v*` tag push; requires tag from a `release/*` branch and a CHANGELOG.md entry for the version before building and publishing to PyPI (trusted publishing)
|
|
409
405
|
|
|
410
406
|
### Add context packing to your repo
|
|
411
407
|
|
|
@@ -627,11 +623,10 @@ Options:
|
|
|
627
623
|
| `--agent` | `auto` | Target agent (`auto` \| `claude` \| `cursor` \| `windsurf` \| `codex` \| `antigravity` \| `generic`). `auto` detects the active IDE from env and project files. |
|
|
628
624
|
| `--task` | `auto` | Task description, or `auto` to infer from git |
|
|
629
625
|
| `--mode` | `balanced` | Budget mode: `minimal`, `balanced`, `deep` |
|
|
630
|
-
| `--budget` | 25000 | Token budget |
|
|
626
|
+
| `--budget` | 0 (uses config default 25000) | Token budget |
|
|
631
627
|
| `--since` | — | Only include files changed since this git ref |
|
|
632
628
|
| `--session` | off | Re-pack on every file change (watch mode) |
|
|
633
629
|
| `--refresh` | off | Force rebuild summaries before packing |
|
|
634
|
-
| `--budget` | 25000 | Token budget override |
|
|
635
630
|
|
|
636
631
|
**Budget modes:**
|
|
637
632
|
|
|
@@ -643,26 +638,9 @@ Options:
|
|
|
643
638
|
|
|
644
639
|
---
|
|
645
640
|
|
|
646
|
-
### `agentpack session`
|
|
641
|
+
### `agentpack session` _(removed)_
|
|
647
642
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
```bash
|
|
651
|
-
agentpack session start # re-run to change agent/mode or force refresh
|
|
652
|
-
agentpack session start --agent claude # set agent (claude|cursor|codex|generic)
|
|
653
|
-
agentpack session start --task "fix bug" # change task + refresh context
|
|
654
|
-
agentpack session status # show session state + context size
|
|
655
|
-
agentpack session refresh # regenerate context now
|
|
656
|
-
agentpack session refresh --task "new task" # change task + refresh
|
|
657
|
-
agentpack session stop # mark session inactive
|
|
658
|
-
```
|
|
659
|
-
|
|
660
|
-
`agentpack init` creates (idempotently):
|
|
661
|
-
- `.agentpack/session.json` — session state
|
|
662
|
-
- `.agentpack/task.md` — current task (edit directly or use `session refresh --task`)
|
|
663
|
-
- `.agentpack/context.md` — readable context pack (updated by `watch`)
|
|
664
|
-
- `.agentpack/context.claude.md` — Claude Code format (always written alongside context.md)
|
|
665
|
-
- `.agentpack/context.compact.md` — compact protocol format
|
|
643
|
+
Session management was removed in v0.1.11. `agentpack init` bootstraps the session automatically. Use `agentpack watch` to keep context current. To change the task, edit `.agentpack/task.md`.
|
|
666
644
|
|
|
667
645
|
---
|
|
668
646
|
|
|
@@ -1280,13 +1258,14 @@ Add to `.github/workflows/agentpack-context.yml` — see the full example in [CI
|
|
|
1280
1258
|
|
|
1281
1259
|
```bash
|
|
1282
1260
|
# One-time project setup
|
|
1283
|
-
agentpack init
|
|
1261
|
+
agentpack init # creates config, session, task.md
|
|
1262
|
+
# Edit .agentpack/task.md to set your task
|
|
1284
1263
|
|
|
1285
1264
|
# Every terminal session — just one command
|
|
1286
|
-
agentpack watch
|
|
1265
|
+
agentpack watch # keeps context fresh automatically
|
|
1287
1266
|
|
|
1288
|
-
# Change task mid-session
|
|
1289
|
-
|
|
1267
|
+
# Change task mid-session: edit .agentpack/task.md directly
|
|
1268
|
+
# watch detects the change and refreshes automatically
|
|
1290
1269
|
```
|
|
1291
1270
|
|
|
1292
1271
|
---
|
|
@@ -1360,7 +1339,7 @@ agentpack init # one-time setup (creates session + task.md)
|
|
|
1360
1339
|
agentpack watch # in another terminal — auto-resumes each time
|
|
1361
1340
|
```
|
|
1362
1341
|
|
|
1363
|
-
Refreshes `.agentpack/context.md` every time you save a file. Change the task
|
|
1342
|
+
Refreshes `.agentpack/context.md` every time you save a file. Change the task by editing `.agentpack/task.md` directly — or tell Claude and it writes the file itself. `watch` picks up the change automatically.
|
|
1364
1343
|
|
|
1365
1344
|
### Debug file selection with `explain`
|
|
1366
1345
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
|
|
7
7
|
|
|
8
|
-
> **Status: alpha (v0.1.
|
|
8
|
+
> **Status: alpha (v0.1.11).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Not yet validated across a wide range of repos. API may change before 1.0.
|
|
9
9
|
>
|
|
10
10
|
> **Platform note:** macOS and Linux are fully supported. Windows support is not yet implemented (git hooks use POSIX shell; the Claude Code session hooks use `python3`/`rm -f`). Contributions welcome.
|
|
11
11
|
|
|
@@ -196,17 +196,13 @@ agentpack watch # auto-resumes session, refreshes context on file/tas
|
|
|
196
196
|
Then open Claude Code / Cursor / Codex and write your coding task normally.
|
|
197
197
|
|
|
198
198
|
- AgentPack keeps `.agentpack/context.md` and `.agentpack/context.claude.md` fresh while `watch` is running.
|
|
199
|
-
- To change the task:
|
|
200
|
-
- Check session state: `agentpack session status`
|
|
201
|
-
- Force a refresh: `agentpack session refresh`
|
|
202
|
-
- Stop: `agentpack session stop`
|
|
199
|
+
- To change the task: edit `.agentpack/task.md` directly, or tell Claude — it updates the file itself. `watch` picks up the change automatically.
|
|
203
200
|
|
|
204
201
|
### Agent integration matrix
|
|
205
202
|
|
|
206
203
|
| Agent | Automation level | Method |
|
|
207
204
|
|---|---|---|
|
|
208
205
|
| Claude Code (hook) | Highest | `UserPromptSubmit` hook auto-injects context |
|
|
209
|
-
| Claude Code (session) | High | `init` + `watch` + read `context.md` |
|
|
210
206
|
| Codex | Medium | `AGENTS.md` + `init` + `watch` |
|
|
211
207
|
| Cursor | Medium | `.cursor/rules/agentpack.mdc` + `init` + `watch` |
|
|
212
208
|
| Windsurf | Medium | `.windsurfrules` + `init` + `watch` |
|
|
@@ -365,8 +361,8 @@ Token counts use tiktoken `cl100k_base` — a close approximation to Claude's ac
|
|
|
365
361
|
|
|
366
362
|
agentpack uses two workflows:
|
|
367
363
|
|
|
368
|
-
- **`ci.yml`** — runs tests
|
|
369
|
-
- **`
|
|
364
|
+
- **`ci.yml`** — runs tests (Python 3.10–3.13) + ruff lint + 80% coverage gate on every push and PR to `main`
|
|
365
|
+
- **`publish.yml`** — runs on every `v*` tag push; requires tag from a `release/*` branch and a CHANGELOG.md entry for the version before building and publishing to PyPI (trusted publishing)
|
|
370
366
|
|
|
371
367
|
### Add context packing to your repo
|
|
372
368
|
|
|
@@ -588,11 +584,10 @@ Options:
|
|
|
588
584
|
| `--agent` | `auto` | Target agent (`auto` \| `claude` \| `cursor` \| `windsurf` \| `codex` \| `antigravity` \| `generic`). `auto` detects the active IDE from env and project files. |
|
|
589
585
|
| `--task` | `auto` | Task description, or `auto` to infer from git |
|
|
590
586
|
| `--mode` | `balanced` | Budget mode: `minimal`, `balanced`, `deep` |
|
|
591
|
-
| `--budget` | 25000 | Token budget |
|
|
587
|
+
| `--budget` | 0 (uses config default 25000) | Token budget |
|
|
592
588
|
| `--since` | — | Only include files changed since this git ref |
|
|
593
589
|
| `--session` | off | Re-pack on every file change (watch mode) |
|
|
594
590
|
| `--refresh` | off | Force rebuild summaries before packing |
|
|
595
|
-
| `--budget` | 25000 | Token budget override |
|
|
596
591
|
|
|
597
592
|
**Budget modes:**
|
|
598
593
|
|
|
@@ -604,26 +599,9 @@ Options:
|
|
|
604
599
|
|
|
605
600
|
---
|
|
606
601
|
|
|
607
|
-
### `agentpack session`
|
|
602
|
+
### `agentpack session` _(removed)_
|
|
608
603
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
```bash
|
|
612
|
-
agentpack session start # re-run to change agent/mode or force refresh
|
|
613
|
-
agentpack session start --agent claude # set agent (claude|cursor|codex|generic)
|
|
614
|
-
agentpack session start --task "fix bug" # change task + refresh context
|
|
615
|
-
agentpack session status # show session state + context size
|
|
616
|
-
agentpack session refresh # regenerate context now
|
|
617
|
-
agentpack session refresh --task "new task" # change task + refresh
|
|
618
|
-
agentpack session stop # mark session inactive
|
|
619
|
-
```
|
|
620
|
-
|
|
621
|
-
`agentpack init` creates (idempotently):
|
|
622
|
-
- `.agentpack/session.json` — session state
|
|
623
|
-
- `.agentpack/task.md` — current task (edit directly or use `session refresh --task`)
|
|
624
|
-
- `.agentpack/context.md` — readable context pack (updated by `watch`)
|
|
625
|
-
- `.agentpack/context.claude.md` — Claude Code format (always written alongside context.md)
|
|
626
|
-
- `.agentpack/context.compact.md` — compact protocol format
|
|
604
|
+
Session management was removed in v0.1.11. `agentpack init` bootstraps the session automatically. Use `agentpack watch` to keep context current. To change the task, edit `.agentpack/task.md`.
|
|
627
605
|
|
|
628
606
|
---
|
|
629
607
|
|
|
@@ -1241,13 +1219,14 @@ Add to `.github/workflows/agentpack-context.yml` — see the full example in [CI
|
|
|
1241
1219
|
|
|
1242
1220
|
```bash
|
|
1243
1221
|
# One-time project setup
|
|
1244
|
-
agentpack init
|
|
1222
|
+
agentpack init # creates config, session, task.md
|
|
1223
|
+
# Edit .agentpack/task.md to set your task
|
|
1245
1224
|
|
|
1246
1225
|
# Every terminal session — just one command
|
|
1247
|
-
agentpack watch
|
|
1226
|
+
agentpack watch # keeps context fresh automatically
|
|
1248
1227
|
|
|
1249
|
-
# Change task mid-session
|
|
1250
|
-
|
|
1228
|
+
# Change task mid-session: edit .agentpack/task.md directly
|
|
1229
|
+
# watch detects the change and refreshes automatically
|
|
1251
1230
|
```
|
|
1252
1231
|
|
|
1253
1232
|
---
|
|
@@ -1321,7 +1300,7 @@ agentpack init # one-time setup (creates session + task.md)
|
|
|
1321
1300
|
agentpack watch # in another terminal — auto-resumes each time
|
|
1322
1301
|
```
|
|
1323
1302
|
|
|
1324
|
-
Refreshes `.agentpack/context.md` every time you save a file. Change the task
|
|
1303
|
+
Refreshes `.agentpack/context.md` every time you save a file. Change the task by editing `.agentpack/task.md` directly — or tell Claude and it writes the file itself. `watch` picks up the change automatically.
|
|
1325
1304
|
|
|
1326
1305
|
### Debug file selection with `explain`
|
|
1327
1306
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import typer
|
|
4
|
-
from agentpack.commands import init, scan, diff, status, stats, summarize, pack, install, monitor, explain, doctor,
|
|
4
|
+
from agentpack.commands import init, scan, diff, status, stats, summarize, pack, install, monitor, explain, doctor, watch, claude_cmd, benchmark, mcp_cmd
|
|
5
5
|
from agentpack import __version__
|
|
6
6
|
|
|
7
7
|
|
|
@@ -21,7 +21,7 @@ def _main(
|
|
|
21
21
|
pass
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
for mod in [init, scan, diff, status, stats, summarize, pack, install, monitor, explain, doctor,
|
|
24
|
+
for mod in [init, scan, diff, status, stats, summarize, pack, install, monitor, explain, doctor, watch, claude_cmd, benchmark, mcp_cmd]:
|
|
25
25
|
mod.register(app)
|
|
26
26
|
|
|
27
27
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import os
|
|
5
|
+
import tempfile
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from agentpack.session.state import CONTEXT_FILE, COMPACT_FILE, TASK_FILE
|
|
13
|
+
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
_ROOT = Path(".")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _root() -> Path:
|
|
20
|
+
return _ROOT
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _now_iso() -> str:
|
|
24
|
+
return datetime.now(timezone.utc).isoformat()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _file_hash(path: Path) -> str:
|
|
28
|
+
if not path.exists():
|
|
29
|
+
return ""
|
|
30
|
+
return hashlib.sha256(path.read_bytes()).hexdigest()[:16]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _atomic_write(path: Path, text: str) -> None:
|
|
34
|
+
"""Write to a temp file in the same dir, then rename — atomic on POSIX."""
|
|
35
|
+
dir_ = path.parent
|
|
36
|
+
try:
|
|
37
|
+
fd, tmp = tempfile.mkstemp(dir=dir_, prefix=".tmp_")
|
|
38
|
+
try:
|
|
39
|
+
with os.fdopen(fd, "w", encoding="utf-8") as fh:
|
|
40
|
+
fh.write(text)
|
|
41
|
+
os.replace(tmp, path)
|
|
42
|
+
except Exception:
|
|
43
|
+
try:
|
|
44
|
+
os.unlink(tmp)
|
|
45
|
+
except OSError:
|
|
46
|
+
pass
|
|
47
|
+
raise
|
|
48
|
+
except OSError:
|
|
49
|
+
path.write_text(text, encoding="utf-8")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def run_refresh(
|
|
53
|
+
root: Path,
|
|
54
|
+
agent: str,
|
|
55
|
+
mode: str,
|
|
56
|
+
budget: int,
|
|
57
|
+
) -> Optional[dict]:
|
|
58
|
+
"""Run PackService and write context + compact files. Returns stats dict or None on error."""
|
|
59
|
+
try:
|
|
60
|
+
from agentpack.application.pack_service import PackService, PackRequest
|
|
61
|
+
from agentpack.core import git
|
|
62
|
+
from agentpack.renderers.compact import render_compact
|
|
63
|
+
from agentpack.renderers.markdown import render_generic, render_claude
|
|
64
|
+
|
|
65
|
+
task_path = root / TASK_FILE
|
|
66
|
+
if task_path.exists():
|
|
67
|
+
raw = task_path.read_text(encoding="utf-8").strip()
|
|
68
|
+
lines = [line for line in raw.splitlines() if line.strip() and not line.startswith("#")]
|
|
69
|
+
task = lines[0].strip() if lines else ""
|
|
70
|
+
else:
|
|
71
|
+
task = ""
|
|
72
|
+
|
|
73
|
+
if not task:
|
|
74
|
+
if git.is_git_repo(root):
|
|
75
|
+
task = git.infer_task_from_git(root)
|
|
76
|
+
else:
|
|
77
|
+
task = "Current branch changes and likely related files"
|
|
78
|
+
|
|
79
|
+
result = PackService().run(PackRequest(
|
|
80
|
+
root=root,
|
|
81
|
+
agent=agent,
|
|
82
|
+
task=task,
|
|
83
|
+
mode=mode,
|
|
84
|
+
budget=budget,
|
|
85
|
+
since=None,
|
|
86
|
+
refresh=False,
|
|
87
|
+
))
|
|
88
|
+
|
|
89
|
+
context_path = root / CONTEXT_FILE
|
|
90
|
+
context_path.parent.mkdir(parents=True, exist_ok=True)
|
|
91
|
+
_atomic_write(context_path, render_generic(result.pack))
|
|
92
|
+
_atomic_write(root / ".agentpack/context.claude.md", render_claude(result.pack))
|
|
93
|
+
|
|
94
|
+
compact_path = root / COMPACT_FILE
|
|
95
|
+
_atomic_write(compact_path, render_compact(result.pack))
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
"files": len(result.pack.selected_files),
|
|
99
|
+
"tokens": result.packed_tokens,
|
|
100
|
+
"saving": result.saving_pct,
|
|
101
|
+
"out_path": result.out_path,
|
|
102
|
+
}
|
|
103
|
+
except Exception as e:
|
|
104
|
+
console.print(f"[red]Error during refresh: {e}[/]")
|
|
105
|
+
return None
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import hashlib
|
|
4
3
|
import shutil
|
|
5
4
|
import subprocess
|
|
6
5
|
|
|
7
6
|
import typer
|
|
8
7
|
|
|
9
|
-
from agentpack.commands._shared import console, _root
|
|
10
|
-
from agentpack.commands.session import _run_refresh, _now_iso
|
|
8
|
+
from agentpack.commands._shared import console, _root, run_refresh, _now_iso, _file_hash
|
|
11
9
|
from agentpack.session.state import CONTEXT_FILE, TASK_FILE, load_session, log_activity, save_session
|
|
12
10
|
|
|
13
11
|
|
|
@@ -19,12 +17,11 @@ def register(app: typer.Typer) -> None:
|
|
|
19
17
|
state = load_session(root)
|
|
20
18
|
|
|
21
19
|
if state is None or not state.active:
|
|
22
|
-
console.print("[yellow]No active session.[/]")
|
|
23
|
-
console.print("Start one with: [bold]agentpack session start[/]")
|
|
20
|
+
console.print("[yellow]No active session. Run: agentpack init[/]")
|
|
24
21
|
raise typer.Exit(1)
|
|
25
22
|
|
|
26
23
|
console.print("Session active. Refreshing context...")
|
|
27
|
-
result =
|
|
24
|
+
result = run_refresh(root, state.agent, state.mode, budget=0)
|
|
28
25
|
if result:
|
|
29
26
|
console.print(
|
|
30
27
|
f"[green]✓[/] refreshed: {result['files']} files, "
|
|
@@ -32,9 +29,7 @@ def register(app: typer.Typer) -> None:
|
|
|
32
29
|
)
|
|
33
30
|
state.last_refresh_at = _now_iso()
|
|
34
31
|
state.refresh_count += 1
|
|
35
|
-
|
|
36
|
-
if task_path.exists():
|
|
37
|
-
state.last_task_hash = hashlib.sha256(task_path.read_bytes()).hexdigest()[:16]
|
|
32
|
+
state.last_task_hash = _file_hash(root / TASK_FILE)
|
|
38
33
|
save_session(root, state)
|
|
39
34
|
log_activity(root, f"claude cmd — {result['files']} files, {result['tokens']:,} tokens")
|
|
40
35
|
else:
|
|
@@ -7,7 +7,7 @@ from pathlib import Path
|
|
|
7
7
|
|
|
8
8
|
import typer
|
|
9
9
|
|
|
10
|
-
from agentpack.commands._shared import console, _root
|
|
10
|
+
from agentpack.commands._shared import console, _root, run_refresh, _file_hash, _now_iso
|
|
11
11
|
from agentpack.session.state import TASK_FILE, load_session, save_session, log_activity
|
|
12
12
|
|
|
13
13
|
|
|
@@ -15,10 +15,17 @@ _IGNORE_DIRS = {
|
|
|
15
15
|
".git", "node_modules", ".venv", "venv", "dist", "build", ".next",
|
|
16
16
|
"__pycache__", ".yarn", ".mypy_cache", ".ruff_cache", ".pytest_cache",
|
|
17
17
|
".tox", ".eggs", "*.egg-info",
|
|
18
|
+
# IDE state dirs — written constantly by editors, never user source
|
|
19
|
+
".vscode", ".idea", ".fleet",
|
|
18
20
|
}
|
|
19
21
|
_IGNORE_NAMES = {"context.md", "context.compact.md"}
|
|
22
|
+
_IGNORE_SUFFIXES = {".tsbuildinfo"} # TypeScript incremental build artifacts
|
|
20
23
|
# Ignore all .agentpack/ generated files; task.md is the sole exception (user-edited, triggers refresh)
|
|
21
24
|
|
|
25
|
+
# Adapter output paths written outside .agentpack/ (e.g. antigravity writes .agent/skills/agentpack/SKILL.md).
|
|
26
|
+
# Populated at runtime from run_refresh() return value so new adapters are covered automatically.
|
|
27
|
+
_WRITTEN_PATHS: set[str] = set()
|
|
28
|
+
|
|
22
29
|
_MAX_POLL_FILES = 50_000
|
|
23
30
|
|
|
24
31
|
|
|
@@ -75,21 +82,32 @@ def _should_ignore(path: str) -> bool:
|
|
|
75
82
|
name = Path(path).name
|
|
76
83
|
if name in _IGNORE_NAMES:
|
|
77
84
|
return True
|
|
85
|
+
if any(name.endswith(suf) for suf in _IGNORE_SUFFIXES):
|
|
86
|
+
return True
|
|
78
87
|
norm = path.replace("\\", "/")
|
|
79
88
|
# Ignore everything under .agentpack/ except task.md
|
|
80
89
|
if norm.startswith(".agentpack/") and norm != TASK_FILE:
|
|
81
90
|
return True
|
|
91
|
+
# Ignore adapter output files written outside .agentpack/ during refresh
|
|
92
|
+
if norm in _WRITTEN_PATHS:
|
|
93
|
+
return True
|
|
82
94
|
return False
|
|
83
95
|
|
|
84
96
|
|
|
85
97
|
def _run_refresh(root: Path, agent: str, mode: str, budget: int) -> None:
|
|
86
|
-
from agentpack.commands.session import _run_refresh as do_refresh, _file_hash, _now_iso
|
|
87
98
|
try:
|
|
88
|
-
result =
|
|
99
|
+
result = run_refresh(root, agent, mode, budget)
|
|
89
100
|
except Exception as e:
|
|
90
101
|
console.print(f"[dim][{_ts()}][/] [red]refresh error: {e}[/]")
|
|
91
102
|
return
|
|
92
103
|
if result:
|
|
104
|
+
# Register adapter output path so _should_ignore suppresses the write event
|
|
105
|
+
out_path = result.get("out_path")
|
|
106
|
+
if out_path is not None:
|
|
107
|
+
try:
|
|
108
|
+
_WRITTEN_PATHS.add(str(Path(out_path).relative_to(root)).replace("\\", "/"))
|
|
109
|
+
except ValueError:
|
|
110
|
+
pass
|
|
93
111
|
ts = _ts()
|
|
94
112
|
console.print(
|
|
95
113
|
f"[dim][{ts}][/] [green]refreshed:[/] {result['files']} files, "
|
|
@@ -124,7 +142,7 @@ def _watch_with_watchdog(
|
|
|
124
142
|
_run_refresh(root, agent, mode, budget)
|
|
125
143
|
|
|
126
144
|
class Handler(FileSystemEventHandler):
|
|
127
|
-
def
|
|
145
|
+
def _handle(self, event) -> None: # type: ignore[override]
|
|
128
146
|
if event.is_directory:
|
|
129
147
|
return
|
|
130
148
|
try:
|
|
@@ -137,6 +155,24 @@ def _watch_with_watchdog(
|
|
|
137
155
|
console.print(f"[dim][{_ts()}][/] task changed")
|
|
138
156
|
_pending[0] = True
|
|
139
157
|
|
|
158
|
+
# Only react to mutations — not reads (avoids inotify IN_ACCESS loop on Linux)
|
|
159
|
+
on_created = _handle
|
|
160
|
+
on_modified = _handle
|
|
161
|
+
on_deleted = _handle
|
|
162
|
+
|
|
163
|
+
def on_moved(self, event) -> None: # type: ignore[override]
|
|
164
|
+
if event.is_directory:
|
|
165
|
+
return
|
|
166
|
+
# Check both src (rename from) and dest (rename to)
|
|
167
|
+
for raw in (event.src_path, event.dest_path):
|
|
168
|
+
try:
|
|
169
|
+
path = str(Path(raw).relative_to(root))
|
|
170
|
+
except ValueError:
|
|
171
|
+
continue
|
|
172
|
+
if not _should_ignore(path):
|
|
173
|
+
_pending[0] = True
|
|
174
|
+
return
|
|
175
|
+
|
|
140
176
|
observer = Observer()
|
|
141
177
|
try:
|
|
142
178
|
observer.schedule(Handler(), str(root), recursive=True)
|
|
@@ -174,7 +174,7 @@ def serve() -> None:
|
|
|
174
174
|
Equivalent to running `agentpack session refresh`.
|
|
175
175
|
Returns summary of what was packed.
|
|
176
176
|
"""
|
|
177
|
-
from agentpack.commands.
|
|
177
|
+
from agentpack.commands._shared import run_refresh
|
|
178
178
|
from agentpack.session.state import load_session
|
|
179
179
|
from agentpack.adapters.detect import detect_agent
|
|
180
180
|
|
|
@@ -183,7 +183,7 @@ def serve() -> None:
|
|
|
183
183
|
agent = state.agent if state else detect_agent(root)
|
|
184
184
|
mode = state.mode if state else "balanced"
|
|
185
185
|
|
|
186
|
-
result =
|
|
186
|
+
result = run_refresh(root, agent, mode, 0)
|
|
187
187
|
if result is None:
|
|
188
188
|
return "Refresh failed."
|
|
189
189
|
return (
|
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import hashlib
|
|
4
|
-
import os
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Optional
|
|
7
|
-
|
|
8
|
-
import typer
|
|
9
|
-
from rich.table import Table
|
|
10
|
-
from rich import box
|
|
11
|
-
|
|
12
|
-
from agentpack.commands._shared import console, _root
|
|
13
|
-
from agentpack.session.state import (
|
|
14
|
-
CONTEXT_FILE, COMPACT_FILE, TASK_FILE, SESSION_FILE,
|
|
15
|
-
create_session, load_session, save_session, stop_session, log_activity,
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def register(app: typer.Typer) -> None:
|
|
20
|
-
session_app = typer.Typer(help="Manage AgentPack sessions.")
|
|
21
|
-
app.add_typer(session_app, name="session")
|
|
22
|
-
|
|
23
|
-
@session_app.command("start")
|
|
24
|
-
def start(
|
|
25
|
-
agent: str = typer.Option("auto", "--agent", help="Target agent (auto|claude|cursor|windsurf|codex|antigravity|generic)."),
|
|
26
|
-
mode: str = typer.Option("balanced", "--mode", help="Pack mode (minimal|balanced|deep)."),
|
|
27
|
-
task: str = typer.Option("", "--task", help="Initial task description."),
|
|
28
|
-
budget: int = typer.Option(0, "--budget", help="Token budget (0 = config default)."),
|
|
29
|
-
silent: bool = typer.Option(False, "--silent", help="Suppress all output (for use in hooks/scripts)."),
|
|
30
|
-
) -> None:
|
|
31
|
-
"""Refresh session and generate context. Optional — `agentpack init` already bootstraps the session.
|
|
32
|
-
|
|
33
|
-
Use this to change agent/mode after init, or to force a fresh context pack.
|
|
34
|
-
Idempotent: resumes existing session rather than recreating it.
|
|
35
|
-
"""
|
|
36
|
-
root = _root()
|
|
37
|
-
if silent:
|
|
38
|
-
console.quiet = True
|
|
39
|
-
|
|
40
|
-
existing = load_session(root)
|
|
41
|
-
if existing is not None:
|
|
42
|
-
# Resume: update agent/mode only if explicitly passed, then refresh
|
|
43
|
-
if agent != "auto":
|
|
44
|
-
existing.agent = agent
|
|
45
|
-
if mode != "balanced" or existing.agent == "generic":
|
|
46
|
-
# only override mode if user explicitly chose non-default
|
|
47
|
-
if mode != "balanced":
|
|
48
|
-
existing.mode = mode
|
|
49
|
-
existing.active = True
|
|
50
|
-
save_session(root, existing)
|
|
51
|
-
state = existing
|
|
52
|
-
console.print("[dim]Session resumed.[/]")
|
|
53
|
-
else:
|
|
54
|
-
state = create_session(root, agent=agent, mode=mode)
|
|
55
|
-
console.print()
|
|
56
|
-
console.print("[bold green]AgentPack session initialized.[/]")
|
|
57
|
-
console.print()
|
|
58
|
-
console.print(f" [green]✓[/] {SESSION_FILE} [dim]session state[/]")
|
|
59
|
-
console.print(f" [green]✓[/] {TASK_FILE} [dim]edit to set your task[/]")
|
|
60
|
-
|
|
61
|
-
if task:
|
|
62
|
-
(root / TASK_FILE).write_text(f"# Current Task\n\n{task}\n", encoding="utf-8")
|
|
63
|
-
|
|
64
|
-
result = _run_refresh(root, state.agent, state.mode, budget)
|
|
65
|
-
if result:
|
|
66
|
-
console.print(f" [green]✓[/] {CONTEXT_FILE} [dim]{result['files']} files, {result['tokens']:,} tokens[/]")
|
|
67
|
-
log_activity(root, f"session start — {result['files']} files, {result['tokens']:,} tokens")
|
|
68
|
-
else:
|
|
69
|
-
console.print(" [dim]✗ context generation failed — run agentpack session refresh[/]")
|
|
70
|
-
log_activity(root, "session start (context generation failed)")
|
|
71
|
-
|
|
72
|
-
console.print()
|
|
73
|
-
console.print("[bold]Next:[/]")
|
|
74
|
-
console.print(" - Run [bold]agentpack watch[/] in another terminal to auto-refresh context.")
|
|
75
|
-
console.print(" - Open your agent (Claude Code / Cursor / Windsurf / Codex / Antigravity) and ask your task normally.")
|
|
76
|
-
console.print(" - To change the task: [bold]agentpack session refresh --task \"new task\"[/]")
|
|
77
|
-
console.print()
|
|
78
|
-
|
|
79
|
-
@session_app.command("stop")
|
|
80
|
-
def stop() -> None:
|
|
81
|
-
"""Stop the current session."""
|
|
82
|
-
root = _root()
|
|
83
|
-
state = load_session(root)
|
|
84
|
-
if state is None or not state.active:
|
|
85
|
-
console.print("[yellow]No active session.[/]")
|
|
86
|
-
raise typer.Exit(1)
|
|
87
|
-
stop_session(root)
|
|
88
|
-
log_activity(root, "session stopped")
|
|
89
|
-
console.print("[dim]Session stopped.[/]")
|
|
90
|
-
|
|
91
|
-
@session_app.command("status")
|
|
92
|
-
def status() -> None:
|
|
93
|
-
"""Show current session status."""
|
|
94
|
-
root = _root()
|
|
95
|
-
state = load_session(root)
|
|
96
|
-
if state is None:
|
|
97
|
-
console.print("[yellow]No session found. Run: agentpack session start[/]")
|
|
98
|
-
raise typer.Exit(1)
|
|
99
|
-
|
|
100
|
-
tbl = Table(box=box.SIMPLE, show_header=False, padding=(0, 2))
|
|
101
|
-
tbl.add_column(style="dim")
|
|
102
|
-
tbl.add_column(style="bold")
|
|
103
|
-
tbl.add_row("active", "[green]yes[/]" if state.active else "[red]no[/]")
|
|
104
|
-
tbl.add_row("agent", state.agent)
|
|
105
|
-
tbl.add_row("mode", state.mode)
|
|
106
|
-
tbl.add_row("started", state.started_at or "—")
|
|
107
|
-
tbl.add_row("last refresh", state.last_refresh_at or "—")
|
|
108
|
-
tbl.add_row("refresh count", str(state.refresh_count))
|
|
109
|
-
tbl.add_row("context", str(root / CONTEXT_FILE))
|
|
110
|
-
console.print(tbl)
|
|
111
|
-
|
|
112
|
-
context_path = root / CONTEXT_FILE
|
|
113
|
-
if context_path.exists():
|
|
114
|
-
from agentpack.core.token_estimator import estimate_tokens
|
|
115
|
-
tokens = estimate_tokens(context_path.read_text(encoding="utf-8"))
|
|
116
|
-
console.print(f"[dim]context size: ~{tokens:,} tokens[/]")
|
|
117
|
-
|
|
118
|
-
@session_app.command("refresh")
|
|
119
|
-
def refresh(
|
|
120
|
-
task: str = typer.Option("", "--task", help="Override task for this refresh."),
|
|
121
|
-
budget: int = typer.Option(0, "--budget", help="Token budget override."),
|
|
122
|
-
) -> None:
|
|
123
|
-
"""Refresh context pack for the current session."""
|
|
124
|
-
root = _root()
|
|
125
|
-
state = load_session(root)
|
|
126
|
-
if state is None:
|
|
127
|
-
console.print("[yellow]No session. Run: agentpack session start[/]")
|
|
128
|
-
raise typer.Exit(1)
|
|
129
|
-
|
|
130
|
-
if task:
|
|
131
|
-
(root / TASK_FILE).write_text(f"# Current Task\n\n{task}\n", encoding="utf-8")
|
|
132
|
-
|
|
133
|
-
result = _run_refresh(root, state.agent, state.mode, budget)
|
|
134
|
-
if result:
|
|
135
|
-
state.last_refresh_at = _now_iso()
|
|
136
|
-
state.refresh_count += 1
|
|
137
|
-
state.last_task_hash = _file_hash(root / TASK_FILE)
|
|
138
|
-
save_session(root, state)
|
|
139
|
-
log_activity(root, f"refreshed — {result['files']} files, {result['tokens']:,} tokens")
|
|
140
|
-
console.print(f"[green]✓[/] refreshed: {result['files']} files, {result['tokens']:,} tokens, {result['saving']:.1f}% saving")
|
|
141
|
-
else:
|
|
142
|
-
console.print("[red]Refresh failed.[/]")
|
|
143
|
-
raise typer.Exit(1)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def _run_refresh(
|
|
147
|
-
root: Path,
|
|
148
|
-
agent: str,
|
|
149
|
-
mode: str,
|
|
150
|
-
budget: int,
|
|
151
|
-
) -> Optional[dict]:
|
|
152
|
-
"""Run PackService and write context + compact files. Returns stats dict or None on error."""
|
|
153
|
-
try:
|
|
154
|
-
from agentpack.application.pack_service import PackService, PackRequest
|
|
155
|
-
from agentpack.core import git
|
|
156
|
-
from agentpack.renderers.compact import render_compact
|
|
157
|
-
|
|
158
|
-
task_path = root / TASK_FILE
|
|
159
|
-
if task_path.exists():
|
|
160
|
-
raw = task_path.read_text(encoding="utf-8").strip()
|
|
161
|
-
lines = [line for line in raw.splitlines() if line.strip() and not line.startswith("#")]
|
|
162
|
-
task = lines[0].strip() if lines else ""
|
|
163
|
-
else:
|
|
164
|
-
task = ""
|
|
165
|
-
|
|
166
|
-
if not task:
|
|
167
|
-
if git.is_git_repo(root):
|
|
168
|
-
task = git.infer_task_from_git(root)
|
|
169
|
-
else:
|
|
170
|
-
task = "Current branch changes and likely related files"
|
|
171
|
-
|
|
172
|
-
result = PackService().run(PackRequest(
|
|
173
|
-
root=root,
|
|
174
|
-
agent=agent,
|
|
175
|
-
task=task,
|
|
176
|
-
mode=mode,
|
|
177
|
-
budget=budget,
|
|
178
|
-
since=None,
|
|
179
|
-
refresh=False,
|
|
180
|
-
))
|
|
181
|
-
|
|
182
|
-
# Write context files atomically — avoids partial reads if interrupted mid-write
|
|
183
|
-
from agentpack.renderers.markdown import render_generic, render_claude
|
|
184
|
-
context_path = root / CONTEXT_FILE
|
|
185
|
-
context_path.parent.mkdir(parents=True, exist_ok=True)
|
|
186
|
-
_atomic_write(context_path, render_generic(result.pack))
|
|
187
|
-
|
|
188
|
-
# Always write the claude-specific format too — the Claude Code hook reads this
|
|
189
|
-
# regardless of which agent the session was started with.
|
|
190
|
-
_atomic_write(root / ".agentpack/context.claude.md", render_claude(result.pack))
|
|
191
|
-
|
|
192
|
-
compact_text = render_compact(result.pack)
|
|
193
|
-
compact_path = root / COMPACT_FILE
|
|
194
|
-
_atomic_write(compact_path, compact_text)
|
|
195
|
-
|
|
196
|
-
return {
|
|
197
|
-
"files": len(result.pack.selected_files),
|
|
198
|
-
"tokens": result.packed_tokens,
|
|
199
|
-
"saving": result.saving_pct,
|
|
200
|
-
}
|
|
201
|
-
except Exception as e:
|
|
202
|
-
console.print(f"[red]Error during refresh: {e}[/]")
|
|
203
|
-
return None
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
def _atomic_write(path: Path, text: str) -> None:
|
|
207
|
-
"""Write to a temp file in the same dir, then rename — atomic on POSIX."""
|
|
208
|
-
import tempfile
|
|
209
|
-
dir_ = path.parent
|
|
210
|
-
try:
|
|
211
|
-
fd, tmp = tempfile.mkstemp(dir=dir_, prefix=".tmp_")
|
|
212
|
-
try:
|
|
213
|
-
with os.fdopen(fd, "w", encoding="utf-8") as fh:
|
|
214
|
-
fh.write(text)
|
|
215
|
-
os.replace(tmp, path)
|
|
216
|
-
except Exception:
|
|
217
|
-
try:
|
|
218
|
-
os.unlink(tmp)
|
|
219
|
-
except OSError:
|
|
220
|
-
pass
|
|
221
|
-
raise
|
|
222
|
-
except OSError:
|
|
223
|
-
path.write_text(text, encoding="utf-8")
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
def _now_iso() -> str:
|
|
227
|
-
from datetime import datetime, timezone
|
|
228
|
-
return datetime.now(timezone.utc).isoformat()
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def _file_hash(path: Path) -> str:
|
|
232
|
-
if not path.exists():
|
|
233
|
-
return ""
|
|
234
|
-
return hashlib.sha256(path.read_bytes()).hexdigest()[:16]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|