agentpack-cli 0.3.21__tar.gz → 0.3.22__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 (153) hide show
  1. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/PKG-INFO +42 -35
  2. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/README.md +33 -32
  3. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/pyproject.toml +11 -3
  4. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/__init__.py +1 -1
  5. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/ranking.py +258 -0
  6. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/role_inference.py +19 -1
  7. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/application/pack_service.py +4 -0
  8. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/benchmark.py +962 -2
  9. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/context_pack.py +872 -8
  10. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/.gitignore +0 -0
  11. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/LICENSE +0 -0
  12. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/__init__.py +0 -0
  13. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/antigravity.py +0 -0
  14. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/base.py +0 -0
  15. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/claude.py +0 -0
  16. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/codex.py +0 -0
  17. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/cursor.py +0 -0
  18. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/detect.py +0 -0
  19. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/generic.py +0 -0
  20. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/windsurf.py +0 -0
  21. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/__init__.py +0 -0
  22. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/dependency_graph.py +0 -0
  23. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/go_imports.py +0 -0
  24. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/java_imports.py +0 -0
  25. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/js_ts_imports.py +0 -0
  26. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/monorepo.py +0 -0
  27. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/naming_signals.py +0 -0
  28. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/python_ast.py +0 -0
  29. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/python_imports.py +0 -0
  30. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/repo_map.py +0 -0
  31. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/rust_imports.py +0 -0
  32. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/symbols.py +0 -0
  33. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/task_classifier.py +0 -0
  34. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/tests.py +0 -0
  35. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/application/__init__.py +0 -0
  36. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/cli.py +0 -0
  37. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/__init__.py +0 -0
  38. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/_shared.py +0 -0
  39. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/ci_cmd.py +0 -0
  40. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/claude_cmd.py +0 -0
  41. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/compress_output.py +0 -0
  42. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/dashboard.py +0 -0
  43. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/dev_check.py +0 -0
  44. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/diagnose_selection.py +0 -0
  45. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/diff.py +0 -0
  46. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/doctor.py +0 -0
  47. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/eval_cmd.py +0 -0
  48. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/explain.py +0 -0
  49. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/guard.py +0 -0
  50. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/hook_cmd.py +0 -0
  51. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/ignore_cmd.py +0 -0
  52. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/init.py +0 -0
  53. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/install.py +0 -0
  54. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/learn.py +0 -0
  55. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/mcp_cmd.py +0 -0
  56. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/memory.py +0 -0
  57. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/migrate.py +0 -0
  58. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/monitor.py +0 -0
  59. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/next_cmd.py +0 -0
  60. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/pack.py +0 -0
  61. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/perf.py +0 -0
  62. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/quickstart.py +0 -0
  63. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/release_check.py +0 -0
  64. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/release_cmd.py +0 -0
  65. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/repair.py +0 -0
  66. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/retrieve.py +0 -0
  67. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/route.py +0 -0
  68. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/scan.py +0 -0
  69. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/skills.py +0 -0
  70. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/start_cmd.py +0 -0
  71. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/state_cmd.py +0 -0
  72. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/stats.py +0 -0
  73. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/status.py +0 -0
  74. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/summarize.py +0 -0
  75. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/task_cmd.py +0 -0
  76. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/threads.py +0 -0
  77. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/tune.py +0 -0
  78. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/verify_wheel.py +0 -0
  79. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/watch.py +0 -0
  80. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/workflow_cmd.py +0 -0
  81. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/wrap.py +0 -0
  82. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/__init__.py +0 -0
  83. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/bootstrap.py +0 -0
  84. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/cache.py +0 -0
  85. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/changed_paths.py +0 -0
  86. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/config.py +0 -0
  87. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/diff.py +0 -0
  88. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/evals.py +0 -0
  89. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/execution_state.py +0 -0
  90. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/git.py +0 -0
  91. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/git_hooks.py +0 -0
  92. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/global_install.py +0 -0
  93. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/ignore.py +0 -0
  94. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/loop_protocol.py +0 -0
  95. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/merkle.py +0 -0
  96. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/models.py +0 -0
  97. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/modes.py +0 -0
  98. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/pack_registry.py +0 -0
  99. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/redactor.py +0 -0
  100. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/scanner.py +0 -0
  101. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/snapshot.py +0 -0
  102. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/task_freshness.py +0 -0
  103. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/thread_context.py +0 -0
  104. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/token_estimator.py +0 -0
  105. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/vscode_tasks.py +0 -0
  106. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/dashboard/__init__.py +0 -0
  107. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/dashboard/collectors.py +0 -0
  108. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/dashboard/models.py +0 -0
  109. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/dashboard/renderers.py +0 -0
  110. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/data/agentpack.md +0 -0
  111. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/__init__.py +0 -0
  112. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/antigravity.py +0 -0
  113. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/claude.py +0 -0
  114. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/codex.py +0 -0
  115. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/cursor.py +0 -0
  116. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/windsurf.py +0 -0
  117. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/__init__.py +0 -0
  118. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/agents.py +0 -0
  119. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/git_hooks.py +0 -0
  120. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/global_install.py +0 -0
  121. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/platform.py +0 -0
  122. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/vscode_tasks.py +0 -0
  123. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/__init__.py +0 -0
  124. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/collector.py +0 -0
  125. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/extractor.py +0 -0
  126. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/feedback.py +0 -0
  127. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/lesson_ranker.py +0 -0
  128. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/models.py +0 -0
  129. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/provider.py +0 -0
  130. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/quality.py +0 -0
  131. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/renderers.py +0 -0
  132. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/skill_map.py +0 -0
  133. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/mcp_server.py +0 -0
  134. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/output_compression/__init__.py +0 -0
  135. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/output_compression/core.py +0 -0
  136. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/renderers/__init__.py +0 -0
  137. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/renderers/compact.py +0 -0
  138. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/renderers/markdown.py +0 -0
  139. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/renderers/receipts.py +0 -0
  140. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/__init__.py +0 -0
  141. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/discovery.py +0 -0
  142. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/models.py +0 -0
  143. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/parser.py +0 -0
  144. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/prompt_builder.py +0 -0
  145. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/scoring.py +0 -0
  146. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/service.py +0 -0
  147. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/skills_index.py +0 -0
  148. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/session/__init__.py +0 -0
  149. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/session/events.py +0 -0
  150. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/session/state.py +0 -0
  151. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/summaries/__init__.py +0 -0
  152. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/summaries/base.py +0 -0
  153. {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/summaries/offline.py +0 -0
@@ -1,10 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentpack-cli
3
- Version: 0.3.21
4
- Summary: Local MCP context router for Claude Code, Codex, Cursor, and AI coding agents.
3
+ Version: 0.3.22
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
+ Project-URL: Homepage, https://github.com/vishal2612200/agentpack
6
+ Project-URL: Documentation, https://vishal2612200.github.io/agentpack/
7
+ Project-URL: Repository, https://github.com/vishal2612200/agentpack
8
+ Project-URL: Issues, https://github.com/vishal2612200/agentpack/issues
9
+ Project-URL: Changelog, https://github.com/vishal2612200/agentpack/blob/main/CHANGELOG.md
5
10
  License: MIT
6
11
  License-File: LICENSE
7
- Keywords: ai,ai-agent,ai-coding-agents,antigravity,ci,claude-code,codex,coding-agent,context,context-engine,context-packing,context-router,cursor,developer-tools,llm,mcp,mcp-context-engine,packing,prompt-context,reduce-token-usage,repo-analysis,repo-context,windsurf
12
+ Keywords: ai,ai-agent,ai-coding-agents,antigravity,ci,claude-code,codex,coding-agent,context,context-engine,context-packing,context-router,cursor,developer-tools,llm,local-first,mcp,mcp-context-engine,packing,prompt-context,reduce-token-usage,repo-analysis,repo-context,repo-map,task-focused-context,windsurf
8
13
  Classifier: Development Status :: 3 - Alpha
9
14
  Classifier: Intended Audience :: Developers
10
15
  Classifier: License :: OSI Approved :: MIT License
@@ -12,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.10
12
17
  Classifier: Programming Language :: Python :: 3.11
13
18
  Classifier: Programming Language :: Python :: 3.12
14
19
  Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
15
21
  Classifier: Topic :: Software Development :: Build Tools
16
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
23
  Requires-Python: >=3.10
@@ -49,9 +55,13 @@ Description-Content-Type: text/markdown
49
55
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
50
56
  [![CI](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml/badge.svg)](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
51
57
 
52
- **Local context router for AI coding agents.**
58
+ **Local context engine for AI coding agents.**
53
59
 
54
- AgentPack gives Claude Code, Codex, Cursor, and other coding agents a ranked starting map before they burn tool calls rediscovering your repo.
60
+ AgentPack ranks relevant repository files and builds compact task-focused context packs for Claude Code, Codex, Cursor, Windsurf, Antigravity, MCP tools, CI jobs, and markdown-based LLM workflows.
61
+
62
+ It runs local/offline repo analysis, compresses selected files into a token budget, and keeps context fresh through CLI commands, MCP tools, hooks, and agent integrations. Use it when an AI coding agent needs a ranked starting map instead of burning tool calls rediscovering your repo.
63
+
64
+ AgentPack is a context preparation tool, not a coding agent.
55
65
 
56
66
  One workflow matters:
57
67
 
@@ -67,19 +77,19 @@ pipx run --spec agentpack-cli agentpack route --task "fix auth token expiry"
67
77
 
68
78
  ![AgentPack route demo](docs/assets/agentpack-route-demo.svg)
69
79
 
70
- > **Status: alpha (v0.3.21).** Works, tested, and used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Current benchmarks are useful regression checks, not broad proof that AgentPack improves coding-agent success. API may change before 1.0.
80
+ > **Status: alpha (v0.3.22).** Works, tested, and used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Current benchmarks are useful regression checks, not broad proof that AgentPack improves coding-agent success. API may change before 1.0.
71
81
  >
72
82
  > **Platform note:** macOS, Linux, and Windows are supported. Windows support targets PowerShell plus Git for Windows. `cmd.exe` and bare Git setups are not a supported path yet.
73
83
  >
74
84
  > **Name note:** PyPI package is `agentpack-cli`, npm package is `@vishal2612200/agentpack`, and the command is `agentpack`. This project is unrelated to AgentPack dataset papers or other repos with the same name.
75
85
 
76
- ## What's New in 0.3.21
86
+ ## What's New in 0.3.22
77
87
 
78
- `0.3.21` is a benchmark trust release. It keeps the current honest expanded
79
- public-suite baseline at **57.0% recall / 50.6% token precision**, removes the
80
- legacy minimal-mode surface in favor of `balanced`, improves benchmark
81
- diagnostics and public-suite methodology, and documents the next release target:
82
- **65%+ recall while holding 50%+ token precision**.
88
+ `0.3.22` is a benchmark recall release. It promotes maintenance-context
89
+ recovery to the current expanded public-suite baseline: **66.0% recall / 51.1%
90
+ token precision** across 108 scored public cases.
91
+ `0.3.21` established the prior honest baseline at **57.0% recall / 50.6% token precision**. The new result clears the 65% recall target while keeping token
92
+ precision above the 51% release floor; remaining risk is config/build recall and NestJS token precision. Result: [`benchmarks/results/2026-06-13-public.md`](benchmarks/results/2026-06-13-public.md).
83
93
 
84
94
  ## Core Workflow
85
95
 
@@ -128,23 +138,21 @@ ranked but cut by budget, or absent from scan.
128
138
 
129
139
  ## Benchmark Proof
130
140
 
131
- Latest published v0.3.20 release table: 8 pinned public commits from Pallets
132
- Click, ItsDangerous, and MarkupSafe, scored against files actually changed by
133
- each commit. The public manifest now also supports 100+ sampled historical
134
- commits across Python, TypeScript, Go, Java, and monorepo repos for broader
135
- release runs.
141
+ Current local release-candidate table: expanded public-suite historical commits
142
+ across Python, TypeScript, Go, Java, and monorepo repos, scored against files
143
+ actually changed by each commit.
136
144
 
137
145
  | Metric | Result |
138
146
  |---|---:|
139
- | Avg recall | 79.2% |
140
- | Avg token precision | 51.2% |
141
- | Pack p50 | 1,450 tokens |
142
- | Pack p95 | 3,805 tokens |
143
-
144
- Full v0.3.20 table: [`benchmarks/results/2026-06-11-public.md`](benchmarks/results/2026-06-11-public.md). This is scoped benchmark evidence, not a universal quality claim.
145
- The expanded 109-case public suite is the current optimization baseline:
146
- **57.0% recall / 50.6% token precision**. It is broader and harder than the
147
- 8-case published table, and recall remains the active improvement target.
147
+ | Scored cases | 108 |
148
+ | Avg recall | 66.0% |
149
+ | Avg token precision | 51.1% |
150
+ | Pack p50 | 315 tokens |
151
+ | Pack p95 | 1,150 tokens |
152
+
153
+ Full local table: [`benchmarks/results/2026-06-13-public.md`](benchmarks/results/2026-06-13-public.md). This is scoped benchmark evidence, not a universal quality claim.
154
+ The latest published v0.3.20 table remains available at
155
+ [`benchmarks/results/2026-06-11-public.md`](benchmarks/results/2026-06-11-public.md).
148
156
  Reproduce the expanded public suite:
149
157
 
150
158
  ```bash
@@ -153,20 +161,19 @@ agentpack benchmark --public-suite --reproduce v0.3.20
153
161
 
154
162
  Benchmark methodology lives under [`benchmarks/results/v0.3.20/`](benchmarks/results/v0.3.20/methodology.md).
155
163
 
156
- ### Next Release Benchmark Target
164
+ ### Release Benchmark Gate
157
165
 
158
- The next benchmark release target is to raise the expanded public suite from the
159
- current **57.0% recall / 50.6% token precision** baseline to **65%+ recall**
160
- while keeping token precision at **50%+**. The target should be measured on the
166
+ The current local release-candidate result clears the target: **66.0% recall**
167
+ and **51.1% token precision**. The target should continue to be measured on the
161
168
  same 100+ public historical-commit suite, with per-language slices published so
162
- precision gains are not hiding TypeScript, Go, Java, or monorepo regressions.
169
+ aggregate gains are not hiding TypeScript, Go, Java, or monorepo regressions.
163
170
 
164
171
  Decision gate for the next public table:
165
172
 
166
173
  - full-suite recall is at least 65.0%
167
- - full-suite token precision is at least 50.0%
174
+ - full-suite token precision is at least 51.0%
168
175
  - no major language or task slice loses more than 2 recall points
169
- - Vite/TypeScript, Gin/Go, and NestJS monorepo misses are reported separately
176
+ - Vite/TypeScript, Gin/Go, Click/Python, and NestJS monorepo misses are reported separately
170
177
  - any AgentPack-vs-no-AgentPack A/B claim includes task success, tool calls,
171
178
  token cost, and time-to-first-correct-file
172
179
 
@@ -182,7 +189,7 @@ and [`docs/data-flow.md`](docs/data-flow.md).
182
189
  Start with the [docs index](docs/index.md), or jump to guides for
183
190
  [Claude Code](docs/claude-code-context-engine.md), [MCP](docs/mcp-context-engine.md),
184
191
  [Cursor](docs/cursor-context-packing.md), [token usage](docs/reduce-claude-code-token-usage.md),
185
- and [how AgentPack works](docs/how-agentpack-works.md).
192
+ [AI coding agent context](docs/ai-coding-agent-context.md), and [how AgentPack works](docs/how-agentpack-works.md).
186
193
 
187
194
  ## Install
188
195
 
@@ -191,7 +198,7 @@ pipx install agentpack-cli
191
198
  agentpack --version
192
199
  ```
193
200
 
194
- Requires Python 3.10+. The PyPI package is `agentpack-cli`; the command is `agentpack`. Use `pipx` for normal installs because many macOS/Linux Python distributions block global `pip install` with PEP 668's `externally-managed-environment` error. If you prefer `pip`, install inside a virtual environment.
201
+ Requires Python 3.10+ and is tested on Python 3.10-3.14. The PyPI package is `agentpack-cli`; the command is `agentpack`. Use `pipx` for normal installs because many macOS/Linux Python distributions block global `pip install` with PEP 668's `externally-managed-environment` error. If you prefer `pip`, install inside a virtual environment.
195
202
 
196
203
  Install `pipx` first if needed:
197
204
 
@@ -8,9 +8,13 @@
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
9
  [![CI](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml/badge.svg)](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
10
10
 
11
- **Local context router for AI coding agents.**
11
+ **Local context engine for AI coding agents.**
12
12
 
13
- AgentPack gives Claude Code, Codex, Cursor, and other coding agents a ranked starting map before they burn tool calls rediscovering your repo.
13
+ AgentPack ranks relevant repository files and builds compact task-focused context packs for Claude Code, Codex, Cursor, Windsurf, Antigravity, MCP tools, CI jobs, and markdown-based LLM workflows.
14
+
15
+ It runs local/offline repo analysis, compresses selected files into a token budget, and keeps context fresh through CLI commands, MCP tools, hooks, and agent integrations. Use it when an AI coding agent needs a ranked starting map instead of burning tool calls rediscovering your repo.
16
+
17
+ AgentPack is a context preparation tool, not a coding agent.
14
18
 
15
19
  One workflow matters:
16
20
 
@@ -26,19 +30,19 @@ pipx run --spec agentpack-cli agentpack route --task "fix auth token expiry"
26
30
 
27
31
  ![AgentPack route demo](docs/assets/agentpack-route-demo.svg)
28
32
 
29
- > **Status: alpha (v0.3.21).** Works, tested, and used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Current benchmarks are useful regression checks, not broad proof that AgentPack improves coding-agent success. API may change before 1.0.
33
+ > **Status: alpha (v0.3.22).** Works, tested, and used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Current benchmarks are useful regression checks, not broad proof that AgentPack improves coding-agent success. API may change before 1.0.
30
34
  >
31
35
  > **Platform note:** macOS, Linux, and Windows are supported. Windows support targets PowerShell plus Git for Windows. `cmd.exe` and bare Git setups are not a supported path yet.
32
36
  >
33
37
  > **Name note:** PyPI package is `agentpack-cli`, npm package is `@vishal2612200/agentpack`, and the command is `agentpack`. This project is unrelated to AgentPack dataset papers or other repos with the same name.
34
38
 
35
- ## What's New in 0.3.21
39
+ ## What's New in 0.3.22
36
40
 
37
- `0.3.21` is a benchmark trust release. It keeps the current honest expanded
38
- public-suite baseline at **57.0% recall / 50.6% token precision**, removes the
39
- legacy minimal-mode surface in favor of `balanced`, improves benchmark
40
- diagnostics and public-suite methodology, and documents the next release target:
41
- **65%+ recall while holding 50%+ token precision**.
41
+ `0.3.22` is a benchmark recall release. It promotes maintenance-context
42
+ recovery to the current expanded public-suite baseline: **66.0% recall / 51.1%
43
+ token precision** across 108 scored public cases.
44
+ `0.3.21` established the prior honest baseline at **57.0% recall / 50.6% token precision**. The new result clears the 65% recall target while keeping token
45
+ precision above the 51% release floor; remaining risk is config/build recall and NestJS token precision. Result: [`benchmarks/results/2026-06-13-public.md`](benchmarks/results/2026-06-13-public.md).
42
46
 
43
47
  ## Core Workflow
44
48
 
@@ -87,23 +91,21 @@ ranked but cut by budget, or absent from scan.
87
91
 
88
92
  ## Benchmark Proof
89
93
 
90
- Latest published v0.3.20 release table: 8 pinned public commits from Pallets
91
- Click, ItsDangerous, and MarkupSafe, scored against files actually changed by
92
- each commit. The public manifest now also supports 100+ sampled historical
93
- commits across Python, TypeScript, Go, Java, and monorepo repos for broader
94
- release runs.
94
+ Current local release-candidate table: expanded public-suite historical commits
95
+ across Python, TypeScript, Go, Java, and monorepo repos, scored against files
96
+ actually changed by each commit.
95
97
 
96
98
  | Metric | Result |
97
99
  |---|---:|
98
- | Avg recall | 79.2% |
99
- | Avg token precision | 51.2% |
100
- | Pack p50 | 1,450 tokens |
101
- | Pack p95 | 3,805 tokens |
102
-
103
- Full v0.3.20 table: [`benchmarks/results/2026-06-11-public.md`](benchmarks/results/2026-06-11-public.md). This is scoped benchmark evidence, not a universal quality claim.
104
- The expanded 109-case public suite is the current optimization baseline:
105
- **57.0% recall / 50.6% token precision**. It is broader and harder than the
106
- 8-case published table, and recall remains the active improvement target.
100
+ | Scored cases | 108 |
101
+ | Avg recall | 66.0% |
102
+ | Avg token precision | 51.1% |
103
+ | Pack p50 | 315 tokens |
104
+ | Pack p95 | 1,150 tokens |
105
+
106
+ Full local table: [`benchmarks/results/2026-06-13-public.md`](benchmarks/results/2026-06-13-public.md). This is scoped benchmark evidence, not a universal quality claim.
107
+ The latest published v0.3.20 table remains available at
108
+ [`benchmarks/results/2026-06-11-public.md`](benchmarks/results/2026-06-11-public.md).
107
109
  Reproduce the expanded public suite:
108
110
 
109
111
  ```bash
@@ -112,20 +114,19 @@ agentpack benchmark --public-suite --reproduce v0.3.20
112
114
 
113
115
  Benchmark methodology lives under [`benchmarks/results/v0.3.20/`](benchmarks/results/v0.3.20/methodology.md).
114
116
 
115
- ### Next Release Benchmark Target
117
+ ### Release Benchmark Gate
116
118
 
117
- The next benchmark release target is to raise the expanded public suite from the
118
- current **57.0% recall / 50.6% token precision** baseline to **65%+ recall**
119
- while keeping token precision at **50%+**. The target should be measured on the
119
+ The current local release-candidate result clears the target: **66.0% recall**
120
+ and **51.1% token precision**. The target should continue to be measured on the
120
121
  same 100+ public historical-commit suite, with per-language slices published so
121
- precision gains are not hiding TypeScript, Go, Java, or monorepo regressions.
122
+ aggregate gains are not hiding TypeScript, Go, Java, or monorepo regressions.
122
123
 
123
124
  Decision gate for the next public table:
124
125
 
125
126
  - full-suite recall is at least 65.0%
126
- - full-suite token precision is at least 50.0%
127
+ - full-suite token precision is at least 51.0%
127
128
  - no major language or task slice loses more than 2 recall points
128
- - Vite/TypeScript, Gin/Go, and NestJS monorepo misses are reported separately
129
+ - Vite/TypeScript, Gin/Go, Click/Python, and NestJS monorepo misses are reported separately
129
130
  - any AgentPack-vs-no-AgentPack A/B claim includes task success, tool calls,
130
131
  token cost, and time-to-first-correct-file
131
132
 
@@ -141,7 +142,7 @@ and [`docs/data-flow.md`](docs/data-flow.md).
141
142
  Start with the [docs index](docs/index.md), or jump to guides for
142
143
  [Claude Code](docs/claude-code-context-engine.md), [MCP](docs/mcp-context-engine.md),
143
144
  [Cursor](docs/cursor-context-packing.md), [token usage](docs/reduce-claude-code-token-usage.md),
144
- and [how AgentPack works](docs/how-agentpack-works.md).
145
+ [AI coding agent context](docs/ai-coding-agent-context.md), and [how AgentPack works](docs/how-agentpack-works.md).
145
146
 
146
147
  ## Install
147
148
 
@@ -150,7 +151,7 @@ pipx install agentpack-cli
150
151
  agentpack --version
151
152
  ```
152
153
 
153
- Requires Python 3.10+. The PyPI package is `agentpack-cli`; the command is `agentpack`. Use `pipx` for normal installs because many macOS/Linux Python distributions block global `pip install` with PEP 668's `externally-managed-environment` error. If you prefer `pip`, install inside a virtual environment.
154
+ Requires Python 3.10+ and is tested on Python 3.10-3.14. The PyPI package is `agentpack-cli`; the command is `agentpack`. Use `pipx` for normal installs because many macOS/Linux Python distributions block global `pip install` with PEP 668's `externally-managed-environment` error. If you prefer `pip`, install inside a virtual environment.
154
155
 
155
156
  Install `pipx` first if needed:
156
157
 
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "agentpack-cli"
3
- version = "0.3.21"
4
- description = "Local MCP context router for Claude Code, Codex, Cursor, and AI coding agents."
3
+ version = "0.3.22"
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"
7
7
  license = {text = "MIT"}
8
- keywords = ["ai-coding-agents", "coding-agent", "ai-agent", "claude-code", "developer-tools", "repo-analysis", "repo-context", "context-engine", "mcp-context-engine", "context-router", "context-packing", "prompt-context", "reduce-token-usage", "mcp", "ci", "codex", "cursor", "windsurf", "antigravity", "ai", "llm", "context", "packing"]
8
+ keywords = ["ai-coding-agents", "coding-agent", "ai-agent", "claude-code", "developer-tools", "repo-analysis", "repo-context", "context-engine", "mcp-context-engine", "context-router", "context-packing", "prompt-context", "task-focused-context", "reduce-token-usage", "local-first", "repo-map", "mcp", "ci", "codex", "cursor", "windsurf", "antigravity", "ai", "llm", "context", "packing"]
9
9
  classifiers = [
10
10
  "Development Status :: 3 - Alpha",
11
11
  "Intended Audience :: Developers",
@@ -14,6 +14,7 @@ classifiers = [
14
14
  "Programming Language :: Python :: 3.11",
15
15
  "Programming Language :: Python :: 3.12",
16
16
  "Programming Language :: Python :: 3.13",
17
+ "Programming Language :: Python :: 3.14",
17
18
  "Topic :: Software Development :: Libraries :: Python Modules",
18
19
  "Topic :: Software Development :: Build Tools",
19
20
  ]
@@ -28,6 +29,13 @@ dependencies = [
28
29
  "tomli>=2.0.0; python_version < '3.11'"
29
30
  ]
30
31
 
32
+ [project.urls]
33
+ Homepage = "https://github.com/vishal2612200/agentpack"
34
+ Documentation = "https://vishal2612200.github.io/agentpack/"
35
+ Repository = "https://github.com/vishal2612200/agentpack"
36
+ Issues = "https://github.com/vishal2612200/agentpack/issues"
37
+ Changelog = "https://github.com/vishal2612200/agentpack/blob/main/CHANGELOG.md"
38
+
31
39
  [project.scripts]
32
40
  agentpack = "agentpack.cli:app"
33
41
 
@@ -1,3 +1,3 @@
1
1
  """AgentPack — task-aware context packing for AI coding agents."""
2
2
 
3
- __version__ = "0.3.21"
3
+ __version__ = "0.3.22"
@@ -1160,6 +1160,149 @@ def _domain_tokens(path: str) -> set[str]:
1160
1160
  return {tok for tok in _path_tokens(path) if len(tok) >= 3 and tok not in _PATH_NOISE_TOKENS}
1161
1161
 
1162
1162
 
1163
+ def _api_route_terms(path: str) -> tuple[str, ...]:
1164
+ parts = [part.lower() for part in Path(path).parts]
1165
+ if "api" not in parts:
1166
+ return ()
1167
+ api_index = parts.index("api")
1168
+ suffix = parts[api_index + 1:]
1169
+ if not suffix:
1170
+ return ()
1171
+ route_file_names = {
1172
+ "route.ts", "route.tsx", "route.js", "route.jsx",
1173
+ "routes.py", "urls.py", "views.py", "controller.ts", "controller.js",
1174
+ }
1175
+ if suffix[-1] in route_file_names or Path(suffix[-1]).stem.lower() in {"route", "routes", "urls", "views", "controller"}:
1176
+ suffix = suffix[:-1]
1177
+ terms: list[str] = []
1178
+ for part in suffix:
1179
+ clean = part.strip("[](){}")
1180
+ if not clean or clean.startswith("_"):
1181
+ continue
1182
+ terms.extend(token for token in _ordered_tokens(clean) if token and token not in _PATH_NOISE_TOKENS)
1183
+ return tuple(dict.fromkeys(terms))
1184
+
1185
+
1186
+ def _is_api_route_path(path: str) -> bool:
1187
+ return bool(_api_route_terms(path))
1188
+
1189
+
1190
+ def _api_route_label(path: str) -> str:
1191
+ terms = _api_route_terms(path)
1192
+ return "/api/" + "/".join(terms) if terms else path
1193
+
1194
+
1195
+ def _normalize_api_path(value: str) -> str | None:
1196
+ match = re.search(r"/api/[A-Za-z0-9_./${}\[\]-]+", value)
1197
+ if not match:
1198
+ return None
1199
+ path = match.group(0).split("?", 1)[0].split("#", 1)[0].split("${", 1)[0]
1200
+ path = re.sub(r"/\[[^\]]+\]", "", path)
1201
+ path = path.rstrip("/,;)")
1202
+ return path.rstrip("/") or "/api"
1203
+
1204
+
1205
+ def _api_paths_from_summary(summary_data: object | None) -> set[str]:
1206
+ paths: set[str] = set()
1207
+ if summary_data is None:
1208
+ return paths
1209
+ for summary_field in ("calls", "entrypoints", "public_api"):
1210
+ for value in _summary_values(summary_data, summary_field):
1211
+ normalized = _normalize_api_path(value)
1212
+ if normalized:
1213
+ paths.add(normalized)
1214
+ return paths
1215
+
1216
+
1217
+ def _api_path_terms(api_path: str) -> set[str]:
1218
+ return {
1219
+ token
1220
+ for token in _ordered_tokens(api_path.removeprefix("/api/"))
1221
+ if token and token not in _PATH_NOISE_TOKENS
1222
+ }
1223
+
1224
+
1225
+ def _api_route_path(path: str, summary_data: object | None = None) -> str | None:
1226
+ for value in _summary_values(summary_data, "entrypoints"):
1227
+ normalized = _normalize_api_path(value)
1228
+ if normalized:
1229
+ return normalized
1230
+ terms = _api_route_terms(path)
1231
+ if terms:
1232
+ return "/api/" + "/".join(terms)
1233
+ return None
1234
+
1235
+
1236
+ def _looks_like_frontend_consumer(path: str, summary_data: object | None) -> bool:
1237
+ suffix = Path(path).suffix.lower()
1238
+ if suffix in {".tsx", ".jsx"}:
1239
+ return True
1240
+ path_terms = _path_tokens(path)
1241
+ if path_terms & {"component", "components", "page", "pages", "client", "dashboard"}:
1242
+ return True
1243
+ return any(
1244
+ value.startswith(("React page:", "React layout:", "React component:"))
1245
+ for value in _summary_values(summary_data, "entrypoints")
1246
+ )
1247
+
1248
+
1249
+ def _has_strong_structural_reason(reasons: list[str]) -> bool:
1250
+ return any(
1251
+ reason.startswith((
1252
+ "API endpoint pair",
1253
+ "API route owner match",
1254
+ "direct content evidence",
1255
+ "direct dependency",
1256
+ "historically co-changed",
1257
+ "keyword phrase match:",
1258
+ "literal definition match:",
1259
+ "matched call:",
1260
+ "matched define:",
1261
+ "matched entrypoint:",
1262
+ "multi-token",
1263
+ "quoted literal match:",
1264
+ "recall neighbor",
1265
+ "reverse dependency",
1266
+ "test for",
1267
+ "workspace match",
1268
+ ))
1269
+ or reason in {
1270
+ "build/dependency metadata",
1271
+ "config file",
1272
+ "has related tests",
1273
+ "knowledge/architecture doc",
1274
+ "release/version metadata",
1275
+ }
1276
+ for reason in reasons
1277
+ )
1278
+
1279
+
1280
+ def _keyword_only_false_positive(path: str, reasons: list[str], content_hits: int) -> bool:
1281
+ if _is_test_file(path):
1282
+ return False
1283
+ if _has_strong_structural_reason(reasons):
1284
+ return False
1285
+ keyword_reasons = [
1286
+ reason for reason in reasons
1287
+ if reason == "filename keyword match"
1288
+ or reason == "symbol keyword match"
1289
+ or reason.startswith((
1290
+ "content keyword match",
1291
+ "matched domain:",
1292
+ "matched naming keyword:",
1293
+ "matched ranking keyword:",
1294
+ "matched role keyword:",
1295
+ ))
1296
+ ]
1297
+ if len(keyword_reasons) < 2:
1298
+ return False
1299
+ if _is_api_route_path(path):
1300
+ return False
1301
+ if content_hits >= 4 and "symbol keyword match" in reasons:
1302
+ return False
1303
+ return True
1304
+
1305
+
1163
1306
  def score_files(
1164
1307
  files: list[FileInfo],
1165
1308
  changed_paths: set[str],
@@ -1296,6 +1439,12 @@ def score_files(
1296
1439
  score += min(-6.0, w.weak_filename_match_penalty / 2)
1297
1440
  reasons.append(f"generic public API penalty: {generic_public_names[0]}")
1298
1441
 
1442
+ api_route_terms = set(_api_route_terms(fi.path))
1443
+ api_route_matches = api_route_terms & (set(_keyword_token_weights(keywords, path=fi.path)) - _PATH_NOISE_TOKENS)
1444
+ if api_route_matches:
1445
+ score += 170.0 + (35.0 * min(2, len(api_route_matches) - 1))
1446
+ reasons.append(f"API route owner match: {_api_route_label(fi.path)}")
1447
+
1299
1448
  content_hits = 0
1300
1449
  searchable_text = ""
1301
1450
  if fi.content is not None:
@@ -1368,6 +1517,8 @@ def score_files(
1368
1517
  if matched_task_signal and _has_role(fi.path, _IMPLEMENTATION_ROLE_TOKENS):
1369
1518
  score += w.implementation_role
1370
1519
  reasons.append("implementation role match")
1520
+ elif fi.path in changed_paths:
1521
+ reasons.append("modified workspace context only")
1371
1522
 
1372
1523
  if explicit_test_task:
1373
1524
  if _is_test_file(fi.path):
@@ -1397,6 +1548,8 @@ def score_files(
1397
1548
  if tests and any(t in all_paths for t in tests):
1398
1549
  score += w.related_test
1399
1550
  reasons.append("has related tests")
1551
+ elif _is_api_route_path(fi.path):
1552
+ reasons.append("no direct tests found for endpoint")
1400
1553
 
1401
1554
  if _is_test_file(fi.path):
1402
1555
  for src_path in changed_paths:
@@ -1460,6 +1613,10 @@ def score_files(
1460
1613
  score += w.large_unrelated_penalty
1461
1614
  reasons.append("large unrelated file")
1462
1615
 
1616
+ if _keyword_only_false_positive(fi.path, reasons, content_hits):
1617
+ score = max(0.0, score * 0.72)
1618
+ reasons.append("likely false positive: keyword-only match")
1619
+
1463
1620
  results.append((fi, score, reasons))
1464
1621
 
1465
1622
  return results
@@ -1507,6 +1664,107 @@ def boost_cross_layer_related(
1507
1664
  return result
1508
1665
 
1509
1666
 
1667
+ def boost_api_endpoint_pairs(
1668
+ scored: list[tuple[FileInfo, float, list[str]]],
1669
+ keywords: set[str] | dict[str, float] | KeywordPlan,
1670
+ weights: ScoringWeights | None = None,
1671
+ ) -> list[tuple[FileInfo, float, list[str]]]:
1672
+ """Boost sibling API endpoints once one endpoint in the family is a strong task match."""
1673
+ w = weights or _DEFAULT_WEIGHTS
1674
+ keyword_tokens = set(_keyword_token_weights(keywords)) - _PATH_NOISE_TOKENS
1675
+ api_rows: list[tuple[FileInfo, float, list[str], tuple[str, ...]]] = []
1676
+ for fi, score, reasons in scored:
1677
+ terms = _api_route_terms(fi.path)
1678
+ if terms and not fi.ignored and not fi.binary:
1679
+ api_rows.append((fi, score, reasons, terms))
1680
+ if len(api_rows) < 2:
1681
+ return scored
1682
+
1683
+ seeds: dict[str, tuple[str, float]] = {}
1684
+ for fi, score, reasons, terms in api_rows:
1685
+ if not terms:
1686
+ continue
1687
+ family = terms[0]
1688
+ direct_owner = any(reason.startswith("API route owner match:") for reason in reasons)
1689
+ endpoint_matches_task = bool(set(terms) & keyword_tokens)
1690
+ if score < 90 and not direct_owner:
1691
+ continue
1692
+ if not (direct_owner or endpoint_matches_task):
1693
+ continue
1694
+ current = seeds.get(family)
1695
+ if current is None or score > current[1]:
1696
+ seeds[family] = (fi.path, score)
1697
+ if not seeds:
1698
+ return scored
1699
+
1700
+ result: list[tuple[FileInfo, float, list[str]]] = []
1701
+ for fi, score, reasons in scored:
1702
+ terms = _api_route_terms(fi.path)
1703
+ if terms:
1704
+ family = terms[0]
1705
+ seed = seeds.get(family)
1706
+ if seed and seed[0] != fi.path and not any(reason.startswith("API endpoint pair") for reason in reasons):
1707
+ seed_path, _seed_score = seed
1708
+ amount = min(85.0, w.cross_layer_related + 15.0)
1709
+ if set(terms) & keyword_tokens:
1710
+ amount += 25.0
1711
+ score += amount
1712
+ reasons = reasons + [f"API endpoint pair with {_api_route_label(seed_path)}"]
1713
+ result.append((fi, score, reasons))
1714
+ return result
1715
+
1716
+
1717
+ def boost_frontend_api_consumers(
1718
+ scored: list[tuple[FileInfo, float, list[str]]],
1719
+ summaries: dict[str, Any] | None,
1720
+ keywords: set[str] | dict[str, float] | KeywordPlan,
1721
+ weights: ScoringWeights | None = None,
1722
+ ) -> list[tuple[FileInfo, float, list[str]]]:
1723
+ """Boost API route files consumed by scored frontend/client files."""
1724
+ if not summaries:
1725
+ return scored
1726
+ w = weights or _DEFAULT_WEIGHTS
1727
+ keyword_tokens = set(_keyword_token_weights(keywords)) - _PATH_NOISE_TOKENS
1728
+ endpoint_by_api_path: dict[str, str] = {}
1729
+ for fi, _score, _reasons in scored:
1730
+ api_path = _api_route_path(fi.path, summaries.get(fi.path))
1731
+ if api_path:
1732
+ endpoint_by_api_path[api_path] = fi.path
1733
+ if not endpoint_by_api_path:
1734
+ return scored
1735
+
1736
+ boosts: dict[str, tuple[float, str, str]] = {}
1737
+ for consumer, consumer_score, _consumer_reasons in scored:
1738
+ summary_data = summaries.get(consumer.path)
1739
+ consumed_paths = _api_paths_from_summary(summary_data)
1740
+ if not consumed_paths or consumer_score <= 0:
1741
+ continue
1742
+ if not _looks_like_frontend_consumer(consumer.path, summary_data):
1743
+ continue
1744
+ for api_path in consumed_paths:
1745
+ endpoint_path = endpoint_by_api_path.get(api_path)
1746
+ if not endpoint_path or endpoint_path == consumer.path:
1747
+ continue
1748
+ amount = min(150.0, 90.0 + (w.cross_layer_related * 0.6))
1749
+ if _api_path_terms(api_path) & keyword_tokens:
1750
+ amount += 45.0
1751
+ current = boosts.get(endpoint_path)
1752
+ if current is None or amount > current[0]:
1753
+ boosts[endpoint_path] = (amount, api_path, consumer.path)
1754
+
1755
+ if not boosts:
1756
+ return scored
1757
+ result: list[tuple[FileInfo, float, list[str]]] = []
1758
+ for fi, score, reasons in scored:
1759
+ boost = boosts.get(fi.path)
1760
+ if boost:
1761
+ amount, api_path, consumer_path = boost
1762
+ score += amount
1763
+ reasons = reasons + [f"API producer for frontend call {api_path} from {consumer_path}"]
1764
+ result.append((fi, score, reasons))
1765
+ return result
1766
+
1767
+
1510
1768
  def boost_paired_tests(
1511
1769
  scored: list[tuple[FileInfo, float, list[str]]],
1512
1770
  weights: ScoringWeights | None = None,
@@ -323,7 +323,7 @@ def _js_ts_intelligence(path: str, text: str, symbols: list[Symbol]) -> CodeInte
323
323
  if text.startswith("#!") and "node" in text.splitlines()[0]:
324
324
  entrypoints.append(f"CLI script: {norm_path}")
325
325
 
326
- calls = _js_calls(text)
326
+ calls = [*_js_calls(text), *_js_api_calls(text)]
327
327
  return CodeIntelligence(
328
328
  entrypoints=_dedupe(entrypoints)[:40],
329
329
  defines=_dedupe(defines)[:60],
@@ -488,6 +488,24 @@ def _js_calls(text: str) -> list[str]:
488
488
  return calls
489
489
 
490
490
 
491
+ def _js_api_calls(text: str) -> list[str]:
492
+ calls: list[str] = []
493
+ for raw in re.findall(r"['\"`](/api/[^'\"`\s)]+)", text):
494
+ normalized = _normalize_api_literal(raw)
495
+ if normalized:
496
+ calls.append(f"API call: {normalized}")
497
+ return calls
498
+
499
+
500
+ def _normalize_api_literal(raw: str) -> str:
501
+ value = raw.split("?", 1)[0].split("#", 1)[0]
502
+ value = value.split("${", 1)[0]
503
+ value = value.rstrip("/,;)")
504
+ if not value.startswith("/api/"):
505
+ return ""
506
+ return value.rstrip("/") or "/api"
507
+
508
+
491
509
  def _next_api_path(path: str) -> str:
492
510
  match = re.search(r"(?:^|/)app/api/(.*)/route\.(?:ts|tsx|js|jsx)$", path)
493
511
  if not match: