sourcecode 1.32.4__tar.gz → 1.32.6__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 (93) hide show
  1. {sourcecode-1.32.4 → sourcecode-1.32.6}/PKG-INFO +1 -1
  2. {sourcecode-1.32.4 → sourcecode-1.32.6}/pyproject.toml +1 -1
  3. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/__init__.py +1 -1
  4. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/cache.py +10 -1
  5. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/cli.py +105 -3
  6. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/license.py +1 -0
  7. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/ris.py +7 -2
  8. {sourcecode-1.32.4 → sourcecode-1.32.6}/.github/workflows/build-windows.yml +0 -0
  9. {sourcecode-1.32.4 → sourcecode-1.32.6}/.gitignore +0 -0
  10. {sourcecode-1.32.4 → sourcecode-1.32.6}/.ruff.toml +0 -0
  11. {sourcecode-1.32.4 → sourcecode-1.32.6}/CHANGELOG.md +0 -0
  12. {sourcecode-1.32.4 → sourcecode-1.32.6}/CONTRIBUTING.md +0 -0
  13. {sourcecode-1.32.4 → sourcecode-1.32.6}/LICENSE +0 -0
  14. {sourcecode-1.32.4 → sourcecode-1.32.6}/README.md +0 -0
  15. {sourcecode-1.32.4 → sourcecode-1.32.6}/SECURITY.md +0 -0
  16. {sourcecode-1.32.4 → sourcecode-1.32.6}/raw +0 -0
  17. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/adaptive_scanner.py +0 -0
  18. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/architecture_analyzer.py +0 -0
  19. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/architecture_summary.py +0 -0
  20. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/ast_extractor.py +0 -0
  21. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/cache.tmp_new +0 -0
  22. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/canonical_ir.py +0 -0
  23. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/classifier.py +0 -0
  24. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/code_notes_analyzer.py +0 -0
  25. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/confidence_analyzer.py +0 -0
  26. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/context_scorer.py +0 -0
  27. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/context_summarizer.py +0 -0
  28. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/contract_model.py +0 -0
  29. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/contract_pipeline.py +0 -0
  30. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/coverage_parser.py +0 -0
  31. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/dependency_analyzer.py +0 -0
  32. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/__init__.py +0 -0
  33. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/base.py +0 -0
  34. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/csproj_parser.py +0 -0
  35. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/dart.py +0 -0
  36. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/dotnet.py +0 -0
  37. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/elixir.py +0 -0
  38. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/go.py +0 -0
  39. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/heuristic.py +0 -0
  40. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/hybrid.py +0 -0
  41. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/java.py +0 -0
  42. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/jvm_ext.py +0 -0
  43. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/nodejs.py +0 -0
  44. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/parsers.py +0 -0
  45. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/php.py +0 -0
  46. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/project.py +0 -0
  47. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/python.py +0 -0
  48. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/ruby.py +0 -0
  49. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/rust.py +0 -0
  50. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/systems.py +0 -0
  51. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/terraform.py +0 -0
  52. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/detectors/tooling.py +0 -0
  53. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/doc_analyzer.py +0 -0
  54. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/entrypoint_classifier.py +0 -0
  55. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/env_analyzer.py +0 -0
  56. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/file_classifier.py +0 -0
  57. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/flow_analyzer.py +0 -0
  58. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/git_analyzer.py +0 -0
  59. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/graph_analyzer.py +0 -0
  60. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/mcp/__init__.py +0 -0
  61. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  62. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  63. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  64. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  65. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  66. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/mcp/runner.py +0 -0
  67. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/mcp/server.py +0 -0
  68. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/mcp_nudge.py +0 -0
  69. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/metrics_analyzer.py +0 -0
  70. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/output_budget.py +0 -0
  71. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/path_filters.py +0 -0
  72. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/pr_comment_renderer.py +0 -0
  73. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/prepare_context.py +0 -0
  74. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/progress.py +0 -0
  75. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/ranking_engine.py +0 -0
  76. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/redactor.py +0 -0
  77. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/relevance_scorer.py +0 -0
  78. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/repo_classifier.py +0 -0
  79. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/repository_ir.py +0 -0
  80. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/runtime_classifier.py +0 -0
  81. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/scanner.py +0 -0
  82. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/schema.py +0 -0
  83. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/semantic_analyzer.py +0 -0
  84. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/serializer.py +0 -0
  85. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/summarizer.py +0 -0
  86. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/telemetry/__init__.py +0 -0
  87. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/telemetry/config.py +0 -0
  88. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/telemetry/consent.py +0 -0
  89. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/telemetry/events.py +0 -0
  90. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/telemetry/filters.py +0 -0
  91. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/telemetry/transport.py +0 -0
  92. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/tree_utils.py +0 -0
  93. {sourcecode-1.32.4 → sourcecode-1.32.6}/src/sourcecode/workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.32.4
3
+ Version: 1.32.6
4
4
  Summary: Deterministic codebase context 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.32.4"
7
+ version = "1.32.6"
8
8
  description = "Deterministic codebase context 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.32.4"
3
+ __version__ = "1.32.6"
@@ -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.write_bytes(gzip.compress(raw, compresslevel=6))
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
 
@@ -382,6 +384,18 @@ def _get_command_with_preprocessing(typer_instance: Any) -> Any:
382
384
  # Refresh help text at invocation time so it reflects current license state.
383
385
  cmd.help = _build_help_text()
384
386
 
387
+ # Add [Pro] badge to Pro-gated option help strings for free-tier users.
388
+ try:
389
+ from sourcecode.license import is_pro as _lp_is_pro
390
+ except Exception:
391
+ _lp_is_pro = False
392
+ if not _lp_is_pro:
393
+ _PRO_OPTS = {"full"}
394
+ for _param in cmd.params:
395
+ if getattr(_param, "name", None) in _PRO_OPTS and getattr(_param, "help", None):
396
+ if "[Pro]" not in _param.help:
397
+ _param.help = _param.help + " [dim][Pro][/dim]"
398
+
385
399
  _orig_cmd_main = cmd.main
386
400
 
387
401
  def _cmd_main(args: Optional[list[str]] = None, **kwargs: Any) -> Any:
@@ -412,6 +426,9 @@ app.add_typer(telemetry_app, name="telemetry")
412
426
  mcp_app = typer.Typer(help="MCP integration: setup, status, serve, remove.", rich_markup_mode="rich")
413
427
  app.add_typer(mcp_app, name="mcp")
414
428
 
429
+ cache_app = typer.Typer(help="Cache inspection and management.", rich_markup_mode="rich")
430
+ app.add_typer(cache_app, name="cache")
431
+
415
432
 
416
433
  def _maybe_ask_consent() -> None:
417
434
  """Show first-run consent prompt once, on interactive TTYs only."""
@@ -1064,7 +1081,6 @@ def main(
1064
1081
  # Only cache when target IS the git repo root (not a subdir of one),
1065
1082
  # to avoid polluting sub-project directories used in tests.
1066
1083
  if _git_sha and (target / ".git").exists():
1067
- from sourcecode import __version__ as _sc_version
1068
1084
  _excl_key = (
1069
1085
  ",".join(sorted(e.strip() for e in exclude.split(",") if e.strip()))
1070
1086
  if exclude else ""
@@ -1072,8 +1088,10 @@ def main(
1072
1088
 
1073
1089
  # ── Core (analysis) flags: affect which analyzers run + scan config ──
1074
1090
  # Use effective_depth (not raw depth) so Java auto-adjustment is captured.
1091
+ # acv = ANALYZER_CACHE_VERSION — bumped only when analysis logic/schema
1092
+ # changes, NOT on every package release. Prevents patch-bump cache wipes.
1075
1093
  _core_flags_str = (
1076
- f"v={_sc_version},"
1094
+ f"acv={_cache_mod.ANALYZER_CACHE_VERSION},"
1077
1095
  f"dep={dependencies},gm={graph_modules},"
1078
1096
  f"docs={docs},fm={full_metrics},sem={semantics},"
1079
1097
  f"arch={architecture},gc={git_context},em={env_map},"
@@ -1436,12 +1454,23 @@ def main(
1436
1454
  if dependency_analyzer is not None
1437
1455
  else None
1438
1456
  )
1457
+ # Free-tier node cap: limit graph size to 10 nodes unless Pro.
1458
+ _effective_max_nodes = max_nodes
1459
+ try:
1460
+ from sourcecode.license import is_pro as _lp_is_pro_gm
1461
+ except Exception:
1462
+ _lp_is_pro_gm = False
1463
+ _FREE_NODE_CAP = 10
1464
+ if not _lp_is_pro_gm and graph_analyzer is not None:
1465
+ if _effective_max_nodes is None or _effective_max_nodes > _FREE_NODE_CAP:
1466
+ _effective_max_nodes = _FREE_NODE_CAP
1467
+
1439
1468
  module_graph = (
1440
1469
  graph_analyzer.merge_graphs(
1441
1470
  module_graphs,
1442
1471
  detail=graph_detail_typed,
1443
1472
  edge_kinds=parsed_graph_edges,
1444
- max_nodes=max_nodes,
1473
+ max_nodes=_effective_max_nodes,
1445
1474
  entry_points=entry_points,
1446
1475
  )
1447
1476
  if graph_analyzer is not None
@@ -1561,6 +1590,15 @@ def main(
1561
1590
  semantic_summary=sem_sum,
1562
1591
  )
1563
1592
 
1593
+ # Free-tier node cap for --semantics: limit semantic_symbols to 10 unless Pro.
1594
+ if semantic_analyzer is not None and sm.semantic_symbols:
1595
+ try:
1596
+ from sourcecode.license import is_pro as _lp_is_pro_sem
1597
+ except Exception:
1598
+ _lp_is_pro_sem = False
1599
+ if not _lp_is_pro_sem and len(sm.semantic_symbols) > _FREE_NODE_CAP:
1600
+ sm = replace(sm, semantic_symbols=sm.semantic_symbols[:_FREE_NODE_CAP])
1601
+
1564
1602
  # Runtime architecture — classify workspace packages for structural summaries
1565
1603
  if workspace_analysis.workspaces:
1566
1604
  from sourcecode.runtime_classifier import RuntimeClassifier
@@ -4124,6 +4162,70 @@ def mcp_remove(
4124
4162
  typer.echo(" Re-add: sourcecode mcp init")
4125
4163
 
4126
4164
 
4165
+ # ── Cache subcommands ─────────────────────────────────────────────────────────
4166
+
4167
+
4168
+ @cache_app.command("status")
4169
+ def cache_status_cmd(
4170
+ path: Path = typer.Argument(Path("."), help="Repository path (default: current directory)"),
4171
+ json_output: bool = typer.Option(False, "--json", help="Output as JSON."),
4172
+ ) -> None:
4173
+ """Show cache statistics for a repository."""
4174
+ from sourcecode import cache as _cm
4175
+ target = Path(path).resolve()
4176
+ stats = _cm.status(target)
4177
+ if json_output:
4178
+ import json as _j
4179
+ typer.echo(_j.dumps(stats, indent=2, ensure_ascii=False))
4180
+ else:
4181
+ typer.echo(f"Cache dir: {stats['cache_dir']}")
4182
+ typer.echo(f"Cores: {stats['cores']}")
4183
+ typer.echo(f"Snapshots: {stats['snapshots']}")
4184
+ typer.echo(f"Views: {stats['views']}")
4185
+ typer.echo(f"CAS blobs: {stats['cas_blobs']}")
4186
+ typer.echo(f"Total size: {stats['total_size_mb']} MB")
4187
+
4188
+
4189
+ @cache_app.command("clear")
4190
+ def cache_clear_cmd(
4191
+ path: Path = typer.Argument(Path("."), help="Repository path (default: current directory)"),
4192
+ yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt."),
4193
+ ) -> None:
4194
+ """Delete all cached snapshots for a repository."""
4195
+ from sourcecode import cache as _cm
4196
+ target = Path(path).resolve()
4197
+ if not yes:
4198
+ typer.confirm(f"Delete all cache files for {target}?", abort=True)
4199
+ removed = _cm.clear(target)
4200
+ typer.echo(f"Removed {removed} file(s).")
4201
+
4202
+
4203
+ @cache_app.command("warm")
4204
+ def cache_warm_cmd(
4205
+ path: Path = typer.Argument(Path("."), help="Repository path to warm (default: current directory)"),
4206
+ compact: bool = typer.Option(True, "--compact/--no-compact", help="Warm compact view (default: on)."),
4207
+ agent: bool = typer.Option(False, "--agent", help="Also warm agent view."),
4208
+ ) -> None:
4209
+ """Pre-populate the cache by running a fresh analysis."""
4210
+ import subprocess as _sub
4211
+ import sys as _sys
4212
+ target = Path(path).resolve()
4213
+ typer.echo(f"Warming cache for {target} …", err=True)
4214
+ cmd = [_sys.executable, "-m", "sourcecode", str(target)]
4215
+ if compact:
4216
+ cmd.append("--compact")
4217
+ if agent:
4218
+ cmd.append("--agent")
4219
+ result = _sub.run(cmd, capture_output=True, text=True)
4220
+ if result.returncode == 0:
4221
+ typer.echo("Cache warmed.", err=True)
4222
+ else:
4223
+ typer.echo(f"Warm failed (exit {result.returncode}).", err=True)
4224
+ if result.stderr:
4225
+ typer.echo(result.stderr.strip(), err=True)
4226
+ raise typer.Exit(code=result.returncode)
4227
+
4228
+
4127
4229
  # ── Entry point ───────────────────────────────────────────────────────────────
4128
4230
 
4129
4231
  def main_entry() -> None:
@@ -248,6 +248,7 @@ def require_feature(feature_name: str) -> None:
248
248
  f"'{display}' requires a Pro license. "
249
249
  "Run: sourcecode activate <license_key>"
250
250
  ),
251
+ "upgrade_hint": "sourcecode activate <license_key>",
251
252
  }
252
253
  sys.stdout.write(json.dumps(payload, ensure_ascii=False) + "\n")
253
254
  sys.stdout.flush()
@@ -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