agentpack-cli 0.3.25__tar.gz → 0.3.26__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 (162) hide show
  1. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/PKG-INFO +1 -1
  2. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/pyproject.toml +1 -1
  3. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/__init__.py +1 -1
  4. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/application/pack_service.py +7 -0
  5. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/benchmark.py +20 -0
  6. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/doctor.py +37 -4
  7. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/next_cmd.py +4 -3
  8. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/pack.py +3 -2
  9. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/start_cmd.py +2 -3
  10. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/status.py +2 -1
  11. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/task_cmd.py +3 -2
  12. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/workflow_cmd.py +5 -3
  13. agentpack_cli-0.3.26/src/agentpack/core/command_surface.py +127 -0
  14. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/context_pack.py +12 -1
  15. agentpack_cli-0.3.26/src/agentpack/core/e2e_benchmark.py +75 -0
  16. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/data/agentpack.md +7 -7
  17. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/data/codex_plugin/.codex-plugin/plugin.json +1 -1
  18. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/data/codex_plugin/skills/agentpack-refresh.md +3 -3
  19. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/installers/antigravity.py +19 -9
  20. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/installers/claude.py +23 -9
  21. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/installers/codex.py +19 -9
  22. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/installers/cursor.py +23 -25
  23. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/installers/windsurf.py +20 -10
  24. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/integrations/agents.py +11 -9
  25. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/integrations/vscode_tasks.py +5 -2
  26. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/mcp_server.py +56 -0
  27. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/renderers/markdown.py +14 -3
  28. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/router/models.py +5 -0
  29. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/router/prompt_builder.py +19 -0
  30. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/router/service.py +239 -1
  31. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/.gitignore +0 -0
  32. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/LICENSE +0 -0
  33. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/README.md +0 -0
  34. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/adapters/__init__.py +0 -0
  35. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/adapters/antigravity.py +0 -0
  36. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/adapters/base.py +0 -0
  37. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/adapters/claude.py +0 -0
  38. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/adapters/codex.py +0 -0
  39. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/adapters/cursor.py +0 -0
  40. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/adapters/detect.py +0 -0
  41. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/adapters/generic.py +0 -0
  42. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/adapters/windsurf.py +0 -0
  43. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/__init__.py +0 -0
  44. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/dependency_graph.py +0 -0
  45. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/go_imports.py +0 -0
  46. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/java_imports.py +0 -0
  47. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/js_ts_imports.py +0 -0
  48. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/monorepo.py +0 -0
  49. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/naming_signals.py +0 -0
  50. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/python_ast.py +0 -0
  51. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/python_imports.py +0 -0
  52. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/ranking.py +0 -0
  53. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/repo_map.py +0 -0
  54. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/role_inference.py +0 -0
  55. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/rust_imports.py +0 -0
  56. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/symbols.py +0 -0
  57. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/task_classifier.py +0 -0
  58. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/analysis/tests.py +0 -0
  59. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/application/__init__.py +0 -0
  60. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/cli.py +0 -0
  61. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/__init__.py +0 -0
  62. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/_shared.py +0 -0
  63. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/ci_cmd.py +0 -0
  64. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/claude_cmd.py +0 -0
  65. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/compress_output.py +0 -0
  66. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/dashboard.py +0 -0
  67. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/dev_check.py +0 -0
  68. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/diagnose_selection.py +0 -0
  69. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/diff.py +0 -0
  70. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/eval_cmd.py +0 -0
  71. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/explain.py +0 -0
  72. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/guard.py +0 -0
  73. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/hook_cmd.py +0 -0
  74. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/ignore_cmd.py +0 -0
  75. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/init.py +0 -0
  76. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/install.py +0 -0
  77. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/learn.py +0 -0
  78. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/mcp_cmd.py +0 -0
  79. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/memory.py +0 -0
  80. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/migrate.py +0 -0
  81. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/monitor.py +0 -0
  82. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/perf.py +0 -0
  83. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/quickstart.py +0 -0
  84. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/release_check.py +0 -0
  85. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/release_cmd.py +0 -0
  86. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/repair.py +0 -0
  87. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/retrieve.py +0 -0
  88. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/route.py +0 -0
  89. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/scan.py +0 -0
  90. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/skills.py +0 -0
  91. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/state_cmd.py +0 -0
  92. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/stats.py +0 -0
  93. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/summarize.py +0 -0
  94. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/threads.py +0 -0
  95. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/tune.py +0 -0
  96. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/upgrade.py +0 -0
  97. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/verify_wheel.py +0 -0
  98. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/watch.py +0 -0
  99. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/commands/wrap.py +0 -0
  100. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/__init__.py +0 -0
  101. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/bootstrap.py +0 -0
  102. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/cache.py +0 -0
  103. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/changed_paths.py +0 -0
  104. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/config.py +0 -0
  105. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/diff.py +0 -0
  106. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/evals.py +0 -0
  107. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/execution_state.py +0 -0
  108. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/git.py +0 -0
  109. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/git_hooks.py +0 -0
  110. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/global_install.py +0 -0
  111. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/ignore.py +0 -0
  112. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/loop_protocol.py +0 -0
  113. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/merkle.py +0 -0
  114. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/models.py +0 -0
  115. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/modes.py +0 -0
  116. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/pack_registry.py +0 -0
  117. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/redactor.py +0 -0
  118. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/scanner.py +0 -0
  119. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/snapshot.py +0 -0
  120. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/task_freshness.py +0 -0
  121. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/thread_context.py +0 -0
  122. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/token_estimator.py +0 -0
  123. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/core/vscode_tasks.py +0 -0
  124. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/dashboard/__init__.py +0 -0
  125. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/dashboard/collectors.py +0 -0
  126. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/dashboard/models.py +0 -0
  127. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/dashboard/renderers.py +0 -0
  128. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/data/codex_plugin/skills/agentpack-pack.md +0 -0
  129. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/data/codex_plugin/skills/agentpack-review.md +0 -0
  130. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/data/codex_plugin/skills/agentpack-route.md +0 -0
  131. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/data/codex_plugin/skills/agentpack.md +0 -0
  132. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/installers/__init__.py +0 -0
  133. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/integrations/__init__.py +0 -0
  134. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/integrations/git_hooks.py +0 -0
  135. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/integrations/global_install.py +0 -0
  136. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/integrations/platform.py +0 -0
  137. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/learning/__init__.py +0 -0
  138. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/learning/collector.py +0 -0
  139. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/learning/extractor.py +0 -0
  140. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/learning/feedback.py +0 -0
  141. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/learning/lesson_ranker.py +0 -0
  142. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/learning/models.py +0 -0
  143. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/learning/provider.py +0 -0
  144. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/learning/quality.py +0 -0
  145. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/learning/renderers.py +0 -0
  146. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/learning/skill_map.py +0 -0
  147. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/output_compression/__init__.py +0 -0
  148. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/output_compression/core.py +0 -0
  149. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/renderers/__init__.py +0 -0
  150. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/renderers/compact.py +0 -0
  151. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/renderers/receipts.py +0 -0
  152. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/router/__init__.py +0 -0
  153. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/router/discovery.py +0 -0
  154. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/router/parser.py +0 -0
  155. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/router/scoring.py +0 -0
  156. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/router/skills_index.py +0 -0
  157. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/session/__init__.py +0 -0
  158. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/session/events.py +0 -0
  159. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/session/state.py +0 -0
  160. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/summaries/__init__.py +0 -0
  161. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/src/agentpack/summaries/base.py +0 -0
  162. {agentpack_cli-0.3.25 → agentpack_cli-0.3.26}/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.3.25
3
+ Version: 0.3.26
4
4
  Summary: Local context engine for AI coding agents that ranks relevant repo files and builds compact task-focused context packs for Claude Code, Codex, Cursor, Windsurf, MCP, and CI workflows.
5
5
  Project-URL: Homepage, https://github.com/vishal2612200/agentpack
6
6
  Project-URL: Documentation, https://vishal2612200.github.io/agentpack/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentpack-cli"
3
- version = "0.3.25"
3
+ version = "0.3.26"
4
4
  description = "Local context engine for AI coding agents that ranks relevant repo files and builds compact task-focused context packs for Claude Code, Codex, Cursor, Windsurf, MCP, and CI workflows."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -1,3 +1,3 @@
1
1
  """AgentPack — task-aware context packing for AI coding agents."""
2
2
 
3
- __version__ = "0.3.25"
3
+ __version__ = "0.3.26"
@@ -9,6 +9,7 @@ from datetime import datetime, timezone
9
9
  from pathlib import Path
10
10
  from typing import Any
11
11
 
12
+ from agentpack import __version__
12
13
  from agentpack.core.config import load_config
13
14
  from agentpack.core.changed_paths import clear_changed_paths, read_changed_paths
14
15
  from agentpack.core.ignore import DEFAULT_AGENTIGNORE, load_spec
@@ -16,6 +17,7 @@ from agentpack.core.scanner import scan, scan_incremental
16
17
  from agentpack.core.snapshot import build_snapshot, save_snapshot, load_snapshot
17
18
  from agentpack.core.diff import diff_snapshots
18
19
  from agentpack.core import git
20
+ from agentpack.core.command_surface import refresh_commands
19
21
  from agentpack.core.context_pack import enrich_call_site_scores, select_files, save_pack_metadata, load_pack_metadata
20
22
  from agentpack.core.execution_state import build_execution_state, compact_execution_state
21
23
  from agentpack.core.models import (
@@ -1575,7 +1577,12 @@ def _build_freshness_metadata(
1575
1577
  ) -> dict[str, Any]:
1576
1578
  dirty = git.dirty_files(root) if git.is_git_repo(root) else set()
1577
1579
  metadata: dict[str, Any] = {
1580
+ "agentpack_version": __version__,
1578
1581
  "generated_at": datetime.now(timezone.utc).isoformat(),
1582
+ "cwd": str(Path.cwd()),
1583
+ "git_root": str(root),
1584
+ "worktree_path": str(root),
1585
+ "source_command": refresh_commands(request.agent).primary,
1579
1586
  "task_source": request.task_source,
1580
1587
  "changed_files_source": plan.changed_files_source,
1581
1588
  "snapshot_root_hash": snapshot_root_hash,
@@ -166,6 +166,7 @@ class E2EResult:
166
166
  expected_files_touched: list[str]
167
167
  missing_expected_edits: list[str]
168
168
  unexpected_files_touched: list[str]
169
+ agentpack_noise: list[str]
169
170
  agent_log_path: str
170
171
  test_log_path: str
171
172
  workdir: str
@@ -3226,6 +3227,7 @@ def _e2e_strategy_metrics(records: list[dict[str, Any]], strategy: str) -> dict[
3226
3227
  return {
3227
3228
  "runs": float(len(subset)),
3228
3229
  "success_rate": sum(1 for row in subset if row.get("passed")) / len(subset),
3230
+ "noise_rate": sum(1 for row in subset if row.get("agentpack_noise")) / len(subset),
3229
3231
  "expected_touch_rate": expected_touch_rate,
3230
3232
  "avg_input_tokens": avg("input_tokens"),
3231
3233
  "avg_output_tokens": avg("agent_output_tokens"),
@@ -3285,6 +3287,7 @@ def _print_e2e_ab_table(
3285
3287
  table.add_row("runs", f"{base['runs']:.0f}", f"{treat['runs']:.0f}", "-")
3286
3288
  table.add_row("task success", f"{base['success_rate']:.0%}", f"{treat['success_rate']:.0%}", f"{deltas['success_rate_pp']:+.1f} pp")
3287
3289
  table.add_row("expected file touched", f"{base['expected_touch_rate']:.0%}", f"{treat['expected_touch_rate']:.0%}", "-")
3290
+ table.add_row("AgentPack noise cases", f"{base['noise_rate']:.0%}", f"{treat['noise_rate']:.0%}", "-")
3288
3291
  table.add_row("tool calls", f"{base['avg_tool_calls']:.1f}", f"{treat['avg_tool_calls']:.1f}", f"{deltas['tool_calls_saved']:+.1f}")
3289
3292
  table.add_row("tokens", f"{base['avg_total_tokens']:,.0f}", f"{treat['avg_total_tokens']:,.0f}", f"{deltas['tokens_saved']:+,.0f}")
3290
3293
  table.add_row("cost", f"${base['avg_total_cost_usd']:.4f}", f"${treat['avg_total_cost_usd']:.4f}", _fmt_signed_usd(deltas["token_cost_saved_usd"]))
@@ -3317,6 +3320,7 @@ def _e2e_ab_markdown(
3317
3320
  f"| runs | {base['runs']:.0f} | {treat['runs']:.0f} | - |",
3318
3321
  f"| task success | {base['success_rate']:.0%} | {treat['success_rate']:.0%} | {deltas['success_rate_pp']:+.1f} pp |",
3319
3322
  f"| expected file touched | {base['expected_touch_rate']:.0%} | {treat['expected_touch_rate']:.0%} | - |",
3323
+ f"| AgentPack noise cases | {base['noise_rate']:.0%} | {treat['noise_rate']:.0%} | - |",
3320
3324
  f"| tool calls | {base['avg_tool_calls']:.1f} | {treat['avg_tool_calls']:.1f} | {deltas['tool_calls_saved']:+.1f} |",
3321
3325
  f"| tokens | {base['avg_total_tokens']:,.0f} | {treat['avg_total_tokens']:,.0f} | {deltas['tokens_saved']:+,.0f} |",
3322
3326
  f"| token cost | ${base['avg_total_cost_usd']:.4f} | ${treat['avg_total_cost_usd']:.4f} | {_fmt_signed_usd(deltas['token_cost_saved_usd'])} |",
@@ -3410,6 +3414,7 @@ def _run_e2e_case(
3410
3414
  expected_touched = _expected_files_touched(public_changed, case.expected_edit_paths)
3411
3415
  missing_expected = sorted(set(case.expected_edit_paths) - set(expected_touched))
3412
3416
  unexpected_touched = _unexpected_files_touched(public_changed, case.expected_edit_paths)
3417
+ agentpack_noise = _agentpack_noise(strategy, unexpected_touched, missing_expected, public_changed)
3413
3418
  time_to_first_expected_file = _time_to_first_expected_file(repo, expected_touched, agent_start_epoch)
3414
3419
  tool_calls = _estimate_agent_tool_calls(agent)
3415
3420
  duration = time.perf_counter() - start
@@ -3442,6 +3447,7 @@ def _run_e2e_case(
3442
3447
  expected_files_touched=expected_touched,
3443
3448
  missing_expected_edits=missing_expected,
3444
3449
  unexpected_files_touched=unexpected_touched,
3450
+ agentpack_noise=agentpack_noise,
3445
3451
  agent_log_path=str(agent_log_path),
3446
3452
  test_log_path=str(test_log_path),
3447
3453
  workdir=str(work_root),
@@ -3495,6 +3501,20 @@ def _unexpected_files_touched(changed: list[str], expected_edit_paths: list[str]
3495
3501
  return sorted(path for path in changed if path not in expected)
3496
3502
 
3497
3503
 
3504
+ def _agentpack_noise(strategy: str, unexpected: list[str], missing_expected: list[str], changed: list[str]) -> list[str]:
3505
+ if "agentpack" not in strategy:
3506
+ return []
3507
+ noise: list[str] = []
3508
+ if unexpected:
3509
+ noise.append(f"unexpected edits: {', '.join(unexpected[:5])}")
3510
+ if missing_expected:
3511
+ noise.append(f"missed expected files: {', '.join(missing_expected[:5])}")
3512
+ generated = [path for path in changed if _is_generated_e2e_path(path)]
3513
+ if generated:
3514
+ noise.append(f"generated AgentPack files changed: {', '.join(generated[:5])}")
3515
+ return noise
3516
+
3517
+
3498
3518
  def _process_output_tokens(result: subprocess.CompletedProcess[str]) -> int:
3499
3519
  return estimate_tokens("\n".join(part for part in (result.stdout, result.stderr) if part))
3500
3520
 
@@ -17,6 +17,7 @@ from agentpack.integrations.global_install import (
17
17
  _detect_rc_file,
18
18
  )
19
19
  from agentpack.commands._shared import console, _root
20
+ from agentpack.core.command_surface import available_cli_commands, installed_cli_status, refresh_commands
20
21
  from agentpack.core.context_pack import load_pack_metadata
21
22
  from agentpack.core.ignore import agentignore_sync_status, format_import_summary
22
23
  from agentpack.core.task_freshness import task_freshness
@@ -45,7 +46,12 @@ def register(app: typer.Typer) -> None:
45
46
 
46
47
  # --- CLI binary ---
47
48
  console.print("[bold]CLI[/]")
48
- binary = shutil.which("agentpack")
49
+ cli_status = installed_cli_status()
50
+ binary = cli_status.get("binary") or shutil.which("agentpack")
51
+ console.print(f" [green]✓[/] importable AgentPack version: {cli_status.get('agentpack_version')}")
52
+ importable = cli_status.get("importable_commands") or []
53
+ if importable:
54
+ console.print(f" [green]✓[/] importable commands: {', '.join(str(cmd) for cmd in importable)}")
49
55
  if binary:
50
56
  try:
51
57
  result = subprocess.run(["agentpack", "--version"], capture_output=True, text=True)
@@ -56,6 +62,15 @@ def register(app: typer.Typer) -> None:
56
62
  else:
57
63
  console.print(" [red]✗[/] agentpack not on PATH — run: pipx install agentpack-cli")
58
64
  ok = False
65
+ help_commands = cli_status.get("help_commands") or []
66
+ if help_commands:
67
+ console.print(f" [green]✓[/] installed CLI commands: {', '.join(str(cmd) for cmd in help_commands)}")
68
+ if binary and "guard" not in set(str(cmd) for cmd in help_commands) and "guard" in set(available_cli_commands()):
69
+ console.print(
70
+ " [yellow]![/] installed CLI command surface may be stale; "
71
+ f"exact repair: {cli_status.get('repair_command')}"
72
+ )
73
+ ok = False
59
74
 
60
75
  try:
61
76
  root = _root()
@@ -147,8 +162,19 @@ def register(app: typer.Typer) -> None:
147
162
  "MCP get_context auto-refreshes this, or run: agentpack pack --task auto"
148
163
  )
149
164
  ok = False
165
+ meta = load_pack_metadata(root) or {}
166
+ freshness = meta.get("freshness") or {}
167
+ if freshness:
168
+ console.print(
169
+ " [green]✓[/] context provenance: "
170
+ f"task_source={freshness.get('task_source', 'unknown')}, "
171
+ f"git_root={freshness.get('git_root', root)}, "
172
+ f"worktree={freshness.get('worktree_path', root)}, "
173
+ f"branch={freshness.get('git_branch', 'unknown')}, "
174
+ f"generated={freshness.get('generated_at', 'unknown')}"
175
+ )
150
176
  else:
151
- console.print(" [yellow]![/] No context pack yet — write .agentpack/task.md, then run: agentpack pack --task auto")
177
+ console.print(f" [yellow]![/] No context pack yet — write .agentpack/task.md, then run: {refresh_commands(agent).context_missing}")
152
178
 
153
179
  # --- Agent-specific config ---
154
180
  console.print("\n[bold]Agent config[/]")
@@ -249,6 +275,14 @@ def register(app: typer.Typer) -> None:
249
275
  pass
250
276
  if not _local_has_mcp and not _global_has_mcp:
251
277
  console.print(" [yellow]![/] MCP server not registered — mcp__agentpack__* tools unavailable")
278
+ console.print(" [yellow]![/] exact repair: agentpack install --agent claude")
279
+ ok = False
280
+ else:
281
+ console.print(
282
+ " [green]✓[/] expected MCP tools: "
283
+ "readiness, route_task, pack_context, get_context, refresh, get_stats"
284
+ )
285
+ console.print(" [green]✓[/] live exposure proof: call MCP tool `readiness` from the agent host")
252
286
 
253
287
  # --- Agent integration matrix ---
254
288
  console.print("\n[bold]Agent integration audit[/]")
@@ -268,8 +302,7 @@ def register(app: typer.Typer) -> None:
268
302
  ok = False
269
303
  if not selected_ok:
270
304
  console.print(
271
- f" [yellow]![/] executable guard repair: "
272
- f"agentpack guard --agent {selected} --repair-stale --refresh-context"
305
+ f" [yellow]![/] exact repair: {refresh_commands(selected).repair}"
273
306
  )
274
307
 
275
308
  # --- Concurrent threads ---
@@ -7,6 +7,7 @@ import typer
7
7
  from agentpack.commands._shared import console, _root, run_refresh
8
8
  from agentpack.commands.diagnose_selection import build_selection_diagnosis, _markdown_report
9
9
  from agentpack.commands.guard import _context_is_fresh
10
+ from agentpack.core.command_surface import refresh_commands
10
11
  from agentpack.core.config import load_config
11
12
  from agentpack.core.context_pack import load_pack_metadata
12
13
  from agentpack.core.loop_protocol import load_loop_state
@@ -34,7 +35,7 @@ def register(app: typer.Typer) -> None:
34
35
  stats = run_refresh(root, "auto", "balanced", 0)
35
36
  if stats:
36
37
  recommendations = [{"kind": "fixed", "command": "agentpack next", "reason": "refreshed stale context"}]
37
- fixes.append({"kind": "stale_context", "command": "agentpack guard --agent auto --repair-stale --refresh-context", "returncode": 0})
38
+ fixes.append({"kind": "stale_context", "command": refresh_commands("auto").repair, "returncode": 0})
38
39
  payload = {"recommendations": recommendations, "fixes": fixes, "ok": not recommendations}
39
40
  if json_output:
40
41
  typer.echo(json.dumps(payload, indent=2, sort_keys=True))
@@ -58,7 +59,7 @@ def _recommendations(root) -> list[dict[str, str]]:
58
59
  items.append({"kind": "missing_task", "command": 'agentpack start "describe the task"', "reason": "no concrete task is set"})
59
60
  fresh, reason = _context_is_fresh(root)
60
61
  if not fresh:
61
- items.append({"kind": "stale_context", "command": "agentpack guard --agent auto --repair-stale --refresh-context", "reason": reason})
62
+ items.append({"kind": "stale_context", "command": refresh_commands("auto").repair, "reason": reason})
62
63
  if _has_thread_conflicts(root):
63
64
  items.append({"kind": "thread_conflict", "command": "agentpack threads --conflicts", "reason": "active threads overlap on this branch/worktree"})
64
65
  if _pack_looks_noisy(root):
@@ -138,7 +139,7 @@ def _fix_all_safe(root, recommendations: list[dict[str, str]]) -> tuple[list[dic
138
139
  stats = run_refresh(root, "auto", "balanced", 0)
139
140
  fixes.append({
140
141
  "kind": "stale_context",
141
- "command": "agentpack guard --agent auto --repair-stale --refresh-context",
142
+ "command": refresh_commands("auto").repair,
142
143
  "returncode": 0 if stats else 1,
143
144
  })
144
145
  recommendations = _recommendations(root)
@@ -17,6 +17,7 @@ from agentpack.analysis.ranking import suggest_task_rewrite
17
17
  from agentpack.application.pack_service import PackRequest, PackService, PackResult
18
18
  from agentpack.commands._shared import console, _root, _file_hash, _now_iso
19
19
  from agentpack.core.changed_paths import record_changed_paths
20
+ from agentpack.core.command_surface import refresh_commands
20
21
  from agentpack.core.modes import MODE_HELP, invalid_mode_message, is_requested_mode
21
22
  from agentpack.integrations.agents import check_agent_integration, install_agent_integration
22
23
  from agentpack.session.state import TASK_FILE, load_session, save_session, log_activity
@@ -314,7 +315,7 @@ def _agent_integration_warnings(result: PackResult) -> list[str]:
314
315
  if not failing:
315
316
  return []
316
317
  return [
317
- f"Agent integration needs repair ({agent}); run `agentpack guard --agent {agent} --repair-stale --refresh-context`."
318
+ f"Agent integration needs repair ({agent}); run `{refresh_commands(agent).repair}`."
318
319
  ]
319
320
 
320
321
 
@@ -337,7 +338,7 @@ def _auto_repair_stale_agent_rules(agent: str) -> None:
337
338
  except Exception as exc:
338
339
  console.print(
339
340
  f"[yellow]Stale AgentPack integration detected for {agent}; "
340
- f"run `agentpack guard --agent {agent} --repair-stale --refresh-context`. ({exc})[/]"
341
+ f"run `{refresh_commands(agent).repair}`. ({exc})[/]"
341
342
  )
342
343
 
343
344
 
@@ -6,6 +6,7 @@ from pathlib import Path
6
6
  import typer
7
7
 
8
8
  from agentpack.commands._shared import console, _root
9
+ from agentpack.core.command_surface import refresh_command_args
9
10
  from agentpack.core.context_pack import load_pack_metadata
10
11
  from agentpack.core.thread_context import resolve_thread_option, thread_paths
11
12
  from agentpack.integrations.platform import cli_module_argv
@@ -42,9 +43,7 @@ def register(app: typer.Typer) -> None:
42
43
  if workspace:
43
44
  argv.extend(["--workspace", workspace])
44
45
  else:
45
- argv = cli_module_argv("guard", "--agent", agent, "--repair-stale", "--refresh-context", "--mode", mode)
46
- if budget:
47
- argv.extend(["--budget", str(budget)])
46
+ argv = cli_module_argv(*refresh_command_args(agent, mode, budget))
48
47
  if thread_id:
49
48
  argv.extend(["--thread", thread_id])
50
49
  result = subprocess.run(argv, cwd=root)
@@ -4,6 +4,7 @@ import typer
4
4
  import shutil
5
5
 
6
6
  from agentpack.core.config import load_config
7
+ from agentpack.core.command_surface import refresh_commands
7
8
  from agentpack.core.ignore import load_spec
8
9
  from agentpack.core.scanner import scan
9
10
  from agentpack.core.snapshot import build_snapshot
@@ -98,4 +99,4 @@ def _print_deep_health(root, meta: dict | None) -> None:
98
99
  if not check.ok:
99
100
  failing.append(check)
100
101
  if failing:
101
- console.print(f" [yellow]![/] Guard repair: agentpack guard --agent {agent} --repair-stale --refresh-context")
102
+ console.print(f" [yellow]![/] Repair: {refresh_commands(agent).repair}")
@@ -7,6 +7,7 @@ from pathlib import Path
7
7
  import typer
8
8
 
9
9
  from agentpack.commands._shared import console, _root
10
+ from agentpack.core.command_surface import refresh_command_args
10
11
  from agentpack.core.thread_context import resolve_thread_option, thread_paths
11
12
  from agentpack.integrations.platform import cli_module_argv
12
13
  from agentpack.session.state import TASK_FILE
@@ -47,7 +48,7 @@ def set_task(
47
48
  task_text: str = typer.Argument(..., help="Task text to write."),
48
49
  thread: str = typer.Option("", "--thread", help="Use thread-scoped task state."),
49
50
  pack: bool = typer.Option(False, "--pack", help="Run agentpack pack after writing the task."),
50
- guard: bool = typer.Option(False, "--guard", help="Run agentpack guard --repair-stale --refresh-context after writing."),
51
+ guard: bool = typer.Option(False, "--guard", help="Run the installed refresh/repair command after writing."),
51
52
  agent: str = typer.Option("auto", "--agent", help="Agent to pass to pack/guard."),
52
53
  mode: str = typer.Option("balanced", "--mode", help="Pack/guard mode."),
53
54
  ) -> None:
@@ -63,7 +64,7 @@ def set_task(
63
64
 
64
65
  thread_id = _thread_id(root, thread)
65
66
  if guard:
66
- _run_cli(["guard", "--agent", agent, "--repair-stale", "--refresh-context", "--mode", mode], thread_id=thread_id)
67
+ _run_cli(refresh_command_args(agent, mode), thread_id=thread_id)
67
68
  elif pack:
68
69
  _run_cli(["pack", "--agent", agent, "--task", "auto", "--mode", mode], thread_id=thread_id)
69
70
 
@@ -10,6 +10,7 @@ import typer
10
10
 
11
11
  from agentpack.commands._shared import console, _root, run_refresh
12
12
  from agentpack.commands.guard import _context_is_fresh
13
+ from agentpack.core.command_surface import refresh_commands
13
14
  from agentpack.core.config import load_config
14
15
  from agentpack.core.loop_protocol import (
15
16
  LoopCommandResult,
@@ -317,7 +318,7 @@ def _loop_finish_blockers(
317
318
  {
318
319
  "kind": "stale_context",
319
320
  "message": f"Context is stale: {reason}",
320
- "command": "agentpack guard --agent auto --repair-stale --refresh-context",
321
+ "command": refresh_commands("auto").repair,
321
322
  }
322
323
  )
323
324
  return blockers
@@ -434,6 +435,7 @@ def _read_task(root: Path, thread: str) -> str:
434
435
 
435
436
  def _refresh_loop_context(root: Path, agent: str, mode: str, budget: int, thread_id: str | None) -> LoopCommandResult:
436
437
  stats = run_refresh(root, agent, mode, budget, thread_id=thread_id)
438
+ command = refresh_commands(agent).primary
437
439
  if stats is None:
438
- return LoopCommandResult(command="agentpack guard --repair-stale --refresh-context", returncode=1, output_excerpt="context refresh failed")
439
- return LoopCommandResult(command="agentpack guard --repair-stale --refresh-context", returncode=0, output_excerpt=json.dumps(stats, sort_keys=True))
440
+ return LoopCommandResult(command=command, returncode=1, output_excerpt="context refresh failed")
441
+ return LoopCommandResult(command=command, returncode=0, output_excerpt=json.dumps(stats, sort_keys=True))
@@ -0,0 +1,127 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ import subprocess
5
+ from dataclasses import dataclass
6
+ from typing import Iterable
7
+
8
+ from agentpack import __version__
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class RefreshCommands:
13
+ primary: str
14
+ context_missing: str
15
+ thread_auto: str | None
16
+ repair: str
17
+ used_guard: bool
18
+
19
+
20
+ def available_cli_commands() -> tuple[str, ...]:
21
+ """Return command names registered by the importable AgentPack CLI."""
22
+ try:
23
+ import typer.main
24
+
25
+ from agentpack.cli import app
26
+
27
+ click_cmd = typer.main.get_command(app)
28
+ return tuple(sorted(click_cmd.commands))
29
+ except Exception:
30
+ return ()
31
+
32
+
33
+ def has_cli_command(command: str) -> bool:
34
+ return command in available_cli_commands()
35
+
36
+
37
+ def refresh_commands(agent: str = "auto") -> RefreshCommands:
38
+ if has_cli_command("guard"):
39
+ base = f"agentpack guard --agent {agent} --repair-stale --refresh-context"
40
+ return RefreshCommands(
41
+ primary=base,
42
+ context_missing=base,
43
+ thread_auto=f"AGENTPACK_THREAD_ID=<stable-id> {base} --thread auto",
44
+ repair=base,
45
+ used_guard=True,
46
+ )
47
+ pack = f"agentpack pack --agent {agent} --task auto"
48
+ return RefreshCommands(
49
+ primary=pack,
50
+ context_missing='printf "%s\\n" "<task>" > .agentpack/task.md && ' + pack,
51
+ thread_auto=None,
52
+ repair="agentpack repair --agent " + agent if has_cli_command("repair") else pack,
53
+ used_guard=False,
54
+ )
55
+
56
+
57
+ def refresh_command_args(agent: str = "auto", mode: str = "balanced", budget: int = 0) -> list[str]:
58
+ """Return CLI argv parts for refreshing context with the current command surface."""
59
+ if has_cli_command("guard"):
60
+ args = ["guard", "--agent", agent, "--repair-stale", "--refresh-context", "--mode", mode]
61
+ else:
62
+ args = ["pack", "--agent", agent, "--task", "auto", "--mode", mode]
63
+ if budget:
64
+ args.extend(["--budget", str(budget)])
65
+ return args
66
+
67
+
68
+ def fallback_agent_guidance() -> str:
69
+ return (
70
+ "If AgentPack tools are unavailable or context looks stale/wrong-worktree, "
71
+ "do not trust old pack output. Use direct `rg`, PR diff inspection, and target-file reads, "
72
+ "then run focused validation."
73
+ )
74
+
75
+
76
+ def installed_cli_status() -> dict[str, object]:
77
+ binary = shutil.which("agentpack")
78
+ status: dict[str, object] = {
79
+ "agentpack_version": __version__,
80
+ "binary": binary,
81
+ "importable_commands": list(available_cli_commands()),
82
+ }
83
+ if not binary:
84
+ status["available"] = False
85
+ status["repair_command"] = "pipx install agentpack-cli"
86
+ return status
87
+ try:
88
+ version = subprocess.run(
89
+ [binary, "--version"],
90
+ capture_output=True,
91
+ text=True,
92
+ timeout=5,
93
+ )
94
+ help_result = subprocess.run(
95
+ [binary, "--help"],
96
+ capture_output=True,
97
+ text=True,
98
+ timeout=5,
99
+ )
100
+ except (OSError, subprocess.TimeoutExpired) as exc:
101
+ status["available"] = False
102
+ status["error"] = str(exc)
103
+ status["repair_command"] = "pipx upgrade agentpack-cli"
104
+ return status
105
+ status["available"] = version.returncode == 0
106
+ status["installed_version"] = (version.stdout.strip() or version.stderr.strip())
107
+ status["help_commands"] = _commands_from_help(help_result.stdout + "\n" + help_result.stderr)
108
+ status["repair_command"] = "pipx upgrade agentpack-cli"
109
+ return status
110
+
111
+
112
+ def _commands_from_help(text: str) -> list[str]:
113
+ commands: set[str] = set()
114
+ known = set(available_cli_commands())
115
+ for line in text.splitlines():
116
+ stripped = line.strip()
117
+ if not stripped:
118
+ continue
119
+ first = stripped.split()[0].strip("`")
120
+ if first in known:
121
+ commands.add(first)
122
+ return sorted(commands)
123
+
124
+
125
+ def missing_commands(commands: Iterable[str]) -> list[str]:
126
+ available = set(available_cli_commands())
127
+ return sorted({cmd for cmd in commands if cmd and cmd not in available})
@@ -91,7 +91,18 @@ def save_pack_metadata(
91
91
  "concurrent_context": concurrent_context or {},
92
92
  }
93
93
  if freshness:
94
- for key in ("git_sha", "git_branch", "task_source", "changed_files_source", "task_class"):
94
+ for key in (
95
+ "agentpack_version",
96
+ "source_command",
97
+ "cwd",
98
+ "git_root",
99
+ "worktree_path",
100
+ "git_sha",
101
+ "git_branch",
102
+ "task_source",
103
+ "changed_files_source",
104
+ "task_class",
105
+ ):
95
106
  if key in freshness:
96
107
  meta[key] = freshness[key]
97
108
  path = metadata_path or _metadata_path(root)
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from dataclasses import dataclass, field
5
+ from pathlib import Path
6
+ from typing import Any, Literal
7
+
8
+
9
+ Variant = Literal["baseline", "agentpack"]
10
+
11
+
12
+ @dataclass(frozen=True)
13
+ class E2ERunMetrics:
14
+ case_id: str
15
+ variant: Variant
16
+ task_success: bool | None = None
17
+ validation_passed: bool | None = None
18
+ token_usage: int | None = None
19
+ estimated_cost_usd: float | None = None
20
+ turns: int | None = None
21
+ tool_calls: int | None = None
22
+ time_to_first_correct_file_seconds: float | None = None
23
+ wall_time_seconds: float | None = None
24
+ final_edited_files: list[str] = field(default_factory=list)
25
+ expected_files: list[str] = field(default_factory=list)
26
+ agentpack_noise: list[str] = field(default_factory=list)
27
+
28
+ def to_record(self) -> dict[str, Any]:
29
+ return {
30
+ "case_id": self.case_id,
31
+ "variant": self.variant,
32
+ "task_success": self.task_success,
33
+ "validation_passed": self.validation_passed,
34
+ "token_usage": self.token_usage,
35
+ "estimated_cost_usd": self.estimated_cost_usd,
36
+ "turns": self.turns,
37
+ "tool_calls": self.tool_calls,
38
+ "time_to_first_correct_file_seconds": self.time_to_first_correct_file_seconds,
39
+ "wall_time_seconds": self.wall_time_seconds,
40
+ "final_edited_files": self.final_edited_files,
41
+ "expected_files": self.expected_files,
42
+ "edited_expected_overlap": sorted(set(self.final_edited_files) & set(self.expected_files)),
43
+ "unexpected_edited_files": sorted(set(self.final_edited_files) - set(self.expected_files)),
44
+ "missing_expected_files": sorted(set(self.expected_files) - set(self.final_edited_files)),
45
+ "agentpack_noise": self.agentpack_noise,
46
+ }
47
+
48
+
49
+ def append_e2e_result(path: Path, metrics: E2ERunMetrics) -> None:
50
+ path.parent.mkdir(parents=True, exist_ok=True)
51
+ with path.open("a", encoding="utf-8") as handle:
52
+ handle.write(json.dumps(metrics.to_record(), sort_keys=True) + "\n")
53
+
54
+
55
+ def e2e_scaffold_markdown() -> str:
56
+ return """# AgentPack E2E Benchmark Scaffold
57
+
58
+ Compare the same real task in two variants:
59
+
60
+ - baseline: agent runs without AgentPack context/routing.
61
+ - agentpack: agent starts with AgentPack route/context guidance.
62
+
63
+ Required metrics:
64
+
65
+ - task success
66
+ - tests or validation pass
67
+ - token usage and estimated cost
68
+ - turns and tool calls
69
+ - time-to-first-correct-file
70
+ - wall time
71
+ - final edited files vs expected files
72
+ - AgentPack noise or slowdown cases
73
+
74
+ Keep file-selection benchmarks as scoped ranking evidence. Do not claim cost, turn, or task-success gains until this E2E data exists.
75
+ """
@@ -33,7 +33,7 @@ Pack repo context and immediately start working on the task.
33
33
  If a session is already running (`.agentpack/session.json` exists and `"active": true`):
34
34
 
35
35
  1. If the user gives a new coding task, write a one-line summary to `.agentpack/task.md`.
36
- 2. Run `agentpack guard --agent claude --repair-stale --refresh-context` unless watch mode already refreshed after the task write.
36
+ 2. Run `agentpack pack --agent claude --task auto` unless watch mode already refreshed after the task write.
37
37
  3. Read `.agentpack/context.md` — context now matches the current task.
38
38
  4. Proceed with the task using the context you just read.
39
39
 
@@ -72,21 +72,21 @@ Then use normal prompts — context stays current while `watch` is running.
72
72
 
73
73
  ```bash
74
74
  printf '%s\n' "<task>" > .agentpack/task.md
75
- agentpack guard --agent claude --repair-stale --refresh-context --mode balanced
75
+ agentpack pack --agent claude --task auto --mode balanced
76
76
  ```
77
77
 
78
78
  Then read `.agentpack/context.claude.md` in full.
79
79
 
80
80
  ## Thread Mode (explicit opt-in)
81
81
 
82
- Plain `agentpack pack`, `agentpack status`, and `agentpack guard` use the legacy global files:
82
+ Plain `agentpack pack` and `agentpack status` use the legacy global files:
83
83
  `.agentpack/task.md`, `.agentpack/context.md`, and `.agentpack/pack_metadata.json`.
84
84
 
85
85
  When multiple agents work in the same repo, opt into scoped state:
86
86
 
87
87
  ```bash
88
88
  export AGENTPACK_THREAD_ID=codex-local
89
- agentpack guard --agent claude --repair-stale --refresh-context --thread auto
89
+ agentpack pack --agent claude --task auto --thread auto
90
90
  ```
91
91
 
92
92
  Thread mode writes `.agentpack/threads/<id>/task.md`, `context.md`, `context.claude.md`,
@@ -122,12 +122,12 @@ test -f .agentpack/config.toml || "$AGENTPACK_BIN" init --yes
122
122
 
123
123
  **Session active** (`.agentpack/session.json` exists, `"active": true`):
124
124
  - Update `.agentpack/task.md` if task changed
125
- - Run `"$AGENTPACK_BIN" guard --agent claude --repair-stale --refresh-context` unless watch already refreshed it
125
+ - Run `"$AGENTPACK_BIN" pack --agent claude --task auto` unless watch already refreshed it
126
126
  - Read `.agentpack/context.md`
127
127
  - Proceed immediately
128
128
 
129
129
  **No session**:
130
- - Run `"$AGENTPACK_BIN" session start` or `"$AGENTPACK_BIN" guard --agent claude --repair-stale --refresh-context`
130
+ - Run `"$AGENTPACK_BIN" session start` or `"$AGENTPACK_BIN" pack --agent claude --task auto`
131
131
  - Read the context file
132
132
  - Proceed
133
133
 
@@ -145,7 +145,7 @@ Do not say "context pack ready" and stop. Do not tell the user to run more comma
145
145
 
146
146
  If `"$AGENTPACK_BIN" status` exits non-zero or context seems unrelated to the task:
147
147
  - Run `"$AGENTPACK_BIN" session refresh` (if session active)
148
- - Or run `"$AGENTPACK_BIN" guard --agent claude --repair-stale --refresh-context` (manual mode)
148
+ - Or run `"$AGENTPACK_BIN" pack --agent claude --task auto` (manual mode)
149
149
  - Re-read the context, then proceed
150
150
 
151
151
  Do not ask the user — just refresh and proceed.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentpack",
3
- "version": "0.3.25",
3
+ "version": "0.3.26",
4
4
  "description": "Thin Codex plugin for AgentPack ranked repo context.",
5
5
  "author": {
6
6
  "name": "AgentPack",