sourcecode 1.33.23__tar.gz → 1.33.25__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.23 → sourcecode-1.33.25}/PKG-INFO +2 -2
  2. {sourcecode-1.33.23 → sourcecode-1.33.25}/README.md +1 -1
  3. {sourcecode-1.33.23 → sourcecode-1.33.25}/pyproject.toml +1 -1
  4. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/__init__.py +1 -1
  5. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/entrypoint_classifier.py +26 -1
  6. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/prepare_context.py +39 -0
  7. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/relevance_scorer.py +26 -1
  8. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/ris.py +6 -1
  9. {sourcecode-1.33.23 → sourcecode-1.33.25}/.github/workflows/build-windows.yml +0 -0
  10. {sourcecode-1.33.23 → sourcecode-1.33.25}/.gitignore +0 -0
  11. {sourcecode-1.33.23 → sourcecode-1.33.25}/.ruff.toml +0 -0
  12. {sourcecode-1.33.23 → sourcecode-1.33.25}/CHANGELOG.md +0 -0
  13. {sourcecode-1.33.23 → sourcecode-1.33.25}/CONTRIBUTING.md +0 -0
  14. {sourcecode-1.33.23 → sourcecode-1.33.25}/LICENSE +0 -0
  15. {sourcecode-1.33.23 → sourcecode-1.33.25}/SECURITY.md +0 -0
  16. {sourcecode-1.33.23 → sourcecode-1.33.25}/raw +0 -0
  17. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/adaptive_scanner.py +0 -0
  18. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/architecture_analyzer.py +0 -0
  19. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/architecture_summary.py +0 -0
  20. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/ast_extractor.py +0 -0
  21. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/cache.py +0 -0
  22. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/canonical_ir.py +0 -0
  23. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/classifier.py +0 -0
  24. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/cli.py +0 -0
  25. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/code_notes_analyzer.py +0 -0
  26. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/confidence_analyzer.py +0 -0
  27. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/context_scorer.py +0 -0
  28. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/context_summarizer.py +0 -0
  29. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/contract_model.py +0 -0
  30. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/contract_pipeline.py +0 -0
  31. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/coverage_parser.py +0 -0
  32. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/dependency_analyzer.py +0 -0
  33. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/__init__.py +0 -0
  34. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/base.py +0 -0
  35. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/csproj_parser.py +0 -0
  36. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/dart.py +0 -0
  37. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/dotnet.py +0 -0
  38. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/elixir.py +0 -0
  39. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/go.py +0 -0
  40. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/heuristic.py +0 -0
  41. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/hybrid.py +0 -0
  42. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/java.py +0 -0
  43. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/jvm_ext.py +0 -0
  44. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/nodejs.py +0 -0
  45. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/parsers.py +0 -0
  46. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/php.py +0 -0
  47. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/project.py +0 -0
  48. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/python.py +0 -0
  49. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/ruby.py +0 -0
  50. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/rust.py +0 -0
  51. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/systems.py +0 -0
  52. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/terraform.py +0 -0
  53. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/detectors/tooling.py +0 -0
  54. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/doc_analyzer.py +0 -0
  55. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/env_analyzer.py +0 -0
  56. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/error_schema.py +0 -0
  57. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/file_classifier.py +0 -0
  58. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/flow_analyzer.py +0 -0
  59. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/git_analyzer.py +0 -0
  60. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/graph_analyzer.py +0 -0
  61. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/license.py +0 -0
  62. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp/__init__.py +0 -0
  63. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  64. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  65. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  66. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  67. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  68. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp/orchestrator.py +0 -0
  69. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp/registry.py +0 -0
  70. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp/runner.py +0 -0
  71. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp/server.py +0 -0
  72. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/mcp_nudge.py +0 -0
  73. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/metrics_analyzer.py +0 -0
  74. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/output_budget.py +0 -0
  75. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/path_filters.py +0 -0
  76. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/pr_comment_renderer.py +0 -0
  77. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/progress.py +0 -0
  78. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/ranking_engine.py +0 -0
  79. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/redactor.py +0 -0
  80. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/repo_classifier.py +0 -0
  81. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/repository_ir.py +0 -0
  82. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/runtime_classifier.py +0 -0
  83. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/scanner.py +0 -0
  84. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/schema.py +0 -0
  85. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/semantic_analyzer.py +0 -0
  86. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/serializer.py +0 -0
  87. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/summarizer.py +0 -0
  88. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/telemetry/__init__.py +0 -0
  89. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/telemetry/config.py +0 -0
  90. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/telemetry/consent.py +0 -0
  91. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/telemetry/events.py +0 -0
  92. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/telemetry/filters.py +0 -0
  93. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/telemetry/transport.py +0 -0
  94. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/tree_utils.py +0 -0
  95. {sourcecode-1.33.23 → sourcecode-1.33.25}/src/sourcecode/workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.33.23
3
+ Version: 1.33.25
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
@@ -39,7 +39,7 @@ Description-Content-Type: text/markdown
39
39
 
40
40
  **Persistent structural context and ultra-fast repeated analysis for AI coding agents.**
41
41
 
42
- ![Version](https://img.shields.io/badge/version-1.33.23-blue)
42
+ ![Version](https://img.shields.io/badge/version-1.33.25-blue)
43
43
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
44
44
 
45
45
  ---
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Persistent structural context and ultra-fast repeated analysis for AI coding agents.**
4
4
 
5
- ![Version](https://img.shields.io/badge/version-1.33.23-blue)
5
+ ![Version](https://img.shields.io/badge/version-1.33.25-blue)
6
6
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
7
7
 
8
8
  ---
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.33.23"
7
+ version = "1.33.25"
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.23"
3
+ __version__ = "1.33.25"
@@ -25,6 +25,31 @@ _DEVELOPMENT_DIRS = frozenset({
25
25
  _DEV_MARKERS = ("rspress", "vite", "storybook", "playground", "dev-server")
26
26
  _PRODUCTION_SCRIPT_REASONS = {"script:start", "script:serve", "script:server"}
27
27
 
28
+ # JVM source trees: directories below these markers are package namespaces,
29
+ # not functional directory roles — "com/example/spaghetti" must not match
30
+ # _AUXILIARY_DIRS just because "example" is a package name component.
31
+ _JVM_SRC_ROOTS = (
32
+ "src/main/java/", "src/test/java/",
33
+ "src/main/kotlin/", "src/test/kotlin/",
34
+ "src/main/scala/", "src/test/scala/",
35
+ "src/integration-test/java/", "src/integrationTest/java/",
36
+ )
37
+
38
+
39
+ def _dir_check_parts(path: str) -> frozenset[str]:
40
+ """Return path segments used for auxiliary/development dir-name matching.
41
+
42
+ For JVM source files the package path (below the source root) is a
43
+ namespace, not a functional directory hierarchy. Truncate there so
44
+ package components like 'example' in com.example.* don't false-match
45
+ _AUXILIARY_DIRS entries.
46
+ """
47
+ for root in _JVM_SRC_ROOTS:
48
+ idx = path.find(root)
49
+ if idx >= 0:
50
+ return frozenset(path[: idx + len(root)].split("/"))
51
+ return frozenset(path.split("/"))
52
+
28
53
 
29
54
  def classify_entry_point(ep: EntryPoint) -> Classification:
30
55
  """Return the operational class for an entry point.
@@ -33,7 +58,7 @@ def classify_entry_point(ep: EntryPoint) -> Classification:
33
58
  and auxiliary path evidence wins over detector-provided production labels.
34
59
  """
35
60
  path = ep.path.replace("\\", "/").lower()
36
- parts = set(path.split("/"))
61
+ parts = _dir_check_parts(path)
37
62
  reason = (ep.reason or "").lower()
38
63
  evidence = (ep.evidence or "").lower()
39
64
  marker_text = f"{path} {reason} {evidence}"
@@ -864,6 +864,10 @@ _SYMPTOM_STOP_WORDS: frozenset[str] = frozenset({
864
864
  "error", "issue", "problem", "bug",
865
865
  "from", "into", "via", "due", "also", "after", "before",
866
866
  "slow", "fast", "new", "old",
867
+ # Diagnostic abbreviations — too ubiquitous in comments/javadoc to be useful
868
+ # as path/content signals (e.g. "npe" matches "NPE" in thousands of comments).
869
+ "npe", "oom", "oob", "iae", "ise", "npe", "cce", "aioobe",
870
+ "exception", "throwable", "stacktrace",
867
871
  })
868
872
 
869
873
  # Repo-scale threshold: above this file count, use stricter injection logic.
@@ -2363,6 +2367,26 @@ class TaskContextBuilder:
2363
2367
  if _is_large_repo and len(relevant_files) > 40:
2364
2368
  relevant_files = relevant_files[:40]
2365
2369
 
2370
+ # Score normalization: prevent all-1.0 saturation when many files
2371
+ # accumulate enough boost to hit the cap. Normalize display scores
2372
+ # relative to max raw signal so the ranked gradient is preserved.
2373
+ _norm_max = max(
2374
+ (_raw_signals.get(rf.path, rf.score) for rf in relevant_files),
2375
+ default=1.0,
2376
+ ) or 1.0
2377
+ if _norm_max > 1.0:
2378
+ relevant_files = [
2379
+ RelevantFile(
2380
+ path=rf.path,
2381
+ role=rf.role,
2382
+ score=round(min(_raw_signals.get(rf.path, rf.score) / _norm_max, 1.0), 3),
2383
+ reason=rf.reason,
2384
+ why=rf.why,
2385
+ tier=rf.tier,
2386
+ )
2387
+ for rf in relevant_files
2388
+ ]
2389
+
2366
2390
  # Synonym note (only when synonyms actually fired)
2367
2391
  if _frontend_kws and _sx_synonyms:
2368
2392
  symptom_note = (
@@ -2491,12 +2515,27 @@ class TaskContextBuilder:
2491
2515
  key=lambda x: -(x["public_method_count"] * (1.5 if x["has_framework_annotations"] else 1.0))
2492
2516
  )
2493
2517
  _top = _java_candidates if all_gaps else _java_candidates[:20]
2518
+ _max_rank = max(
2519
+ (c["public_method_count"] * (1.5 if c["has_framework_annotations"] else 1.0)
2520
+ for c in _java_candidates),
2521
+ default=1.0,
2522
+ ) or 1.0
2494
2523
  test_gaps = [
2495
2524
  {
2496
2525
  "path": c["path"],
2497
2526
  "public_method_count": c["public_method_count"],
2498
2527
  "has_framework_annotations": c["has_framework_annotations"],
2499
2528
  "rank_score": round(c["public_method_count"] * (1.5 if c["has_framework_annotations"] else 1.0), 1),
2529
+ "score": round(min(
2530
+ c["public_method_count"] * (1.5 if c["has_framework_annotations"] else 1.0) / _max_rank,
2531
+ 1.0,
2532
+ ), 3),
2533
+ "reason": (
2534
+ (f"{c['public_method_count']} public method{'s' if c['public_method_count'] != 1 else ''}; "
2535
+ if c["public_method_count"] else "")
2536
+ + ("has Spring/Jakarta framework annotations" if c["has_framework_annotations"]
2537
+ else "no test coverage detected")
2538
+ ).strip("; ") or "untested source file",
2500
2539
  }
2501
2540
  for c in _top
2502
2541
  ]
@@ -88,6 +88,31 @@ _AUXILIARY_DIR_PATTERNS: list[re.Pattern[str]] = [
88
88
  re.compile(r"(?:^|/)stories(?:/|$)"),
89
89
  ]
90
90
 
91
+ # JVM source roots: path components below these are package namespaces, not
92
+ # functional directories. "com/example/foo" must not match the "example"
93
+ # auxiliary-dir pattern just because "example" is a package name component.
94
+ _JVM_SRC_ROOTS: tuple[str, ...] = (
95
+ "src/main/java/", "src/test/java/",
96
+ "src/main/kotlin/", "src/test/kotlin/",
97
+ "src/main/scala/", "src/test/scala/",
98
+ "src/integration-test/java/", "src/integrationTest/java/",
99
+ )
100
+
101
+
102
+ def _jvm_strip_path(path: str) -> str:
103
+ """Return the path segment used for auxiliary-dir pattern matching.
104
+
105
+ For JVM source trees the package path below the source root is a namespace,
106
+ not a functional directory hierarchy. Truncate at the source root so that
107
+ package components like 'example' in com.example.* don't false-match
108
+ _AUXILIARY_DIR_PATTERNS entries.
109
+ """
110
+ for root in _JVM_SRC_ROOTS:
111
+ idx = path.find(root)
112
+ if idx >= 0:
113
+ return path[: idx + len(root)]
114
+ return path
115
+
91
116
  # Test file patterns — scored low, excluded from default contract output
92
117
  _TEST_FILE_PATTERNS: tuple[str, ...] = (
93
118
  "_test.", ".test.", ".spec.", "test_", "conftest", "_spec.",
@@ -221,7 +246,7 @@ class RelevanceScorer:
221
246
  return self._is_auxiliary(path.replace("\\", "/"))
222
247
 
223
248
  def _is_auxiliary(self, norm: str) -> bool:
224
- return any(p.search(norm) for p in _AUXILIARY_DIR_PATTERNS)
249
+ return any(p.search(_jvm_strip_path(norm)) for p in _AUXILIARY_DIR_PATTERNS)
225
250
 
226
251
  def package_role(self, path: str) -> str:
227
252
  """Return the monorepo package role for this path, or empty string."""
@@ -422,7 +422,9 @@ def get_cold_start_context(repo_root: Path) -> dict:
422
422
  if _validation_status == "incomplete_snapshot" and not stale:
423
423
  _status_base = "cold_start_incomplete"
424
424
 
425
+ _compact = ris.compact_summary or {}
425
426
  result: dict = {
427
+ "schema_version": "1.1",
426
428
  "status": _status_base,
427
429
  "repo_id": ris.repo_id,
428
430
  "git_head": ris.git_head,
@@ -433,7 +435,10 @@ def get_cold_start_context(repo_root: Path) -> dict:
433
435
  "cache_source": "RIS",
434
436
  "data_scope": "RIS_BOOTSTRAP",
435
437
  "api_surface_complete": _api_complete,
436
- "summary": ris.compact_summary,
438
+ # Backward-compat alias: old consumers read cold-start.project_type directly.
439
+ # New consumers should use cold-start.summary.project_type.
440
+ "project_type": _compact.get("project_type"),
441
+ "summary": _compact,
437
442
  "entrypoints": ris.structural_map.get("entrypoints", []),
438
443
  "endpoints": endpoints,
439
444
  "hotspots": ris.git_context_snapshot.get("hotspots", []),
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes