agentpack-cli 0.1.12__tar.gz → 0.1.14__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/PKG-INFO +1 -1
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/pyproject.toml +1 -1
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/__init__.py +1 -1
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/application/pack_service.py +58 -1
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/stats.py +40 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/watch.py +22 -1
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/.gitignore +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/LICENSE +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/README.md +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/adapters/__init__.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/adapters/antigravity.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/adapters/base.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/adapters/claude.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/adapters/codex.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/adapters/cursor.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/adapters/detect.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/adapters/generic.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/adapters/windsurf.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/analysis/__init__.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/analysis/dependency_graph.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/analysis/go_imports.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/analysis/java_imports.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/analysis/js_ts_imports.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/analysis/python_imports.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/analysis/ranking.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/analysis/rust_imports.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/analysis/symbols.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/analysis/tests.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/application/__init__.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/cli.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/__init__.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/_shared.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/benchmark.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/claude_cmd.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/diff.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/doctor.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/explain.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/init.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/install.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/mcp_cmd.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/monitor.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/pack.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/scan.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/status.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/commands/summarize.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/__init__.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/bootstrap.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/cache.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/config.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/context_pack.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/diff.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/git.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/git_hooks.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/global_install.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/ignore.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/merkle.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/models.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/redactor.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/scanner.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/snapshot.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/token_estimator.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/core/vscode_tasks.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/data/agentpack.md +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/installers/__init__.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/installers/antigravity.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/installers/claude.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/installers/codex.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/installers/cursor.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/installers/windsurf.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/integrations/__init__.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/integrations/git_hooks.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/integrations/global_install.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/integrations/vscode_tasks.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/mcp_server.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/renderers/__init__.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/renderers/compact.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/renderers/markdown.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/renderers/receipts.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/session/__init__.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/session/state.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/summaries/__init__.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/summaries/base.py +0 -0
- {agentpack_cli-0.1.12 → agentpack_cli-0.1.14}/src/agentpack/summaries/offline.py +0 -0
|
@@ -305,6 +305,8 @@ class PackService:
|
|
|
305
305
|
saving_pct=saving_pct,
|
|
306
306
|
selected_count=len(plan.selected),
|
|
307
307
|
changed_count=len(plan.all_changed),
|
|
308
|
+
selected_paths=[sf.path for sf in plan.selected],
|
|
309
|
+
current_changed=plan.all_changed,
|
|
308
310
|
)
|
|
309
311
|
|
|
310
312
|
return PackResult(
|
|
@@ -331,6 +333,56 @@ def _sf_tokens(sf: SelectedFile) -> int:
|
|
|
331
333
|
return estimate_tokens("\n".join(parts)) if parts else 50
|
|
332
334
|
|
|
333
335
|
|
|
336
|
+
def _load_last_record(metrics_path: Path) -> dict[str, Any] | None:
|
|
337
|
+
"""Return the most recent metrics record that has selected_paths."""
|
|
338
|
+
if not metrics_path.exists():
|
|
339
|
+
return None
|
|
340
|
+
try:
|
|
341
|
+
lines = metrics_path.read_text(encoding="utf-8").splitlines()
|
|
342
|
+
for line in reversed(lines):
|
|
343
|
+
line = line.strip()
|
|
344
|
+
if not line:
|
|
345
|
+
continue
|
|
346
|
+
rec = json.loads(line)
|
|
347
|
+
if rec.get("selected_paths"):
|
|
348
|
+
return rec
|
|
349
|
+
except Exception:
|
|
350
|
+
pass
|
|
351
|
+
return None
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _compute_selection_accuracy(
|
|
355
|
+
root: Path,
|
|
356
|
+
metrics_path: Path,
|
|
357
|
+
current_selected: list[str],
|
|
358
|
+
current_changed: set[str],
|
|
359
|
+
) -> dict[str, float]:
|
|
360
|
+
"""Compare previous pack's selected_paths vs files actually changed since then.
|
|
361
|
+
|
|
362
|
+
recall = |predicted ∩ actual_changed| / |actual_changed|
|
|
363
|
+
precision = |predicted ∩ actual_changed| / |predicted|
|
|
364
|
+
"""
|
|
365
|
+
prev = _load_last_record(metrics_path)
|
|
366
|
+
if prev is None:
|
|
367
|
+
return {}
|
|
368
|
+
|
|
369
|
+
prev_selected: set[str] = set(prev["selected_paths"])
|
|
370
|
+
# actual_changed = files changed since the previous pack (current git diff)
|
|
371
|
+
actual_changed: set[str] = current_changed
|
|
372
|
+
if not actual_changed or not prev_selected:
|
|
373
|
+
return {}
|
|
374
|
+
|
|
375
|
+
hits = prev_selected & actual_changed
|
|
376
|
+
recall = len(hits) / len(actual_changed)
|
|
377
|
+
precision = len(hits) / len(prev_selected)
|
|
378
|
+
f1 = (2 * precision * recall / (precision + recall)) if (precision + recall) > 0 else 0.0
|
|
379
|
+
return {
|
|
380
|
+
"selection_recall": round(recall, 3),
|
|
381
|
+
"selection_precision": round(precision, 3),
|
|
382
|
+
"selection_f1": round(f1, 3),
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
|
|
334
386
|
def _record_metrics(
|
|
335
387
|
root: Path,
|
|
336
388
|
*,
|
|
@@ -342,9 +394,12 @@ def _record_metrics(
|
|
|
342
394
|
saving_pct: float,
|
|
343
395
|
selected_count: int,
|
|
344
396
|
changed_count: int,
|
|
397
|
+
selected_paths: list[str],
|
|
398
|
+
current_changed: set[str],
|
|
345
399
|
) -> None:
|
|
346
400
|
metrics_path = root / ".agentpack" / "metrics.jsonl"
|
|
347
|
-
|
|
401
|
+
accuracy = _compute_selection_accuracy(root, metrics_path, selected_paths, current_changed)
|
|
402
|
+
record: dict[str, Any] = {
|
|
348
403
|
"ts": datetime.now(timezone.utc).isoformat(),
|
|
349
404
|
"task": task,
|
|
350
405
|
"mode": mode,
|
|
@@ -353,9 +408,11 @@ def _record_metrics(
|
|
|
353
408
|
"saving_pct": round(saving_pct, 1),
|
|
354
409
|
"selected_files": selected_count,
|
|
355
410
|
"changed_files": changed_count,
|
|
411
|
+
"selected_paths": selected_paths,
|
|
356
412
|
"phases": {k: round(v, 3) for k, v in phase_times.items()},
|
|
357
413
|
"total_s": round(sum(phase_times.values()), 3),
|
|
358
414
|
}
|
|
415
|
+
record.update(accuracy)
|
|
359
416
|
try:
|
|
360
417
|
with metrics_path.open("a") as fh:
|
|
361
418
|
fh.write(json.dumps(record) + "\n")
|
|
@@ -109,9 +109,49 @@ def register(app: typer.Typer) -> None:
|
|
|
109
109
|
top_tbl.add_row(str(i), path, mode, why)
|
|
110
110
|
console.print(top_tbl)
|
|
111
111
|
|
|
112
|
+
# --- Selection accuracy (last 10 runs) ---
|
|
113
|
+
accuracy_rows = _load_accuracy_rows(metrics_path, n=10)
|
|
114
|
+
if accuracy_rows:
|
|
115
|
+
avg_recall = sum(r["selection_recall"] for r in accuracy_rows) / len(accuracy_rows)
|
|
116
|
+
avg_precision = sum(r["selection_precision"] for r in accuracy_rows) / len(accuracy_rows)
|
|
117
|
+
avg_f1 = sum(r["selection_f1"] for r in accuracy_rows) / len(accuracy_rows)
|
|
118
|
+
console.print()
|
|
119
|
+
acc_tbl = Table(title=f"Selection Accuracy (last {len(accuracy_rows)} runs)", box=box.SIMPLE, show_header=False, padding=(0, 2))
|
|
120
|
+
acc_tbl.add_column(style="dim")
|
|
121
|
+
acc_tbl.add_column(justify="right", style="bold")
|
|
122
|
+
acc_tbl.add_row("avg recall", f"{avg_recall:.1%}")
|
|
123
|
+
acc_tbl.add_row("avg precision", f"{avg_precision:.1%}")
|
|
124
|
+
acc_tbl.add_row("avg F1", f"{avg_f1:.1%}")
|
|
125
|
+
console.print(acc_tbl)
|
|
126
|
+
console.print("[dim]recall = how many changed files were in the previous pack[/]")
|
|
127
|
+
|
|
112
128
|
console.print("[dim]'manual' = hand-picking 20 most relevant full files[/]")
|
|
113
129
|
|
|
114
130
|
|
|
131
|
+
def _load_accuracy_rows(metrics_path: Path, n: int = 10) -> list[dict]:
|
|
132
|
+
"""Return up to n most recent metrics records that have accuracy fields."""
|
|
133
|
+
if not metrics_path.exists():
|
|
134
|
+
return []
|
|
135
|
+
try:
|
|
136
|
+
lines = metrics_path.read_text(encoding="utf-8").splitlines()
|
|
137
|
+
rows = []
|
|
138
|
+
for line in reversed(lines):
|
|
139
|
+
line = line.strip()
|
|
140
|
+
if not line:
|
|
141
|
+
continue
|
|
142
|
+
try:
|
|
143
|
+
rec = json.loads(line)
|
|
144
|
+
except Exception:
|
|
145
|
+
continue
|
|
146
|
+
if "selection_recall" in rec:
|
|
147
|
+
rows.append(rec)
|
|
148
|
+
if len(rows) >= n:
|
|
149
|
+
break
|
|
150
|
+
return rows
|
|
151
|
+
except Exception:
|
|
152
|
+
return []
|
|
153
|
+
|
|
154
|
+
|
|
115
155
|
def _parse_top_files(context_path: Path) -> list[tuple[str, str, str]]:
|
|
116
156
|
"""Parse top selected files from context.md. Returns list of (path, mode, why)."""
|
|
117
157
|
results: list[tuple[str, str, str]] = []
|
|
@@ -19,6 +19,7 @@ _IGNORE_DIRS = {
|
|
|
19
19
|
".vscode", ".idea", ".fleet",
|
|
20
20
|
}
|
|
21
21
|
_IGNORE_NAMES = {"context.md", "context.compact.md"}
|
|
22
|
+
_IGNORE_SUFFIXES = {".tsbuildinfo"} # TypeScript incremental build artifacts
|
|
22
23
|
# Ignore all .agentpack/ generated files; task.md is the sole exception (user-edited, triggers refresh)
|
|
23
24
|
|
|
24
25
|
# Adapter output paths written outside .agentpack/ (e.g. antigravity writes .agent/skills/agentpack/SKILL.md).
|
|
@@ -81,6 +82,8 @@ def _should_ignore(path: str) -> bool:
|
|
|
81
82
|
name = Path(path).name
|
|
82
83
|
if name in _IGNORE_NAMES:
|
|
83
84
|
return True
|
|
85
|
+
if any(name.endswith(suf) for suf in _IGNORE_SUFFIXES):
|
|
86
|
+
return True
|
|
84
87
|
norm = path.replace("\\", "/")
|
|
85
88
|
# Ignore everything under .agentpack/ except task.md
|
|
86
89
|
if norm.startswith(".agentpack/") and norm != TASK_FILE:
|
|
@@ -139,7 +142,7 @@ def _watch_with_watchdog(
|
|
|
139
142
|
_run_refresh(root, agent, mode, budget)
|
|
140
143
|
|
|
141
144
|
class Handler(FileSystemEventHandler):
|
|
142
|
-
def
|
|
145
|
+
def _handle(self, event) -> None: # type: ignore[override]
|
|
143
146
|
if event.is_directory:
|
|
144
147
|
return
|
|
145
148
|
try:
|
|
@@ -152,6 +155,24 @@ def _watch_with_watchdog(
|
|
|
152
155
|
console.print(f"[dim][{_ts()}][/] task changed")
|
|
153
156
|
_pending[0] = True
|
|
154
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
|
+
|
|
155
176
|
observer = Observer()
|
|
156
177
|
try:
|
|
157
178
|
observer.schedule(Handler(), str(root), recursive=True)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|