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.
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/PKG-INFO +42 -35
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/README.md +33 -32
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/pyproject.toml +11 -3
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/__init__.py +1 -1
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/ranking.py +258 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/role_inference.py +19 -1
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/application/pack_service.py +4 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/benchmark.py +962 -2
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/context_pack.py +872 -8
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/.gitignore +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/LICENSE +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/antigravity.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/base.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/claude.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/codex.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/cursor.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/detect.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/generic.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/adapters/windsurf.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/dependency_graph.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/go_imports.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/java_imports.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/js_ts_imports.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/monorepo.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/naming_signals.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/python_ast.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/python_imports.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/repo_map.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/rust_imports.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/symbols.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/task_classifier.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/analysis/tests.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/application/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/cli.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/_shared.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/ci_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/claude_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/compress_output.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/dashboard.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/dev_check.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/diagnose_selection.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/diff.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/doctor.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/eval_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/explain.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/guard.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/hook_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/ignore_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/init.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/install.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/learn.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/mcp_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/memory.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/migrate.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/monitor.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/next_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/pack.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/perf.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/quickstart.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/release_check.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/release_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/repair.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/retrieve.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/route.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/scan.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/skills.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/start_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/state_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/stats.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/status.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/summarize.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/task_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/threads.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/tune.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/verify_wheel.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/watch.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/workflow_cmd.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/commands/wrap.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/bootstrap.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/cache.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/changed_paths.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/config.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/diff.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/evals.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/execution_state.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/git.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/git_hooks.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/global_install.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/ignore.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/loop_protocol.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/merkle.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/models.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/modes.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/pack_registry.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/redactor.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/scanner.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/snapshot.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/task_freshness.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/thread_context.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/token_estimator.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/core/vscode_tasks.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/dashboard/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/dashboard/collectors.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/dashboard/models.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/dashboard/renderers.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/data/agentpack.md +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/antigravity.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/claude.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/codex.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/cursor.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/installers/windsurf.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/agents.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/git_hooks.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/global_install.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/platform.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/integrations/vscode_tasks.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/collector.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/extractor.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/feedback.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/lesson_ranker.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/models.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/provider.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/quality.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/renderers.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/learning/skill_map.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/mcp_server.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/output_compression/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/output_compression/core.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/renderers/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/renderers/compact.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/renderers/markdown.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/renderers/receipts.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/discovery.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/models.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/parser.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/prompt_builder.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/scoring.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/service.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/router/skills_index.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/session/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/session/events.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/session/state.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/summaries/__init__.py +0 -0
- {agentpack_cli-0.3.21 → agentpack_cli-0.3.22}/src/agentpack/summaries/base.py +0 -0
- {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.
|
|
4
|
-
Summary: Local
|
|
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
|
[](https://opensource.org/licenses/MIT)
|
|
50
56
|
[](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
|
|
51
57
|
|
|
52
|
-
**Local context
|
|
58
|
+
**Local context engine for AI coding agents.**
|
|
53
59
|
|
|
54
|
-
AgentPack
|
|
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
|

|
|
69
79
|
|
|
70
|
-
> **Status: alpha (v0.3.
|
|
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.
|
|
86
|
+
## What's New in 0.3.22
|
|
77
87
|
|
|
78
|
-
`0.3.
|
|
79
|
-
public-suite baseline
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
each commit.
|
|
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
|
-
|
|
|
140
|
-
| Avg
|
|
141
|
-
|
|
|
142
|
-
| Pack
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
###
|
|
164
|
+
### Release Benchmark Gate
|
|
157
165
|
|
|
158
|
-
The
|
|
159
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
[](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
|
|
10
10
|
|
|
11
|
-
**Local context
|
|
11
|
+
**Local context engine for AI coding agents.**
|
|
12
12
|
|
|
13
|
-
AgentPack
|
|
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
|

|
|
28
32
|
|
|
29
|
-
> **Status: alpha (v0.3.
|
|
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.
|
|
39
|
+
## What's New in 0.3.22
|
|
36
40
|
|
|
37
|
-
`0.3.
|
|
38
|
-
public-suite baseline
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
each commit.
|
|
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
|
-
|
|
|
99
|
-
| Avg
|
|
100
|
-
|
|
|
101
|
-
| Pack
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
###
|
|
117
|
+
### Release Benchmark Gate
|
|
116
118
|
|
|
117
|
-
The
|
|
118
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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.
|
|
4
|
-
description = "Local
|
|
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
|
|
|
@@ -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:
|