sourcecode 1.33.12__tar.gz → 1.33.13__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 (95) hide show
  1. {sourcecode-1.33.12 → sourcecode-1.33.13}/PKG-INFO +1 -1
  2. {sourcecode-1.33.12 → sourcecode-1.33.13}/pyproject.toml +1 -1
  3. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/__init__.py +1 -1
  4. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/cli.py +6 -0
  5. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/output_budget.py +2 -2
  6. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/prepare_context.py +106 -2
  7. {sourcecode-1.33.12 → sourcecode-1.33.13}/.github/workflows/build-windows.yml +0 -0
  8. {sourcecode-1.33.12 → sourcecode-1.33.13}/.gitignore +0 -0
  9. {sourcecode-1.33.12 → sourcecode-1.33.13}/.ruff.toml +0 -0
  10. {sourcecode-1.33.12 → sourcecode-1.33.13}/CHANGELOG.md +0 -0
  11. {sourcecode-1.33.12 → sourcecode-1.33.13}/CONTRIBUTING.md +0 -0
  12. {sourcecode-1.33.12 → sourcecode-1.33.13}/LICENSE +0 -0
  13. {sourcecode-1.33.12 → sourcecode-1.33.13}/README.md +0 -0
  14. {sourcecode-1.33.12 → sourcecode-1.33.13}/SECURITY.md +0 -0
  15. {sourcecode-1.33.12 → sourcecode-1.33.13}/raw +0 -0
  16. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/adaptive_scanner.py +0 -0
  17. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/architecture_analyzer.py +0 -0
  18. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/architecture_summary.py +0 -0
  19. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/ast_extractor.py +0 -0
  20. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/cache.py +0 -0
  21. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/canonical_ir.py +0 -0
  22. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/classifier.py +0 -0
  23. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/code_notes_analyzer.py +0 -0
  24. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/confidence_analyzer.py +0 -0
  25. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/context_scorer.py +0 -0
  26. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/context_summarizer.py +0 -0
  27. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/contract_model.py +0 -0
  28. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/contract_pipeline.py +0 -0
  29. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/coverage_parser.py +0 -0
  30. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/dependency_analyzer.py +0 -0
  31. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/__init__.py +0 -0
  32. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/base.py +0 -0
  33. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/csproj_parser.py +0 -0
  34. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/dart.py +0 -0
  35. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/dotnet.py +0 -0
  36. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/elixir.py +0 -0
  37. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/go.py +0 -0
  38. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/heuristic.py +0 -0
  39. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/hybrid.py +0 -0
  40. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/java.py +0 -0
  41. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/jvm_ext.py +0 -0
  42. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/nodejs.py +0 -0
  43. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/parsers.py +0 -0
  44. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/php.py +0 -0
  45. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/project.py +0 -0
  46. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/python.py +0 -0
  47. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/ruby.py +0 -0
  48. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/rust.py +0 -0
  49. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/systems.py +0 -0
  50. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/terraform.py +0 -0
  51. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/detectors/tooling.py +0 -0
  52. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/doc_analyzer.py +0 -0
  53. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/entrypoint_classifier.py +0 -0
  54. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/env_analyzer.py +0 -0
  55. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/error_schema.py +0 -0
  56. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/file_classifier.py +0 -0
  57. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/flow_analyzer.py +0 -0
  58. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/git_analyzer.py +0 -0
  59. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/graph_analyzer.py +0 -0
  60. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/license.py +0 -0
  61. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp/__init__.py +0 -0
  62. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  63. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  64. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  65. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  66. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  67. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp/orchestrator.py +0 -0
  68. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp/registry.py +0 -0
  69. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp/runner.py +0 -0
  70. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp/server.py +0 -0
  71. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/mcp_nudge.py +0 -0
  72. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/metrics_analyzer.py +0 -0
  73. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/path_filters.py +0 -0
  74. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/pr_comment_renderer.py +0 -0
  75. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/progress.py +0 -0
  76. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/ranking_engine.py +0 -0
  77. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/redactor.py +0 -0
  78. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/relevance_scorer.py +0 -0
  79. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/repo_classifier.py +0 -0
  80. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/repository_ir.py +0 -0
  81. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/ris.py +0 -0
  82. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/runtime_classifier.py +0 -0
  83. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/scanner.py +0 -0
  84. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/schema.py +0 -0
  85. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/semantic_analyzer.py +0 -0
  86. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/serializer.py +0 -0
  87. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/summarizer.py +0 -0
  88. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/telemetry/__init__.py +0 -0
  89. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/telemetry/config.py +0 -0
  90. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/telemetry/consent.py +0 -0
  91. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/telemetry/events.py +0 -0
  92. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/telemetry/filters.py +0 -0
  93. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/telemetry/transport.py +0 -0
  94. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/tree_utils.py +0 -0
  95. {sourcecode-1.33.12 → sourcecode-1.33.13}/src/sourcecode/workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.33.12
3
+ Version: 1.33.13
4
4
  Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
5
5
  License-File: LICENSE
6
6
  Keywords: agents,ai,codebase,context,developer-tools,llm
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.33.12"
7
+ version = "1.33.13"
8
8
  description = "Persistent structural context and ultra-fast repeated analysis for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Deterministic codebase context maps for AI coding agents."""
2
2
 
3
- __version__ = "1.33.12"
3
+ __version__ = "1.33.13"
@@ -1102,6 +1102,9 @@ def main(
1102
1102
  obj = _jm.loads(raw)
1103
1103
  if isinstance(obj, dict):
1104
1104
  obj["_cache"] = meta
1105
+ # Top-level cache_source for one release — backward compat alias
1106
+ if "cache_source" in meta:
1107
+ obj["cache_source"] = meta["cache_source"]
1105
1108
  return _jm.dumps(obj, indent=2, ensure_ascii=False)
1106
1109
  except Exception:
1107
1110
  pass
@@ -2273,6 +2276,9 @@ def _make_explanation(reason: str, why: str) -> str:
2273
2276
  def _serialize_relevant_file(f: Any) -> dict:
2274
2277
  from dataclasses import asdict as _asdict
2275
2278
  d = {k: v for k, v in _asdict(f).items() if v != "" and v is not None}
2279
+ # Emit 'file' as backward-compat alias for 'path' for one release
2280
+ if "path" in d:
2281
+ d["file"] = d["path"]
2276
2282
  reason = d.pop("reason", "") or ""
2277
2283
  why = d.pop("why", "") or ""
2278
2284
  # Expose score as a rounded float so agents can rank/filter files deterministically.
@@ -67,7 +67,7 @@ _TRIM_SCHEDULE: list[tuple[str, str | None, int]] = [
67
67
  ("execution_paths", None, 0),
68
68
  ("dependency_graph_summary", None, 0),
69
69
  # Step 6 — last resort
70
- ("relevant_files", None, 3),
70
+ ("relevant_files", None, 10),
71
71
  ("suspected_areas", None, 0),
72
72
  ("key_dependencies", None, 0),
73
73
  ]
@@ -148,7 +148,7 @@ def trim_to_budget(data: dict, budget_bytes: int, *, label: str = "") -> dict:
148
148
  # Budget constants (bytes) — used by CLI callers
149
149
  BUDGET_COMPACT = 30_000 # compact/agent main cmd
150
150
  BUDGET_AGENT = 40_000 # agent main cmd (slightly more headroom)
151
- BUDGET_FIX_BUG = 100_000 # fix-bug (with or without --symptom)
151
+ BUDGET_FIX_BUG = 200_000 # fix-bug (with or without --symptom)
152
152
  BUDGET_REVIEW_PR = 100_000 # review-pr
153
153
  BUDGET_ONBOARD = 30_000 # onboard
154
154
  BUDGET_EXPLAIN = 30_000 # explain
@@ -1725,6 +1725,7 @@ class TaskContextBuilder:
1725
1725
  _sx_commits: list[dict] = []
1726
1726
  _sx_synonyms: list[str] = []
1727
1727
  _sx_boosts: list[dict] = []
1728
+ _sx_graph_expanded: list[str] = []
1728
1729
 
1729
1730
  # Pass 1: surface code notes whose text contains any keyword
1730
1731
  _note_matched_paths: dict[str, int] = {} # path → count of matching notes
@@ -1897,6 +1898,7 @@ class TaskContextBuilder:
1897
1898
  _no_scan_candidates = relevant_files[_CONTENT_SCAN_LIMIT:]
1898
1899
 
1899
1900
  _boosted: list[RelevantFile] = []
1901
+ _scanned_body: dict[str, str] = {} # cache for graph expansion (Pass 5)
1900
1902
  for _rf in _scan_candidates:
1901
1903
  _extra = 0.0
1902
1904
  _extra_syn = 0.0
@@ -1931,9 +1933,11 @@ class TaskContextBuilder:
1931
1933
  _body_lower = ""
1932
1934
  if Path(_rf.path).suffix.lower() in _src_exts:
1933
1935
  try:
1934
- _body_lower = (self.root / _rf.path).read_text(
1936
+ _raw_body = (self.root / _rf.path).read_text(
1935
1937
  encoding="utf-8", errors="replace"
1936
- )[:12000].lower() # ~300 lines avg
1938
+ )[:12000] # ~300 lines avg
1939
+ _scanned_body[_rf.path] = _raw_body # cache for Pass 5
1940
+ _body_lower = _raw_body.lower()
1937
1941
  except OSError:
1938
1942
  pass
1939
1943
 
@@ -1993,6 +1997,105 @@ class TaskContextBuilder:
1993
1997
  key=lambda rf: (-rf.score, -_boost_totals.get(rf.path, 0)),
1994
1998
  )
1995
1999
 
2000
+ # Pass 5: reverse graph expansion from high-score seed nodes.
2001
+ # Identifies which source files in the repo REFERENCE the seed
2002
+ # classes (imports, implements, extends, field declarations).
2003
+ # This is a reverse-import lookup: for seed class "UserProvider",
2004
+ # it finds JpaUserProvider / DefaultUserSessionProvider which import
2005
+ # UserProvider — even though those files don't contain symptom
2006
+ # keywords in their own path.
2007
+ # Seeds include any high-score file (not just symptom_match role)
2008
+ # so that files found by _rank_files class-name matching also expand.
2009
+ if not fast:
2010
+ import re as _re_gx
2011
+ _GX_SEED_THRESH = 0.5
2012
+ _GX_EXPAND_CAP = 30
2013
+ _GX_HOP_DECAY = 0.6
2014
+
2015
+ # Collect seed class names from high-score results
2016
+ _gx_seed_stems: dict[str, float] = {} # stem → score
2017
+ for _gx_rf in relevant_files:
2018
+ if _gx_rf.score < _GX_SEED_THRESH:
2019
+ continue
2020
+ if Path(_gx_rf.path).suffix.lower() not in _src_exts:
2021
+ continue
2022
+ _gx_stem = Path(_gx_rf.path).stem
2023
+ _gx_seed_stems[_gx_stem] = max(
2024
+ _gx_seed_stems.get(_gx_stem, 0.0), _gx_rf.score
2025
+ )
2026
+
2027
+ if _gx_seed_stems:
2028
+ # Compile per-stem word-boundary patterns for fast matching
2029
+ import re as _re_gx2
2030
+ _gx_patterns: dict[str, Any] = {
2031
+ stem: _re_gx2.compile(rf'\b{_re_gx2.escape(stem)}\b')
2032
+ for stem in _gx_seed_stems
2033
+ }
2034
+
2035
+ _gx_existing = {rf.path for rf in relevant_files}
2036
+ _gx_new: list[RelevantFile] = []
2037
+ _gx_added: set[str] = set()
2038
+
2039
+ # Candidates: non-test source files not yet in results.
2040
+ # Small repos: scan all; large repos: use pre-scanned content only.
2041
+ # Test files are excluded (fix-bug focuses on production code).
2042
+ if _is_large_repo:
2043
+ _gx_candidates = [
2044
+ p for p in _scanned_body
2045
+ if p not in _gx_existing and not self._is_test(p)
2046
+ ]
2047
+ else:
2048
+ _gx_candidates = [
2049
+ p for p in all_paths
2050
+ if p not in _gx_existing
2051
+ and Path(p).suffix.lower() in _src_exts
2052
+ and not self._is_test(p)
2053
+ ]
2054
+
2055
+ for _gx_cand in _gx_candidates:
2056
+ if len(_gx_new) >= _GX_EXPAND_CAP:
2057
+ break
2058
+ if _gx_cand in _gx_added:
2059
+ continue
2060
+
2061
+ # Use cached content or read fresh (small repos only)
2062
+ _gx_body = _scanned_body.get(_gx_cand)
2063
+ if _gx_body is None:
2064
+ if _is_large_repo:
2065
+ continue # never do fresh reads on large repos in Pass 5
2066
+ try:
2067
+ _gx_body = (self.root / _gx_cand).read_text(
2068
+ encoding="utf-8", errors="replace"
2069
+ )[:8000]
2070
+ except OSError:
2071
+ continue
2072
+
2073
+ # Reverse lookup: does this file reference any seed class?
2074
+ for _gx_stem, _gx_seed_score in _gx_seed_stems.items():
2075
+ if _gx_patterns[_gx_stem].search(_gx_body):
2076
+ _hop1_score = round(
2077
+ min(_gx_seed_score * _GX_HOP_DECAY, 0.85), 2
2078
+ )
2079
+ _gx_new.append(RelevantFile(
2080
+ path=_gx_cand,
2081
+ role="symptom_match",
2082
+ score=_hop1_score,
2083
+ reason=(
2084
+ f"graph_expansion: references {_gx_stem} "
2085
+ f"(1-hop reverse import)"
2086
+ ),
2087
+ why=f"graph_expansion: 1 hop from {_gx_stem}",
2088
+ ))
2089
+ _gx_added.add(_gx_cand)
2090
+ _sx_graph_expanded.append(_gx_cand)
2091
+ break # one match per candidate is enough
2092
+
2093
+ if _gx_new:
2094
+ relevant_files = sorted(
2095
+ relevant_files + _gx_new,
2096
+ key=lambda rf: (-rf.score, -_boost_totals.get(rf.path, 0)),
2097
+ )
2098
+
1996
2099
  # Synonym note (only when synonyms actually fired)
1997
2100
  if _frontend_kws and _sx_synonyms:
1998
2101
  symptom_note = (
@@ -2016,6 +2119,7 @@ class TaskContextBuilder:
2016
2119
  "content_matches": _sx_content[:10],
2017
2120
  "commit_matches": _sx_commits[:10],
2018
2121
  "synonym_matches": _sx_synonyms[:10],
2122
+ "graph_expansion": _sx_graph_expanded[:10],
2019
2123
  "boosts": _sx_boosts[:30],
2020
2124
  "final_boost": round(
2021
2125
  sum(b["value"] for b in _sx_boosts), 3
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes