agentpack-cli 0.1.1__tar.gz → 0.1.2__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 (81) hide show
  1. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/PKG-INFO +2 -2
  2. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/README.md +1 -1
  3. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/pyproject.toml +1 -1
  4. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/application/pack_service.py +6 -3
  5. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/scanner.py +27 -3
  6. agentpack_cli-0.1.2/src/agentpack/core/token_estimator.py +40 -0
  7. agentpack_cli-0.1.1/src/agentpack/core/token_estimator.py +0 -26
  8. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/.gitignore +0 -0
  9. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/LICENSE +0 -0
  10. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/__init__.py +0 -0
  11. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/adapters/__init__.py +0 -0
  12. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/adapters/base.py +0 -0
  13. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/adapters/claude.py +0 -0
  14. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/adapters/codex.py +0 -0
  15. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/adapters/cursor.py +0 -0
  16. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/adapters/generic.py +0 -0
  17. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/adapters/windsurf.py +0 -0
  18. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/analysis/__init__.py +0 -0
  19. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/analysis/dependency_graph.py +0 -0
  20. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/analysis/go_imports.py +0 -0
  21. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/analysis/java_imports.py +0 -0
  22. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/analysis/js_ts_imports.py +0 -0
  23. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/analysis/python_imports.py +0 -0
  24. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/analysis/ranking.py +0 -0
  25. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/analysis/rust_imports.py +0 -0
  26. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/analysis/symbols.py +0 -0
  27. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/analysis/tests.py +0 -0
  28. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/application/__init__.py +0 -0
  29. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/cli.py +0 -0
  30. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/__init__.py +0 -0
  31. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/_shared.py +0 -0
  32. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/benchmark.py +0 -0
  33. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/claude_cmd.py +0 -0
  34. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/diff.py +0 -0
  35. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/doctor.py +0 -0
  36. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/explain.py +0 -0
  37. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/init.py +0 -0
  38. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/install.py +0 -0
  39. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/monitor.py +0 -0
  40. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/pack.py +0 -0
  41. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/scan.py +0 -0
  42. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/session.py +0 -0
  43. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/stats.py +0 -0
  44. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/status.py +0 -0
  45. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/summarize.py +0 -0
  46. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/commands/watch.py +0 -0
  47. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/__init__.py +0 -0
  48. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/bootstrap.py +0 -0
  49. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/cache.py +0 -0
  50. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/config.py +0 -0
  51. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/context_pack.py +0 -0
  52. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/diff.py +0 -0
  53. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/git.py +0 -0
  54. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/git_hooks.py +0 -0
  55. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/global_install.py +0 -0
  56. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/ignore.py +0 -0
  57. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/merkle.py +0 -0
  58. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/models.py +0 -0
  59. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/redactor.py +0 -0
  60. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/snapshot.py +0 -0
  61. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/core/vscode_tasks.py +0 -0
  62. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/data/agentpack.md +0 -0
  63. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/installers/__init__.py +0 -0
  64. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/installers/claude.py +0 -0
  65. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/installers/codex.py +0 -0
  66. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/installers/cursor.py +0 -0
  67. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/installers/windsurf.py +0 -0
  68. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/integrations/__init__.py +0 -0
  69. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/integrations/git_hooks.py +0 -0
  70. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/integrations/global_install.py +0 -0
  71. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/integrations/vscode_tasks.py +0 -0
  72. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/renderers/__init__.py +0 -0
  73. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/renderers/compact.py +0 -0
  74. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/renderers/markdown.py +0 -0
  75. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/renderers/receipts.py +0 -0
  76. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/session/__init__.py +0 -0
  77. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/session/state.py +0 -0
  78. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/summaries/__init__.py +0 -0
  79. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/summaries/base.py +0 -0
  80. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/src/agentpack/summaries/llm.py +0 -0
  81. {agentpack_cli-0.1.1 → agentpack_cli-0.1.2}/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.1
3
+ Version: 0.1.2
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
@@ -43,7 +43,7 @@ Description-Content-Type: text/markdown
43
43
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
44
44
  [![CI](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml/badge.svg)](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
45
45
 
46
- > **Status: alpha (v0.1.1).** 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.
46
+ > **Status: alpha (v0.1.2).** 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
47
  >
48
48
  > **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
49
 
@@ -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.1).** 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.2).** 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
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentpack-cli"
3
- version = "0.1.1"
3
+ version = "0.1.2"
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"
@@ -90,9 +90,11 @@ class ChangeDetector:
90
90
  packable: list[FileInfo],
91
91
  root: Path,
92
92
  since: str | None,
93
+ previous_snap: dict | None = None,
93
94
  ) -> ChangeSet:
94
95
  current_snap = build_snapshot(packable)
95
- previous_snap = load_snapshot(root)
96
+ if previous_snap is None:
97
+ previous_snap = load_snapshot(root)
96
98
  snap_diff = diff_snapshots(previous_snap, current_snap)
97
99
  changed_from_snap: set[str] = set(snap_diff.added + snap_diff.modified)
98
100
 
@@ -160,7 +162,8 @@ class PackPlanner:
160
162
  phase_times: dict[str, float] = {}
161
163
 
162
164
  t0 = time.perf_counter()
163
- scan_result = scan(root, ignore_spec, cfg.context.max_file_tokens)
165
+ previous_snap = load_snapshot(root)
166
+ scan_result = scan(root, ignore_spec, cfg.context.max_file_tokens, previous_snapshot=previous_snap)
164
167
  phase_times["scan"] = time.perf_counter() - t0
165
168
 
166
169
  packable = scan_result.packable
@@ -175,7 +178,7 @@ class PackPlanner:
175
178
  phase_times["deps"] = time.perf_counter() - t0
176
179
 
177
180
  t0 = time.perf_counter()
178
- changes = ChangeDetector().detect(packable, root, request.since)
181
+ changes = ChangeDetector().detect(packable, root, request.since, previous_snap=previous_snap)
179
182
  phase_times["changes"] = time.perf_counter() - t0
180
183
 
181
184
  t0 = time.perf_counter()
@@ -7,7 +7,7 @@ import pathspec
7
7
 
8
8
  from agentpack.core.ignore import load_spec, is_ignored
9
9
  from agentpack.core.models import FileInfo, ScanResult
10
- from agentpack.core.token_estimator import estimate_tokens
10
+ from agentpack.core.token_estimator import estimate_tokens, estimate_tokens_bytes
11
11
 
12
12
  BINARY_EXTENSIONS = {
13
13
  ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".ico", ".svg",
@@ -54,7 +54,7 @@ LANGUAGE_MAP: dict[str, str] = {
54
54
  ".xml": "xml",
55
55
  }
56
56
 
57
- ALWAYS_SKIP = {".git", ".agentpack"}
57
+ ALWAYS_SKIP = {".git", ".agentpack", ".claude"}
58
58
 
59
59
 
60
60
  def file_hash(path: Path) -> str:
@@ -79,11 +79,14 @@ def scan(
79
79
  root: Path,
80
80
  ignore_spec: pathspec.PathSpec,
81
81
  max_file_tokens: int = 4000,
82
+ previous_snapshot: dict | None = None,
82
83
  ) -> ScanResult:
83
84
  packable: list[FileInfo] = []
84
85
  ignored: list[FileInfo] = []
85
86
  binary: list[FileInfo] = []
86
87
 
88
+ prev_files: dict[str, dict] = (previous_snapshot or {}).get("files", {})
89
+
87
90
  for abs_path in root.rglob("*"):
88
91
  if not abs_path.is_file():
89
92
  continue
@@ -125,6 +128,27 @@ def scan(
125
128
 
126
129
  size = abs_path.stat().st_size
127
130
  lang = LANGUAGE_MAP.get(abs_path.suffix.lower())
131
+ fhash = file_hash(abs_path)
132
+
133
+ # Unchanged file: reuse cached token count, skip content read.
134
+ # Content is loaded lazily by context_pack.select_files() when needed.
135
+ prev = prev_files.get(rel_str)
136
+ if prev and prev.get("hash") == fhash:
137
+ cached_tokens = prev.get("estimated_tokens", estimate_tokens_bytes(size))
138
+ too_large = cached_tokens > max_file_tokens
139
+ packable.append(
140
+ FileInfo(
141
+ path=rel_str,
142
+ abs_path=abs_path,
143
+ language=lang,
144
+ size_bytes=size,
145
+ estimated_tokens=cached_tokens,
146
+ hash=fhash,
147
+ too_large=too_large,
148
+ content=None,
149
+ )
150
+ )
151
+ continue
128
152
 
129
153
  try:
130
154
  text = abs_path.read_text(errors="replace")
@@ -141,7 +165,7 @@ def scan(
141
165
  language=lang,
142
166
  size_bytes=size,
143
167
  estimated_tokens=tokens,
144
- hash=file_hash(abs_path),
168
+ hash=fhash,
145
169
  too_large=too_large,
146
170
  content=text,
147
171
  )
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+
5
+ _encoder = None
6
+
7
+
8
+ def _get_encoder():
9
+ global _encoder
10
+ if _encoder is None:
11
+ try:
12
+ import tiktoken
13
+ # Only load tiktoken if its vocab cache already exists — avoids
14
+ # a blocking network download when running inside git hooks.
15
+ cache_dir = os.environ.get(
16
+ "TIKTOKEN_CACHE_DIR",
17
+ os.path.join(os.path.expanduser("~"), ".cache", "huggingface", "hub"),
18
+ )
19
+ tiktoken_cache = os.path.join(os.path.expanduser("~"), ".cache", "tiktoken")
20
+ cache_warm = os.path.isdir(tiktoken_cache) and any(
21
+ True for _ in os.scandir(tiktoken_cache)
22
+ ) if os.path.isdir(tiktoken_cache) else False
23
+ if cache_warm or os.environ.get("AGENTPACK_FORCE_TIKTOKEN"):
24
+ _encoder = tiktoken.get_encoding("cl100k_base")
25
+ else:
26
+ _encoder = False
27
+ except ImportError:
28
+ _encoder = False
29
+ return _encoder
30
+
31
+
32
+ def estimate_tokens(text: str) -> int:
33
+ enc = _get_encoder()
34
+ if enc:
35
+ return max(1, len(enc.encode(text, disallowed_special=())))
36
+ return max(1, len(text) // 4)
37
+
38
+
39
+ def estimate_tokens_bytes(size_bytes: int) -> int:
40
+ return max(1, size_bytes // 4)
@@ -1,26 +0,0 @@
1
- from __future__ import annotations
2
-
3
- _encoder = None
4
-
5
-
6
- def _get_encoder():
7
- global _encoder
8
- if _encoder is None:
9
- try:
10
- import tiktoken
11
- _encoder = tiktoken.get_encoding("cl100k_base")
12
- except ImportError:
13
- _encoder = False
14
- return _encoder
15
-
16
-
17
- def estimate_tokens(text: str) -> int:
18
- enc = _get_encoder()
19
- if enc:
20
- return max(1, len(enc.encode(text, disallowed_special=())))
21
- return max(1, len(text) // 4)
22
-
23
-
24
- def estimate_tokens_bytes(size_bytes: int) -> int:
25
- # byte-level fallback when text is unavailable
26
- return max(1, size_bytes // 4)
File without changes
File without changes