agentpack-cli 0.2.2__tar.gz → 0.3.0__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 (92) hide show
  1. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/PKG-INFO +5 -5
  2. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/README.md +4 -4
  3. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/pyproject.toml +1 -1
  4. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/__init__.py +1 -1
  5. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/ranking.py +110 -6
  6. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/repo_map.py +20 -1
  7. agentpack_cli-0.3.0/src/agentpack/analysis/role_inference.py +553 -0
  8. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/symbols.py +1 -1
  9. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/application/pack_service.py +8 -0
  10. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/cache.py +6 -2
  11. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/config.py +5 -1
  12. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/context_pack.py +12 -0
  13. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/models.py +20 -7
  14. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/summaries/offline.py +191 -51
  15. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/.gitignore +0 -0
  16. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/LICENSE +0 -0
  17. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/adapters/__init__.py +0 -0
  18. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/adapters/antigravity.py +0 -0
  19. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/adapters/base.py +0 -0
  20. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/adapters/claude.py +0 -0
  21. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/adapters/codex.py +0 -0
  22. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/adapters/cursor.py +0 -0
  23. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/adapters/detect.py +0 -0
  24. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/adapters/generic.py +0 -0
  25. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/adapters/windsurf.py +0 -0
  26. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/__init__.py +0 -0
  27. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/dependency_graph.py +0 -0
  28. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/go_imports.py +0 -0
  29. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/java_imports.py +0 -0
  30. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/js_ts_imports.py +0 -0
  31. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/monorepo.py +0 -0
  32. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/python_imports.py +0 -0
  33. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/rust_imports.py +0 -0
  34. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/task_classifier.py +0 -0
  35. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/analysis/tests.py +0 -0
  36. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/application/__init__.py +0 -0
  37. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/cli.py +0 -0
  38. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/__init__.py +0 -0
  39. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/_shared.py +0 -0
  40. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/benchmark.py +0 -0
  41. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/claude_cmd.py +0 -0
  42. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/diff.py +0 -0
  43. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/doctor.py +0 -0
  44. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/explain.py +0 -0
  45. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/hook_cmd.py +0 -0
  46. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/init.py +0 -0
  47. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/install.py +0 -0
  48. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/mcp_cmd.py +0 -0
  49. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/monitor.py +0 -0
  50. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/pack.py +0 -0
  51. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/quickstart.py +0 -0
  52. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/repair.py +0 -0
  53. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/scan.py +0 -0
  54. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/stats.py +0 -0
  55. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/status.py +0 -0
  56. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/summarize.py +0 -0
  57. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/tune.py +0 -0
  58. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/commands/watch.py +0 -0
  59. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/__init__.py +0 -0
  60. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/bootstrap.py +0 -0
  61. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/diff.py +0 -0
  62. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/git.py +0 -0
  63. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/git_hooks.py +0 -0
  64. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/global_install.py +0 -0
  65. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/ignore.py +0 -0
  66. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/merkle.py +0 -0
  67. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/redactor.py +0 -0
  68. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/scanner.py +0 -0
  69. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/snapshot.py +0 -0
  70. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/token_estimator.py +0 -0
  71. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/core/vscode_tasks.py +0 -0
  72. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/data/agentpack.md +0 -0
  73. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/installers/__init__.py +0 -0
  74. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/installers/antigravity.py +0 -0
  75. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/installers/claude.py +0 -0
  76. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/installers/codex.py +0 -0
  77. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/installers/cursor.py +0 -0
  78. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/installers/windsurf.py +0 -0
  79. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/integrations/__init__.py +0 -0
  80. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/integrations/agents.py +0 -0
  81. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/integrations/git_hooks.py +0 -0
  82. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/integrations/global_install.py +0 -0
  83. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/integrations/vscode_tasks.py +0 -0
  84. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/mcp_server.py +0 -0
  85. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/renderers/__init__.py +0 -0
  86. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/renderers/compact.py +0 -0
  87. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/renderers/markdown.py +0 -0
  88. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/renderers/receipts.py +0 -0
  89. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/session/__init__.py +0 -0
  90. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/session/state.py +0 -0
  91. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/summaries/__init__.py +0 -0
  92. {agentpack_cli-0.2.2 → agentpack_cli-0.3.0}/src/agentpack/summaries/base.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentpack-cli
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: Task-aware context packing for AI coding agents — Claude, Cursor, Windsurf, Codex, and Antigravity
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -44,7 +44,7 @@ Description-Content-Type: text/markdown
44
44
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
45
45
  [![CI](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml/badge.svg)](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
46
46
 
47
- > **Status: alpha (v0.2.1).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Not yet validated across a wide range of repos. API may change before 1.0.
47
+ > **Status: alpha (v0.3.0).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Public benchmark proof exists for the current suite, but broader repo coverage is still growing. API may change before 1.0.
48
48
  >
49
49
  > **Platform note:** macOS and Linux are fully supported. Windows support is not yet implemented (git hooks use POSIX shell; the Claude Code session hooks use `python3`/`rm -f`). Contributions welcome.
50
50
 
@@ -93,7 +93,7 @@ npm install -g @vishal2612200/agentpack
93
93
  agentpack --version
94
94
  ```
95
95
 
96
- The npm package is a Node launcher around the Python implementation. It installs the matching `agentpack-cli` package into a per-version virtual environment on first run.
96
+ The npm package is a Node launcher around the Python implementation. It requires Node.js 18+ and Python 3.10+, then installs the matching core `agentpack-cli` package into a per-version virtual environment on first run. The Python package remains the source of truth; npm is the convenience install path for JavaScript-heavy teams. Use the PyPI extras below when you need optional `watch` or `mcp` dependencies.
97
97
 
98
98
  ## Quickstart
99
99
 
@@ -1451,7 +1451,7 @@ src/agentpack/
1451
1451
 
1452
1452
  ## Roadmap
1453
1453
 
1454
- Next release target: **0.3.0 = public proof + npm publish hardening**.
1454
+ Post-0.3 release focus: broader real-repo proof, npm publish reliability, and continued ranking precision.
1455
1455
 
1456
1456
  - Expand the public real-repo suite beyond the current curated Pallets smoke set.
1457
1457
  - Keep recall gains measured with `--prove-targets`; target 60%+ recall, 50%+ token precision, and task packs under 25k tokens.
@@ -1495,7 +1495,7 @@ agentpack benchmark --sample-fixtures --misses
1495
1495
  agentpack doctor
1496
1496
  ```
1497
1497
 
1498
- For npm publish, configure GitHub secret `NPM_TOKEN`. `agentpack doctor` warns locally when neither `NPM_TOKEN` nor `NODE_AUTH_TOKEN` is present, and the npm publish workflow fails early with a clear error if the secret is missing.
1498
+ For npm publish, configure GitHub secret `NPM_TOKEN`. The token must publish to the npm scope in `npm/package.json` (`@vishal2612200` today): use a token from that npm user, or create an npm org with that scope and grant the token owner publish access. If `npm publish` reaches the registry and then fails with `E404 Not Found - PUT ... @scope/package`, the token is authenticated but does not own or have write access to that scope. `agentpack doctor` warns locally when neither `NPM_TOKEN` nor `NODE_AUTH_TOKEN` is present, and the npm publish workflow fails early when the secret or scope access is wrong.
1499
1499
 
1500
1500
  Good contribution areas:
1501
1501
 
@@ -5,7 +5,7 @@
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
  [![CI](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml/badge.svg)](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
7
7
 
8
- > **Status: alpha (v0.2.1).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Not yet validated across a wide range of repos. API may change before 1.0.
8
+ > **Status: alpha (v0.3.0).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Public benchmark proof exists for the current suite, but broader repo coverage is still growing. API may change before 1.0.
9
9
  >
10
10
  > **Platform note:** macOS and Linux are fully supported. Windows support is not yet implemented (git hooks use POSIX shell; the Claude Code session hooks use `python3`/`rm -f`). Contributions welcome.
11
11
 
@@ -54,7 +54,7 @@ npm install -g @vishal2612200/agentpack
54
54
  agentpack --version
55
55
  ```
56
56
 
57
- The npm package is a Node launcher around the Python implementation. It installs the matching `agentpack-cli` package into a per-version virtual environment on first run.
57
+ The npm package is a Node launcher around the Python implementation. It requires Node.js 18+ and Python 3.10+, then installs the matching core `agentpack-cli` package into a per-version virtual environment on first run. The Python package remains the source of truth; npm is the convenience install path for JavaScript-heavy teams. Use the PyPI extras below when you need optional `watch` or `mcp` dependencies.
58
58
 
59
59
  ## Quickstart
60
60
 
@@ -1412,7 +1412,7 @@ src/agentpack/
1412
1412
 
1413
1413
  ## Roadmap
1414
1414
 
1415
- Next release target: **0.3.0 = public proof + npm publish hardening**.
1415
+ Post-0.3 release focus: broader real-repo proof, npm publish reliability, and continued ranking precision.
1416
1416
 
1417
1417
  - Expand the public real-repo suite beyond the current curated Pallets smoke set.
1418
1418
  - Keep recall gains measured with `--prove-targets`; target 60%+ recall, 50%+ token precision, and task packs under 25k tokens.
@@ -1456,7 +1456,7 @@ agentpack benchmark --sample-fixtures --misses
1456
1456
  agentpack doctor
1457
1457
  ```
1458
1458
 
1459
- For npm publish, configure GitHub secret `NPM_TOKEN`. `agentpack doctor` warns locally when neither `NPM_TOKEN` nor `NODE_AUTH_TOKEN` is present, and the npm publish workflow fails early with a clear error if the secret is missing.
1459
+ For npm publish, configure GitHub secret `NPM_TOKEN`. The token must publish to the npm scope in `npm/package.json` (`@vishal2612200` today): use a token from that npm user, or create an npm org with that scope and grant the token owner publish access. If `npm publish` reaches the registry and then fails with `E404 Not Found - PUT ... @scope/package`, the token is authenticated but does not own or have write access to that scope. `agentpack doctor` warns locally when neither `NPM_TOKEN` nor `NODE_AUTH_TOKEN` is present, and the npm publish workflow fails early when the secret or scope access is wrong.
1460
1460
 
1461
1461
  Good contribution areas:
1462
1462
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentpack-cli"
3
- version = "0.2.2"
3
+ version = "0.3.0"
4
4
  description = "Task-aware context packing for AI coding agents — Claude, Cursor, Windsurf, Codex, and Antigravity"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -1,3 +1,3 @@
1
1
  """AgentPack — task-aware context packing for AI coding agents."""
2
2
 
3
- __version__ = "0.2.2"
3
+ __version__ = "0.3.0"
@@ -160,6 +160,12 @@ _VARIANTS: dict[str, str] = {
160
160
  "middleware": "middleware",
161
161
  "request": "req",
162
162
  "response": "res",
163
+ "verification": "verify",
164
+ "verified": "verify",
165
+ "verifying": "verify",
166
+ "payments": "payment",
167
+ "webhooks": "webhook",
168
+ "variables": "variable",
163
169
  "session": "session",
164
170
  "sessions": "session",
165
171
  "error": "error",
@@ -226,6 +232,7 @@ _FILENAME_CORROBORATION_PREFIXES = (
226
232
  "staged",
227
233
  "symbol keyword match",
228
234
  "content keyword match",
235
+ "matched ",
229
236
  "direct dependency",
230
237
  "reverse dependency",
231
238
  "has related tests",
@@ -404,6 +411,82 @@ def _symbol_matches_keywords(symbols: list[str], keywords: set[str] | dict[str,
404
411
  return best_weight
405
412
 
406
413
 
414
+ def _summary_values(summary: object, field: str) -> list[str]:
415
+ if summary is None:
416
+ return []
417
+ if isinstance(summary, dict):
418
+ value = summary.get(field)
419
+ else:
420
+ value = getattr(summary, field, None)
421
+ if value is None:
422
+ return []
423
+ if isinstance(value, str):
424
+ return [value]
425
+ if isinstance(value, list):
426
+ result: list[str] = []
427
+ for item in value:
428
+ if isinstance(item, str):
429
+ result.append(item)
430
+ elif isinstance(item, dict) and "name" in item:
431
+ result.append(str(item["name"]))
432
+ elif hasattr(item, "name"):
433
+ result.append(str(item.name))
434
+ else:
435
+ result.append(str(item))
436
+ return result
437
+ return [str(value)]
438
+
439
+
440
+ def _best_summary_match(
441
+ values: list[str],
442
+ keywords: set[str] | dict[str, float],
443
+ *,
444
+ presence_terms: set[str] | None = None,
445
+ ) -> tuple[str, float] | None:
446
+ if not values:
447
+ return None
448
+ best_value = ""
449
+ best_weight = 0.0
450
+ for value in values:
451
+ weight = _match_weight(value, keywords)
452
+ if weight > best_weight:
453
+ best_value = value
454
+ best_weight = weight
455
+ if best_weight > 0:
456
+ return best_value, best_weight
457
+ if presence_terms and (set(_keyword_token_weights(keywords)) & presence_terms):
458
+ return values[0], 0.6
459
+ return None
460
+
461
+
462
+ def _short_reason_value(value: str, max_len: int = 80) -> str:
463
+ clean = " ".join(value.split())
464
+ if len(clean) <= max_len:
465
+ return clean
466
+ return clean[: max_len - 1].rstrip() + "..."
467
+
468
+
469
+ _GENERIC_SUMMARY_VALUES = {
470
+ "HTTP API route handler",
471
+ "React UI component",
472
+ "React page component",
473
+ "React page: page",
474
+ "entrypoint",
475
+ "configuration",
476
+ "api",
477
+ "frontend",
478
+ "data",
479
+ }
480
+
481
+
482
+ def _summary_boost_weight(field: str, value: str, amount: float) -> float:
483
+ if field in {"role", "domain"} and value in _GENERIC_SUMMARY_VALUES:
484
+ return min(amount, 16.0)
485
+ if field == "ranking_keywords" and value in {"handler", "http", "route", "api", "component", "page"}:
486
+ return min(amount, 10.0)
487
+ return amount
488
+
489
+
407
490
  def _has_role(path: str, roles: set[str]) -> bool:
408
491
  return bool(_path_tokens(path) & roles)
409
492
 
@@ -463,17 +546,38 @@ def score_files(
463
546
 
464
547
  node = dep_graph.get(fi.path)
465
548
  sym_names: list[str] = []
466
- if summaries and fi.path in summaries:
467
- raw_syms = summaries[fi.path].get("symbols", [])
468
- sym_names = [
469
- (s["name"] if isinstance(s, dict) else s.name)
470
- for s in raw_syms
471
- ]
549
+ summary_data = summaries.get(fi.path) if summaries and fi.path in summaries else None
550
+ if summary_data:
551
+ sym_names = _summary_values(summary_data, "symbols")
472
552
  symbol_weight = _symbol_matches_keywords(sym_names, keywords)
473
553
  if symbol_weight > 0:
474
554
  score += w.symbol_keyword * symbol_weight
475
555
  reasons.append("symbol keyword match")
476
556
 
557
+ if summary_data:
558
+ summary_boosts = [
559
+ ("entrypoints", "matched entrypoint", 72.0, None),
560
+ ("external_systems", "matched external system", 64.0, None),
561
+ ("role", "matched role keyword", 56.0, None),
562
+ ("domain", "matched domain", 50.0, None),
563
+ ("ranking_keywords", "matched ranking keyword", 44.0, None),
564
+ ("defines", "matched define", 42.0, None),
565
+ ("reads_env", "matched env read", 52.0, {"env", "environment", "variable", "config", "settings"}),
566
+ ("side_effects", "matched side effect", 46.0, {"side", "effect", "effects", "io", "debug"}),
567
+ ("calls", "matched call", 26.0, None),
568
+ ]
569
+ for field, label, amount, presence_terms in summary_boosts:
570
+ match = _best_summary_match(
571
+ _summary_values(summary_data, field),
572
+ keywords,
573
+ presence_terms=presence_terms,
574
+ )
575
+ if not match:
576
+ continue
577
+ value, match_weight = match
578
+ score += _summary_boost_weight(field, value, amount) * match_weight
579
+ reasons.append(f"{label}: {_short_reason_value(value)}")
580
+
477
581
  content_hits = 0
478
582
  if fi.content is not None:
479
583
  hits, hit_weight = _content_matches_keywords(fi.content, keywords)
@@ -44,7 +44,7 @@ def build_repo_map(
44
44
  top_members = sorted(members, key=lambda member: file_scores.get(member.path, 0.0), reverse=True)[:4]
45
45
  for member in top_members:
46
46
  summary = summaries.get(member.path) or {}
47
- label = summary.get("role") or _short_summary(summary.get("summary", ""))
47
+ label = _member_label(summary)
48
48
  deps = dep_graph.get(member.path)
49
49
  rel = ""
50
50
  if deps.imports or deps.imported_by:
@@ -71,7 +71,12 @@ def _group_role(members: list[FileInfo], summaries: dict[str, Any]) -> str:
71
71
  roles: dict[str, int] = {}
72
72
  for member in members:
73
73
  summary = summaries.get(member.path) or {}
74
+ domain = summary.get("domain")
74
75
  role = summary.get("role") or _short_summary(summary.get("summary", ""))
76
+ if domain and role:
77
+ role = f"{domain} / {role}"
78
+ elif domain:
79
+ role = domain
75
80
  if role:
76
81
  roles[role] = roles.get(role, 0) + 1
77
82
  if not roles:
@@ -90,5 +95,19 @@ def _short_summary(summary: str) -> str:
90
95
  return ""
91
96
 
92
97
 
98
+ def _member_label(summary: dict[str, Any]) -> str:
99
+ domain = summary.get("domain")
100
+ role = summary.get("role") or _short_summary(summary.get("summary", ""))
101
+ parts = []
102
+ if role:
103
+ parts.append(role)
104
+ elif domain:
105
+ parts.append(domain)
106
+ entrypoints = summary.get("entrypoints") or []
107
+ if entrypoints:
108
+ parts.append(str(entrypoints[0]))
109
+ return "; ".join(parts)
110
+
111
+
93
112
  def _fits(lines: list[str], candidate: str, budget_tokens: int) -> bool:
94
113
  return estimate_tokens("\n".join([*lines, candidate])) <= budget_tokens