sourcecode 1.32.4__tar.gz → 1.32.5__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.
- {sourcecode-1.32.4 → sourcecode-1.32.5}/PKG-INFO +1 -1
- {sourcecode-1.32.4 → sourcecode-1.32.5}/pyproject.toml +1 -1
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/cache.py +10 -1
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/cli.py +72 -2
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/ris.py +7 -2
- {sourcecode-1.32.4 → sourcecode-1.32.5}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/.gitignore +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/.ruff.toml +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/CHANGELOG.md +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/CONTRIBUTING.md +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/LICENSE +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/README.md +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/SECURITY.md +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/raw +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/cache.tmp_new +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/flow_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/license.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/repository_ir.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/serializer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.32.4 → sourcecode-1.32.5}/src/sourcecode/workspace.py +0 -0
|
@@ -72,6 +72,11 @@ SCHEMA_VERSION: str = "2"
|
|
|
72
72
|
#: Bump to invalidate all L1 core caches (independent of snapshot version).
|
|
73
73
|
CORE_SCHEMA_VERSION: str = "1"
|
|
74
74
|
|
|
75
|
+
#: Bump when analysis logic or output schema changes — NOT on every package release.
|
|
76
|
+
#: This is the stable part of the L1 core cache key. Package version bumps (patch,
|
|
77
|
+
#: minor) must NOT bump this value unless the cached data format actually changed.
|
|
78
|
+
ANALYZER_CACHE_VERSION: str = "1"
|
|
79
|
+
|
|
75
80
|
#: Fields eligible for CAS deduplication (applied to top-level JSON dict keys).
|
|
76
81
|
_CAS_FIELDS: frozenset[str] = frozenset([
|
|
77
82
|
"file_paths",
|
|
@@ -511,7 +516,7 @@ def _cas_store_blob(cache_d: Path, serialised: str) -> str:
|
|
|
511
516
|
path = _cas_path(cache_d, blob_hash)
|
|
512
517
|
if not path.exists():
|
|
513
518
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
514
|
-
path
|
|
519
|
+
_atomic_write(path, gzip.compress(raw, compresslevel=6))
|
|
515
520
|
return blob_hash
|
|
516
521
|
|
|
517
522
|
|
|
@@ -642,7 +647,11 @@ def _gc(cache_d: Path) -> None:
|
|
|
642
647
|
# ── Pass 3: total size cap ──────────────────────────────────────────
|
|
643
648
|
if max_size_bytes > 0:
|
|
644
649
|
size_candidates = [p for p in surviving if p.exists()]
|
|
650
|
+
# Include CAS blobs in the size budget calculation
|
|
651
|
+
cas_d_sz = _cas_dir(cache_d)
|
|
652
|
+
cas_files = list(cas_d_sz.glob("*.gz")) if cas_d_sz.exists() else []
|
|
645
653
|
total = sum(p.stat().st_size for p in size_candidates if not p.name.startswith("view-"))
|
|
654
|
+
total += sum(p.stat().st_size for p in cas_files if p.exists())
|
|
646
655
|
if total > max_size_bytes:
|
|
647
656
|
# Sort oldest-first; evict core+snapshot files until under budget
|
|
648
657
|
size_candidates.sort(key=lambda p: p.stat().st_mtime)
|
|
@@ -208,6 +208,8 @@ _SUBCOMMANDS: frozenset[str] = frozenset(
|
|
|
208
208
|
"onboard", "modernize", "fix-bug", "review-pr",
|
|
209
209
|
# License
|
|
210
210
|
"activate",
|
|
211
|
+
# Cache observability
|
|
212
|
+
"cache",
|
|
211
213
|
}
|
|
212
214
|
)
|
|
213
215
|
|
|
@@ -412,6 +414,9 @@ app.add_typer(telemetry_app, name="telemetry")
|
|
|
412
414
|
mcp_app = typer.Typer(help="MCP integration: setup, status, serve, remove.", rich_markup_mode="rich")
|
|
413
415
|
app.add_typer(mcp_app, name="mcp")
|
|
414
416
|
|
|
417
|
+
cache_app = typer.Typer(help="Cache inspection and management.", rich_markup_mode="rich")
|
|
418
|
+
app.add_typer(cache_app, name="cache")
|
|
419
|
+
|
|
415
420
|
|
|
416
421
|
def _maybe_ask_consent() -> None:
|
|
417
422
|
"""Show first-run consent prompt once, on interactive TTYs only."""
|
|
@@ -1064,7 +1069,6 @@ def main(
|
|
|
1064
1069
|
# Only cache when target IS the git repo root (not a subdir of one),
|
|
1065
1070
|
# to avoid polluting sub-project directories used in tests.
|
|
1066
1071
|
if _git_sha and (target / ".git").exists():
|
|
1067
|
-
from sourcecode import __version__ as _sc_version
|
|
1068
1072
|
_excl_key = (
|
|
1069
1073
|
",".join(sorted(e.strip() for e in exclude.split(",") if e.strip()))
|
|
1070
1074
|
if exclude else ""
|
|
@@ -1072,8 +1076,10 @@ def main(
|
|
|
1072
1076
|
|
|
1073
1077
|
# ── Core (analysis) flags: affect which analyzers run + scan config ──
|
|
1074
1078
|
# Use effective_depth (not raw depth) so Java auto-adjustment is captured.
|
|
1079
|
+
# acv = ANALYZER_CACHE_VERSION — bumped only when analysis logic/schema
|
|
1080
|
+
# changes, NOT on every package release. Prevents patch-bump cache wipes.
|
|
1075
1081
|
_core_flags_str = (
|
|
1076
|
-
f"
|
|
1082
|
+
f"acv={_cache_mod.ANALYZER_CACHE_VERSION},"
|
|
1077
1083
|
f"dep={dependencies},gm={graph_modules},"
|
|
1078
1084
|
f"docs={docs},fm={full_metrics},sem={semantics},"
|
|
1079
1085
|
f"arch={architecture},gc={git_context},em={env_map},"
|
|
@@ -4124,6 +4130,70 @@ def mcp_remove(
|
|
|
4124
4130
|
typer.echo(" Re-add: sourcecode mcp init")
|
|
4125
4131
|
|
|
4126
4132
|
|
|
4133
|
+
# ── Cache subcommands ─────────────────────────────────────────────────────────
|
|
4134
|
+
|
|
4135
|
+
|
|
4136
|
+
@cache_app.command("status")
|
|
4137
|
+
def cache_status_cmd(
|
|
4138
|
+
path: Path = typer.Argument(Path("."), help="Repository path (default: current directory)"),
|
|
4139
|
+
json_output: bool = typer.Option(False, "--json", help="Output as JSON."),
|
|
4140
|
+
) -> None:
|
|
4141
|
+
"""Show cache statistics for a repository."""
|
|
4142
|
+
from sourcecode import cache as _cm
|
|
4143
|
+
target = Path(path).resolve()
|
|
4144
|
+
stats = _cm.status(target)
|
|
4145
|
+
if json_output:
|
|
4146
|
+
import json as _j
|
|
4147
|
+
typer.echo(_j.dumps(stats, indent=2, ensure_ascii=False))
|
|
4148
|
+
else:
|
|
4149
|
+
typer.echo(f"Cache dir: {stats['cache_dir']}")
|
|
4150
|
+
typer.echo(f"Cores: {stats['cores']}")
|
|
4151
|
+
typer.echo(f"Snapshots: {stats['snapshots']}")
|
|
4152
|
+
typer.echo(f"Views: {stats['views']}")
|
|
4153
|
+
typer.echo(f"CAS blobs: {stats['cas_blobs']}")
|
|
4154
|
+
typer.echo(f"Total size: {stats['total_size_mb']} MB")
|
|
4155
|
+
|
|
4156
|
+
|
|
4157
|
+
@cache_app.command("clear")
|
|
4158
|
+
def cache_clear_cmd(
|
|
4159
|
+
path: Path = typer.Argument(Path("."), help="Repository path (default: current directory)"),
|
|
4160
|
+
yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt."),
|
|
4161
|
+
) -> None:
|
|
4162
|
+
"""Delete all cached snapshots for a repository."""
|
|
4163
|
+
from sourcecode import cache as _cm
|
|
4164
|
+
target = Path(path).resolve()
|
|
4165
|
+
if not yes:
|
|
4166
|
+
typer.confirm(f"Delete all cache files for {target}?", abort=True)
|
|
4167
|
+
removed = _cm.clear(target)
|
|
4168
|
+
typer.echo(f"Removed {removed} file(s).")
|
|
4169
|
+
|
|
4170
|
+
|
|
4171
|
+
@cache_app.command("warm")
|
|
4172
|
+
def cache_warm_cmd(
|
|
4173
|
+
path: Path = typer.Argument(Path("."), help="Repository path to warm (default: current directory)"),
|
|
4174
|
+
compact: bool = typer.Option(True, "--compact/--no-compact", help="Warm compact view (default: on)."),
|
|
4175
|
+
agent: bool = typer.Option(False, "--agent", help="Also warm agent view."),
|
|
4176
|
+
) -> None:
|
|
4177
|
+
"""Pre-populate the cache by running a fresh analysis."""
|
|
4178
|
+
import subprocess as _sub
|
|
4179
|
+
import sys as _sys
|
|
4180
|
+
target = Path(path).resolve()
|
|
4181
|
+
typer.echo(f"Warming cache for {target} …", err=True)
|
|
4182
|
+
cmd = [_sys.executable, "-m", "sourcecode", str(target)]
|
|
4183
|
+
if compact:
|
|
4184
|
+
cmd.append("--compact")
|
|
4185
|
+
if agent:
|
|
4186
|
+
cmd.append("--agent")
|
|
4187
|
+
result = _sub.run(cmd, capture_output=True, text=True)
|
|
4188
|
+
if result.returncode == 0:
|
|
4189
|
+
typer.echo("Cache warmed.", err=True)
|
|
4190
|
+
else:
|
|
4191
|
+
typer.echo(f"Warm failed (exit {result.returncode}).", err=True)
|
|
4192
|
+
if result.stderr:
|
|
4193
|
+
typer.echo(result.stderr.strip(), err=True)
|
|
4194
|
+
raise typer.Exit(code=result.returncode)
|
|
4195
|
+
|
|
4196
|
+
|
|
4127
4197
|
# ── Entry point ───────────────────────────────────────────────────────────────
|
|
4128
4198
|
|
|
4129
4199
|
def main_entry() -> None:
|
|
@@ -329,10 +329,15 @@ def update_ris_api_surface(repo_root: Path, endpoints_data: dict) -> None:
|
|
|
329
329
|
# ---------------------------------------------------------------------------
|
|
330
330
|
|
|
331
331
|
def _current_git_head(repo_root: Path) -> str:
|
|
332
|
-
"""Return current HEAD SHA. Returns '' on any error or non-git directory.
|
|
332
|
+
"""Return current HEAD short SHA. Returns '' on any error or non-git directory.
|
|
333
|
+
|
|
334
|
+
Uses --short to match the format stored in the RIS and used by cli.py
|
|
335
|
+
cache key computation — both sides must use the same format or staleness
|
|
336
|
+
checks will always return True.
|
|
337
|
+
"""
|
|
333
338
|
try:
|
|
334
339
|
result = subprocess.run(
|
|
335
|
-
["git", "-C", str(repo_root), "rev-parse", "HEAD"],
|
|
340
|
+
["git", "-C", str(repo_root), "rev-parse", "--short", "HEAD"],
|
|
336
341
|
capture_output=True,
|
|
337
342
|
text=True,
|
|
338
343
|
timeout=2,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|