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.
Files changed (85) hide show
  1. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/PKG-INFO +14 -35
  2. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/README.md +13 -34
  3. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/pyproject.toml +1 -1
  4. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/__init__.py +1 -1
  5. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/cli.py +2 -2
  6. agentpack_cli-0.1.13/src/agentpack/commands/_shared.py +105 -0
  7. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/claude_cmd.py +4 -9
  8. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/watch.py +40 -4
  9. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/mcp_server.py +2 -2
  10. agentpack_cli-0.1.11/src/agentpack/commands/_shared.py +0 -13
  11. agentpack_cli-0.1.11/src/agentpack/commands/session.py +0 -234
  12. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/.gitignore +0 -0
  13. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/LICENSE +0 -0
  14. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/__init__.py +0 -0
  15. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/antigravity.py +0 -0
  16. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/base.py +0 -0
  17. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/claude.py +0 -0
  18. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/codex.py +0 -0
  19. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/cursor.py +0 -0
  20. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/detect.py +0 -0
  21. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/generic.py +0 -0
  22. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/adapters/windsurf.py +0 -0
  23. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/__init__.py +0 -0
  24. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/dependency_graph.py +0 -0
  25. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/go_imports.py +0 -0
  26. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/java_imports.py +0 -0
  27. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/js_ts_imports.py +0 -0
  28. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/python_imports.py +0 -0
  29. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/ranking.py +0 -0
  30. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/rust_imports.py +0 -0
  31. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/symbols.py +0 -0
  32. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/analysis/tests.py +0 -0
  33. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/application/__init__.py +0 -0
  34. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/application/pack_service.py +0 -0
  35. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/__init__.py +0 -0
  36. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/benchmark.py +0 -0
  37. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/diff.py +0 -0
  38. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/doctor.py +0 -0
  39. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/explain.py +0 -0
  40. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/init.py +0 -0
  41. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/install.py +0 -0
  42. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/mcp_cmd.py +0 -0
  43. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/monitor.py +0 -0
  44. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/pack.py +0 -0
  45. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/scan.py +0 -0
  46. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/stats.py +0 -0
  47. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/status.py +0 -0
  48. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/commands/summarize.py +0 -0
  49. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/__init__.py +0 -0
  50. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/bootstrap.py +0 -0
  51. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/cache.py +0 -0
  52. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/config.py +0 -0
  53. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/context_pack.py +0 -0
  54. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/diff.py +0 -0
  55. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/git.py +0 -0
  56. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/git_hooks.py +0 -0
  57. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/global_install.py +0 -0
  58. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/ignore.py +0 -0
  59. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/merkle.py +0 -0
  60. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/models.py +0 -0
  61. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/redactor.py +0 -0
  62. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/scanner.py +0 -0
  63. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/snapshot.py +0 -0
  64. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/token_estimator.py +0 -0
  65. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/core/vscode_tasks.py +0 -0
  66. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/data/agentpack.md +0 -0
  67. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/__init__.py +0 -0
  68. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/antigravity.py +0 -0
  69. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/claude.py +0 -0
  70. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/codex.py +0 -0
  71. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/cursor.py +0 -0
  72. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/installers/windsurf.py +0 -0
  73. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/integrations/__init__.py +0 -0
  74. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/integrations/git_hooks.py +0 -0
  75. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/integrations/global_install.py +0 -0
  76. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/integrations/vscode_tasks.py +0 -0
  77. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/renderers/__init__.py +0 -0
  78. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/renderers/compact.py +0 -0
  79. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/renderers/markdown.py +0 -0
  80. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/renderers/receipts.py +0 -0
  81. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/session/__init__.py +0 -0
  82. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/session/state.py +0 -0
  83. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/summaries/__init__.py +0 -0
  84. {agentpack_cli-0.1.11 → agentpack_cli-0.1.13}/src/agentpack/summaries/base.py +0 -0
  85. {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.11
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
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
45
45
  [![CI](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml/badge.svg)](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
46
46
 
47
- > **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.
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: `agentpack session refresh --task "new task"` or just tell Claude and it updates `task.md` itself.
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 on Python 3.10–3.13 on every push and pull request to `main`
408
- - **`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)
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
- 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.
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 --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
1284
1263
 
1285
1264
  # Every terminal session — just one command
1286
- agentpack watch # auto-resumes session, refreshes context on every save
1265
+ agentpack watch # keeps context fresh automatically
1287
1266
 
1288
- # Change task mid-session
1289
- agentpack session refresh --task "new task"
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 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.
1364
1343
 
1365
1344
  ### Debug file selection with `explain`
1366
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.11"
3
+ version = "0.1.13"
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"
@@ -1,3 +1,3 @@
1
1
  """AgentPack — token-aware context packing for AI coding agents."""
2
2
 
3
- __version__ = "0.1.11"
3
+ __version__ = "0.1.13"
@@ -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
@@ -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 = _run_refresh(root, state.agent, state.mode, budget=0)
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
- task_path = root / TASK_FILE
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 = do_refresh(root, agent, mode, budget)
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 on_any_event(self, event): # type: ignore[override]
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.session import _run_refresh
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 = _run_refresh(root, agent, mode, 0)
186
+ result = run_refresh(root, agent, mode, 0)
187
187
  if result is None:
188
188
  return "Refresh failed."
189
189
  return (
@@ -1,13 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from pathlib import Path
4
-
5
- from rich.console import Console
6
-
7
- console = Console()
8
-
9
- _ROOT = Path(".")
10
-
11
-
12
- def _root() -> Path:
13
- return _ROOT
@@ -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