agentpack-cli 0.1.10__tar.gz → 0.1.12__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.
Files changed (85) hide show
  1. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/PKG-INFO +15 -35
  2. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/README.md +13 -34
  3. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/pyproject.toml +12 -1
  4. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/__init__.py +1 -1
  5. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/analysis/symbols.py +0 -1
  6. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/cli.py +2 -2
  7. agentpack_cli-0.1.12/src/agentpack/commands/_shared.py +105 -0
  8. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/benchmark.py +3 -4
  9. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/claude_cmd.py +4 -10
  10. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/doctor.py +3 -3
  11. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/explain.py +2 -2
  12. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/init.py +3 -3
  13. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/mcp_cmd.py +0 -1
  14. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/pack.py +3 -4
  15. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/stats.py +2 -3
  16. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/watch.py +26 -7
  17. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/cache.py +0 -1
  18. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/context_pack.py +0 -2
  19. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/scanner.py +1 -1
  20. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/token_estimator.py +0 -4
  21. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/mcp_server.py +2 -2
  22. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/session/state.py +1 -1
  23. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/summaries/offline.py +2 -3
  24. agentpack_cli-0.1.10/src/agentpack/commands/_shared.py +0 -13
  25. agentpack_cli-0.1.10/src/agentpack/commands/session.py +0 -234
  26. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/.gitignore +0 -0
  27. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/LICENSE +0 -0
  28. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/adapters/__init__.py +0 -0
  29. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/adapters/antigravity.py +0 -0
  30. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/adapters/base.py +0 -0
  31. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/adapters/claude.py +0 -0
  32. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/adapters/codex.py +0 -0
  33. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/adapters/cursor.py +0 -0
  34. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/adapters/detect.py +0 -0
  35. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/adapters/generic.py +0 -0
  36. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/adapters/windsurf.py +0 -0
  37. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/analysis/__init__.py +0 -0
  38. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/analysis/dependency_graph.py +0 -0
  39. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/analysis/go_imports.py +0 -0
  40. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/analysis/java_imports.py +0 -0
  41. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/analysis/js_ts_imports.py +0 -0
  42. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/analysis/python_imports.py +0 -0
  43. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/analysis/ranking.py +0 -0
  44. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/analysis/rust_imports.py +0 -0
  45. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/analysis/tests.py +0 -0
  46. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/application/__init__.py +0 -0
  47. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/application/pack_service.py +0 -0
  48. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/__init__.py +0 -0
  49. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/diff.py +0 -0
  50. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/install.py +0 -0
  51. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/monitor.py +0 -0
  52. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/scan.py +0 -0
  53. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/status.py +0 -0
  54. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/commands/summarize.py +0 -0
  55. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/__init__.py +0 -0
  56. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/bootstrap.py +0 -0
  57. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/config.py +0 -0
  58. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/diff.py +0 -0
  59. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/git.py +0 -0
  60. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/git_hooks.py +0 -0
  61. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/global_install.py +0 -0
  62. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/ignore.py +0 -0
  63. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/merkle.py +0 -0
  64. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/models.py +0 -0
  65. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/redactor.py +0 -0
  66. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/snapshot.py +0 -0
  67. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/core/vscode_tasks.py +0 -0
  68. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/data/agentpack.md +0 -0
  69. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/installers/__init__.py +0 -0
  70. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/installers/antigravity.py +0 -0
  71. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/installers/claude.py +0 -0
  72. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/installers/codex.py +0 -0
  73. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/installers/cursor.py +0 -0
  74. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/installers/windsurf.py +0 -0
  75. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/integrations/__init__.py +0 -0
  76. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/integrations/git_hooks.py +0 -0
  77. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/integrations/global_install.py +0 -0
  78. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/integrations/vscode_tasks.py +0 -0
  79. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/renderers/__init__.py +0 -0
  80. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/renderers/compact.py +0 -0
  81. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/renderers/markdown.py +0 -0
  82. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/renderers/receipts.py +0 -0
  83. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/session/__init__.py +0 -0
  84. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/summaries/__init__.py +0 -0
  85. {agentpack_cli-0.1.10 → agentpack_cli-0.1.12}/src/agentpack/summaries/base.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentpack-cli
3
- Version: 0.1.10
3
+ Version: 0.1.12
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
@@ -28,6 +28,7 @@ Requires-Dist: watchdog>=4.0.0; extra == 'all'
28
28
  Provides-Extra: dev
29
29
  Requires-Dist: mypy; extra == 'dev'
30
30
  Requires-Dist: pytest; extra == 'dev'
31
+ Requires-Dist: pytest-cov; extra == 'dev'
31
32
  Requires-Dist: ruff; extra == 'dev'
32
33
  Requires-Dist: tomli>=2.0.0; (python_version < '3.11') and extra == 'dev'
33
34
  Provides-Extra: mcp
@@ -43,7 +44,7 @@ Description-Content-Type: text/markdown
43
44
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
44
45
  [![CI](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml/badge.svg)](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
45
46
 
46
- > **Status: alpha (v0.1.9).** 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.
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.
47
48
  >
48
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.
49
50
 
@@ -234,17 +235,13 @@ agentpack watch # auto-resumes session, refreshes context on file/tas
234
235
  Then open Claude Code / Cursor / Codex and write your coding task normally.
235
236
 
236
237
  - AgentPack keeps `.agentpack/context.md` and `.agentpack/context.claude.md` fresh while `watch` is running.
237
- - To change the task: `agentpack session refresh --task "new task"` or just tell Claude and it updates `task.md` itself.
238
- - Check session state: `agentpack session status`
239
- - Force a refresh: `agentpack session refresh`
240
- - 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.
241
239
 
242
240
  ### Agent integration matrix
243
241
 
244
242
  | Agent | Automation level | Method |
245
243
  |---|---|---|
246
244
  | Claude Code (hook) | Highest | `UserPromptSubmit` hook auto-injects context |
247
- | Claude Code (session) | High | `init` + `watch` + read `context.md` |
248
245
  | Codex | Medium | `AGENTS.md` + `init` + `watch` |
249
246
  | Cursor | Medium | `.cursor/rules/agentpack.mdc` + `init` + `watch` |
250
247
  | Windsurf | Medium | `.windsurfrules` + `init` + `watch` |
@@ -403,8 +400,8 @@ Token counts use tiktoken `cl100k_base` — a close approximation to Claude's ac
403
400
 
404
401
  agentpack uses two workflows:
405
402
 
406
- - **`ci.yml`** — runs tests on Python 3.10–3.13 on every push and pull request to `main`
407
- - **`release.yml`** — runs tests then publishes to PyPI on every `v*` tag push (uses PyPI trusted publishing)
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)
408
405
 
409
406
  ### Add context packing to your repo
410
407
 
@@ -626,11 +623,10 @@ Options:
626
623
  | `--agent` | `auto` | Target agent (`auto` \| `claude` \| `cursor` \| `windsurf` \| `codex` \| `antigravity` \| `generic`). `auto` detects the active IDE from env and project files. |
627
624
  | `--task` | `auto` | Task description, or `auto` to infer from git |
628
625
  | `--mode` | `balanced` | Budget mode: `minimal`, `balanced`, `deep` |
629
- | `--budget` | 25000 | Token budget |
626
+ | `--budget` | 0 (uses config default 25000) | Token budget |
630
627
  | `--since` | — | Only include files changed since this git ref |
631
628
  | `--session` | off | Re-pack on every file change (watch mode) |
632
629
  | `--refresh` | off | Force rebuild summaries before packing |
633
- | `--budget` | 25000 | Token budget override |
634
630
 
635
631
  **Budget modes:**
636
632
 
@@ -642,26 +638,9 @@ Options:
642
638
 
643
639
  ---
644
640
 
645
- ### `agentpack session`
641
+ ### `agentpack session` _(removed)_
646
642
 
647
- Optional session management. `agentpack init` bootstraps the session automatically `session start` is only needed to change agent/mode after init or force a fresh pack.
648
-
649
- ```bash
650
- agentpack session start # re-run to change agent/mode or force refresh
651
- agentpack session start --agent claude # set agent (claude|cursor|codex|generic)
652
- agentpack session start --task "fix bug" # change task + refresh context
653
- agentpack session status # show session state + context size
654
- agentpack session refresh # regenerate context now
655
- agentpack session refresh --task "new task" # change task + refresh
656
- agentpack session stop # mark session inactive
657
- ```
658
-
659
- `agentpack init` creates (idempotently):
660
- - `.agentpack/session.json` — session state
661
- - `.agentpack/task.md` — current task (edit directly or use `session refresh --task`)
662
- - `.agentpack/context.md` — readable context pack (updated by `watch`)
663
- - `.agentpack/context.claude.md` — Claude Code format (always written alongside context.md)
664
- - `.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`.
665
644
 
666
645
  ---
667
646
 
@@ -1279,13 +1258,14 @@ Add to `.github/workflows/agentpack-context.yml` — see the full example in [CI
1279
1258
 
1280
1259
  ```bash
1281
1260
  # One-time project setup
1282
- agentpack init --task "refactor auth" # or edit .agentpack/task.md directly
1261
+ agentpack init # creates config, session, task.md
1262
+ # Edit .agentpack/task.md to set your task
1283
1263
 
1284
1264
  # Every terminal session — just one command
1285
- agentpack watch # auto-resumes session, refreshes context on every save
1265
+ agentpack watch # keeps context fresh automatically
1286
1266
 
1287
- # Change task mid-session
1288
- agentpack session refresh --task "new task"
1267
+ # Change task mid-session: edit .agentpack/task.md directly
1268
+ # watch detects the change and refreshes automatically
1289
1269
  ```
1290
1270
 
1291
1271
  ---
@@ -1359,7 +1339,7 @@ agentpack init # one-time setup (creates session + task.md)
1359
1339
  agentpack watch # in another terminal — auto-resumes each time
1360
1340
  ```
1361
1341
 
1362
- Refreshes `.agentpack/context.md` every time you save a file. Change the task with `agentpack session refresh --task "..."` — or tell Claude and it writes `task.md` itself.
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.
1363
1343
 
1364
1344
  ### Debug file selection with `explain`
1365
1345
 
@@ -5,7 +5,7 @@
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
  [![CI](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml/badge.svg)](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
7
7
 
8
- > **Status: alpha (v0.1.9).** 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.
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: `agentpack session refresh --task "new task"` or just tell Claude and it updates `task.md` itself.
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 on Python 3.10–3.13 on every push and pull request to `main`
369
- - **`release.yml`** — runs tests then publishes to PyPI on every `v*` tag push (uses PyPI trusted publishing)
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
- Optional session management. `agentpack init` bootstraps the session automatically `session start` is only needed to change agent/mode after init or force a fresh pack.
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 --task "refactor auth" # or edit .agentpack/task.md directly
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 # auto-resumes session, refreshes context on every save
1226
+ agentpack watch # keeps context fresh automatically
1248
1227
 
1249
- # Change task mid-session
1250
- agentpack session refresh --task "new task"
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 with `agentpack session refresh --task "..."` — or tell Claude and it writes `task.md` itself.
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,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentpack-cli"
3
- version = "0.1.10"
3
+ version = "0.1.12"
4
4
  description = "Token-aware context packing for AI coding agents — Claude, Cursor, Windsurf, and Codex"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -46,6 +46,7 @@ all = [
46
46
 
47
47
  dev = [
48
48
  "pytest",
49
+ "pytest-cov",
49
50
  "ruff",
50
51
  "mypy",
51
52
  "tomli>=2.0.0; python_version < '3.11'"
@@ -57,6 +58,16 @@ markers = [
57
58
  "slow: marks tests as slow (deselect with '-m \"not slow\"')",
58
59
  ]
59
60
 
61
+ [tool.coverage.run]
62
+ source = [
63
+ "src/agentpack/core",
64
+ "src/agentpack/analysis",
65
+ ]
66
+
67
+ [tool.coverage.report]
68
+ fail_under = 80
69
+ show_missing = true
70
+
60
71
  [build-system]
61
72
  requires = ["hatchling"]
62
73
  build-backend = "hatchling.build"
@@ -1,3 +1,3 @@
1
1
  """AgentPack — token-aware context packing for AI coding agents."""
2
2
 
3
- __version__ = "0.1.10"
3
+ __version__ = "0.1.12"
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
  import ast
4
4
  import re
5
5
  from pathlib import Path
6
- from typing import Literal
7
6
 
8
7
  from agentpack.core.models import Symbol
9
8
 
@@ -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, session, watch, claude_cmd, benchmark, mcp_cmd
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, session, watch, claude_cmd, benchmark, mcp_cmd]:
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
@@ -6,7 +6,6 @@ import time
6
6
  from dataclasses import dataclass, field
7
7
  from datetime import datetime, timezone
8
8
  from pathlib import Path
9
- from typing import Optional
10
9
 
11
10
  import typer
12
11
  from rich.table import Table
@@ -312,11 +311,11 @@ def _print_case_detail(result: CaseResult) -> None:
312
311
  hits = expected_set & selected_set
313
312
  misses = expected_set - selected_set
314
313
  if hits:
315
- console.print(f" [green]hit:[/] " + ", ".join(sorted(hits)))
314
+ console.print(" [green]hit:[/] " + ", ".join(sorted(hits)))
316
315
  if misses:
317
- console.print(f" [red]miss:[/] " + ", ".join(sorted(misses)))
316
+ console.print(" [red]miss:[/] " + ", ".join(sorted(misses)))
318
317
 
319
- console.print(f" [dim]top files:[/] " + ", ".join(result.selected_paths[:5]))
318
+ console.print(" [dim]top files:[/] " + ", ".join(result.selected_paths[:5]))
320
319
 
321
320
 
322
321
  def _print_summary_table(results: list[CaseResult]) -> None:
@@ -1,14 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
- import hashlib
4
3
  import shutil
5
4
  import subprocess
6
- from datetime import datetime, timezone
7
5
 
8
6
  import typer
9
7
 
10
- from agentpack.commands._shared import console, _root
11
- from agentpack.commands.session import _run_refresh, _now_iso
8
+ from agentpack.commands._shared import console, _root, run_refresh, _now_iso, _file_hash
12
9
  from agentpack.session.state import CONTEXT_FILE, TASK_FILE, load_session, log_activity, save_session
13
10
 
14
11
 
@@ -20,12 +17,11 @@ def register(app: typer.Typer) -> None:
20
17
  state = load_session(root)
21
18
 
22
19
  if state is None or not state.active:
23
- console.print("[yellow]No active session.[/]")
24
- console.print("Start one with: [bold]agentpack session start[/]")
20
+ console.print("[yellow]No active session. Run: agentpack init[/]")
25
21
  raise typer.Exit(1)
26
22
 
27
23
  console.print("Session active. Refreshing context...")
28
- result = _run_refresh(root, state.agent, state.mode, budget=0)
24
+ result = run_refresh(root, state.agent, state.mode, budget=0)
29
25
  if result:
30
26
  console.print(
31
27
  f"[green]✓[/] refreshed: {result['files']} files, "
@@ -33,9 +29,7 @@ def register(app: typer.Typer) -> None:
33
29
  )
34
30
  state.last_refresh_at = _now_iso()
35
31
  state.refresh_count += 1
36
- task_path = root / TASK_FILE
37
- if task_path.exists():
38
- state.last_task_hash = hashlib.sha256(task_path.read_bytes()).hexdigest()[:16]
32
+ state.last_task_hash = _file_hash(root / TASK_FILE)
39
33
  save_session(root, state)
40
34
  log_activity(root, f"claude cmd — {result['files']} files, {result['tokens']:,} tokens")
41
35
  else:
@@ -98,7 +98,7 @@ def register(app: typer.Typer) -> None:
98
98
  if not config_path.exists():
99
99
  console.print(f" [yellow]![/] Not initialized in {root} — run: agentpack init")
100
100
  else:
101
- console.print(f" [green]✓[/] .agentpack/config.toml present")
101
+ console.print(" [green]✓[/] .agentpack/config.toml present")
102
102
  if context_path.exists():
103
103
  import time
104
104
  age = time.time() - context_path.stat().st_mtime
@@ -127,7 +127,7 @@ def register(app: typer.Typer) -> None:
127
127
  console.print(f" [green]✓[/] Claude hooks present (local): {claude_settings}")
128
128
  _local_has_hooks = True
129
129
  else:
130
- console.print(f" [yellow]![/] Claude hooks missing (local) — run: agentpack install --agent claude")
130
+ console.print(" [yellow]![/] Claude hooks missing (local) — run: agentpack install --agent claude")
131
131
  ok = False
132
132
  except Exception:
133
133
  console.print(f" [yellow]![/] Could not parse {claude_settings}")
@@ -141,7 +141,7 @@ def register(app: typer.Typer) -> None:
141
141
  console.print(f" [green]✓[/] Claude hooks present (global): {global_claude_settings}")
142
142
  _global_has_hooks = True
143
143
  else:
144
- console.print(f" [yellow]![/] Claude hooks missing (global) — run: agentpack install --agent claude --global")
144
+ console.print(" [yellow]![/] Claude hooks missing (global) — run: agentpack install --agent claude --global")
145
145
  except Exception:
146
146
  console.print(f" [yellow]![/] Could not parse {global_claude_settings}")
147
147
  else:
@@ -212,7 +212,7 @@ def register(app: typer.Typer) -> None:
212
212
  )
213
213
 
214
214
  if near_cutoff_paths:
215
- console.print(f"\n[bold]Files near budget cutoff[/] [dim](would appear with larger budget):[/]")
215
+ console.print("\n[bold]Files near budget cutoff[/] [dim](would appear with larger budget):[/]")
216
216
  near_sorted = sorted(
217
217
  near_cutoff_paths,
218
218
  key=lambda p: -score_map.get(p, (0, []))[0],
@@ -226,7 +226,7 @@ def register(app: typer.Typer) -> None:
226
226
  )
227
227
 
228
228
  if excluded_receipts:
229
- console.print(f"\n[bold]Excluded[/] [dim](top 5 by score):[/]")
229
+ console.print("\n[bold]Excluded[/] [dim](top 5 by score):[/]")
230
230
  for r in excluded_receipts[:5]:
231
231
  score_val, _ = score_map.get(r.path, (0, []))
232
232
  console.print(
@@ -5,10 +5,10 @@ from typing import Optional
5
5
 
6
6
  import typer
7
7
 
8
- from agentpack.core.config import DEFAULT_CONFIG, CONFIG_TEMPLATE, save_config
8
+ from agentpack.core.config import DEFAULT_CONFIG, CONFIG_TEMPLATE
9
9
  from agentpack.core.ignore import DEFAULT_AGENTIGNORE
10
10
  from agentpack.commands._shared import console, _root
11
- from agentpack.session.state import load_session, create_session, save_session, SESSION_FILE, TASK_FILE
11
+ from agentpack.session.state import load_session, create_session, SESSION_FILE, TASK_FILE
12
12
 
13
13
 
14
14
  def register(app: typer.Typer) -> None:
@@ -97,7 +97,7 @@ def register(app: typer.Typer) -> None:
97
97
  if existing_session is None or force:
98
98
  from agentpack.adapters.detect import detect_agent
99
99
  resolved_agent = agent if agent != "auto" else detect_agent(root)
100
- session_state = create_session(root, agent=resolved_agent, mode=resolved_mode)
100
+ create_session(root, agent=resolved_agent, mode=resolved_mode)
101
101
  console.print(f"[green]Created[/] {SESSION_FILE} [dim]agent={resolved_agent} mode={resolved_mode}[/]")
102
102
  console.print(f"[green]Created[/] {TASK_FILE} [dim]edit to set your task[/]")
103
103
  else:
@@ -2,7 +2,6 @@ from __future__ import annotations
2
2
 
3
3
  import typer
4
4
 
5
- from agentpack.commands._shared import console
6
5
 
7
6
 
8
7
  def register(app: typer.Typer) -> None:
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import time
4
- from pathlib import Path
5
4
  from typing import Optional
6
5
 
7
6
  import typer
@@ -78,7 +77,7 @@ def _print_pack_summary(result: PackResult) -> None:
78
77
  saving_pct = result.saving_pct
79
78
  changed_files = result.changed_files
80
79
  task = result.pack.task
81
- since = None # since is not stored in PackResult; shown via changed_files
80
+ # since is not stored in PackResult; shown via changed_files
82
81
 
83
82
  stats = Table(box=box.SIMPLE, show_header=False, padding=(0, 2))
84
83
  stats.add_column(style="dim")
@@ -146,7 +145,7 @@ def _print_pack_summary(result: PackResult) -> None:
146
145
  if len(sensitive_excluded) > 10:
147
146
  console.print(f" [dim]... {len(sensitive_excluded) - 10} more[/]")
148
147
 
149
- console.print(f"\n[bold]Next step:[/]")
148
+ console.print("\n[bold]Next step:[/]")
150
149
  console.print(f" [bold white]claude < {out_path}[/]")
151
150
  console.print()
152
151
 
@@ -167,7 +166,7 @@ def _pack_watch(
167
166
  raise typer.Exit(1)
168
167
 
169
168
  root = _root()
170
- console.print(f"[bold]Watch mode active.[/] Repacking on file changes... (Ctrl+C to stop)")
169
+ console.print("[bold]Watch mode active.[/] Repacking on file changes... (Ctrl+C to stop)")
171
170
  console.print(f" Task: {task}")
172
171
 
173
172
  def _run_pack() -> None:
@@ -71,12 +71,11 @@ def register(app: typer.Typer) -> None:
71
71
 
72
72
  # --- Last context top files ---
73
73
  metrics_path = root / ".agentpack" / "metrics.jsonl"
74
- last_selected: list[dict] = []
75
74
  if metrics_path.exists():
76
- lines = [l.strip() for l in metrics_path.read_text().splitlines() if l.strip()]
75
+ lines = [line.strip() for line in metrics_path.read_text().splitlines() if line.strip()]
77
76
  if lines:
78
77
  try:
79
- last_record = json.loads(lines[-1])
78
+ json.loads(lines[-1])
80
79
  # metrics don't store per-file data — use context file for top files
81
80
  except Exception:
82
81
  pass