sourcecode 1.35.15__tar.gz → 1.35.16__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 (106) hide show
  1. {sourcecode-1.35.15 → sourcecode-1.35.16}/PKG-INFO +4 -3
  2. {sourcecode-1.35.15 → sourcecode-1.35.16}/README.md +2 -2
  3. {sourcecode-1.35.15 → sourcecode-1.35.16}/pyproject.toml +2 -1
  4. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/__init__.py +1 -1
  5. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/ast_extractor.py +1 -1
  6. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/cli.py +1 -1
  7. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/dependency_analyzer.py +1 -1
  8. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/license.py +30 -12
  9. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/telemetry/transport.py +4 -1
  10. {sourcecode-1.35.15 → sourcecode-1.35.16}/.github/workflows/build-windows.yml +0 -0
  11. {sourcecode-1.35.15 → sourcecode-1.35.16}/.gitignore +0 -0
  12. {sourcecode-1.35.15 → sourcecode-1.35.16}/.ruff.toml +0 -0
  13. {sourcecode-1.35.15 → sourcecode-1.35.16}/CHANGELOG.md +0 -0
  14. {sourcecode-1.35.15 → sourcecode-1.35.16}/CONTRIBUTING.md +0 -0
  15. {sourcecode-1.35.15 → sourcecode-1.35.16}/LICENSE +0 -0
  16. {sourcecode-1.35.15 → sourcecode-1.35.16}/SECURITY.md +0 -0
  17. {sourcecode-1.35.15 → sourcecode-1.35.16}/raw +0 -0
  18. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/adaptive_scanner.py +0 -0
  19. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/architecture_analyzer.py +0 -0
  20. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/architecture_summary.py +0 -0
  21. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/cache.py +0 -0
  22. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/canonical_ir.py +0 -0
  23. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/cir_graphs.py +0 -0
  24. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/classifier.py +0 -0
  25. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/code_notes_analyzer.py +0 -0
  26. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/confidence_analyzer.py +0 -0
  27. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/context_scorer.py +0 -0
  28. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/context_summarizer.py +0 -0
  29. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/contract_model.py +0 -0
  30. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/contract_pipeline.py +0 -0
  31. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/coverage_parser.py +0 -0
  32. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/__init__.py +0 -0
  33. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/base.py +0 -0
  34. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/csproj_parser.py +0 -0
  35. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/dart.py +0 -0
  36. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/dotnet.py +0 -0
  37. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/elixir.py +0 -0
  38. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/go.py +0 -0
  39. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/heuristic.py +0 -0
  40. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/hybrid.py +0 -0
  41. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/java.py +0 -0
  42. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/jvm_ext.py +0 -0
  43. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/nodejs.py +0 -0
  44. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/parsers.py +0 -0
  45. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/php.py +0 -0
  46. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/project.py +0 -0
  47. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/python.py +0 -0
  48. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/ruby.py +0 -0
  49. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/rust.py +0 -0
  50. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/systems.py +0 -0
  51. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/terraform.py +0 -0
  52. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/detectors/tooling.py +0 -0
  53. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/doc_analyzer.py +0 -0
  54. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/entrypoint_classifier.py +0 -0
  55. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/env_analyzer.py +0 -0
  56. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/error_schema.py +0 -0
  57. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/explain.py +0 -0
  58. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/file_classifier.py +0 -0
  59. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/flow_analyzer.py +0 -0
  60. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/fqn_utils.py +0 -0
  61. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/git_analyzer.py +0 -0
  62. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/graph_analyzer.py +0 -0
  63. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp/__init__.py +0 -0
  64. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  65. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  66. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  67. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  68. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  69. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp/orchestrator.py +0 -0
  70. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp/registry.py +0 -0
  71. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp/runner.py +0 -0
  72. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp/server.py +0 -0
  73. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/mcp_nudge.py +0 -0
  74. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/metrics_analyzer.py +0 -0
  75. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/output_budget.py +0 -0
  76. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/path_filters.py +0 -0
  77. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/pr_comment_renderer.py +0 -0
  78. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/pr_impact.py +0 -0
  79. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/prepare_context.py +0 -0
  80. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/progress.py +0 -0
  81. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/ranking_engine.py +0 -0
  82. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/redactor.py +0 -0
  83. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/relevance_scorer.py +0 -0
  84. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/repo_classifier.py +0 -0
  85. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/repository_ir.py +0 -0
  86. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/ris.py +0 -0
  87. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/runtime_classifier.py +0 -0
  88. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/scanner.py +0 -0
  89. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/schema.py +0 -0
  90. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/semantic_analyzer.py +0 -0
  91. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/serializer.py +0 -0
  92. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/spring_event_topology.py +0 -0
  93. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/spring_findings.py +0 -0
  94. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/spring_impact.py +0 -0
  95. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/spring_model.py +0 -0
  96. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/spring_security_audit.py +0 -0
  97. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/spring_semantic.py +0 -0
  98. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/spring_tx_analyzer.py +0 -0
  99. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/summarizer.py +0 -0
  100. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/telemetry/__init__.py +0 -0
  101. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/telemetry/config.py +0 -0
  102. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/telemetry/consent.py +0 -0
  103. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/telemetry/events.py +0 -0
  104. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/telemetry/filters.py +0 -0
  105. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/tree_utils.py +0 -0
  106. {sourcecode-1.35.15 → sourcecode-1.35.16}/src/sourcecode/workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.35.15
3
+ Version: 1.35.16
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
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
18
  Classifier: Topic :: Utilities
19
19
  Requires-Python: >=3.9
20
+ Requires-Dist: defusedxml>=0.7
20
21
  Requires-Dist: mcp>=1.0.0
21
22
  Requires-Dist: pathspec>=1.0
22
23
  Requires-Dist: ruamel-yaml>=0.18
@@ -39,7 +40,7 @@ Description-Content-Type: text/markdown
39
40
 
40
41
  **Persistent structural context and ultra-fast repeated analysis for AI coding agents.**
41
42
 
42
- ![Version](https://img.shields.io/badge/version-1.35.15-blue)
43
+ ![Version](https://img.shields.io/badge/version-1.35.16-blue)
43
44
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
44
45
 
45
46
  ---
@@ -113,7 +114,7 @@ pipx install sourcecode
113
114
 
114
115
  ```bash
115
116
  sourcecode version
116
- # sourcecode 1.35.15
117
+ # sourcecode 1.35.16
117
118
  ```
118
119
 
119
120
  ---
@@ -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.35.15-blue)
5
+ ![Version](https://img.shields.io/badge/version-1.35.16-blue)
6
6
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
7
7
 
8
8
  ---
@@ -76,7 +76,7 @@ pipx install sourcecode
76
76
 
77
77
  ```bash
78
78
  sourcecode version
79
- # sourcecode 1.35.15
79
+ # sourcecode 1.35.16
80
80
  ```
81
81
 
82
82
  ---
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.35.15"
7
+ version = "1.35.16"
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"
@@ -31,6 +31,7 @@ dependencies = [
31
31
  "ruamel.yaml>=0.18",
32
32
  "tomli>=2.0; python_version < '3.11'",
33
33
  "mcp>=1.0.0",
34
+ "defusedxml>=0.7",
34
35
  ]
35
36
 
36
37
  [project.scripts]
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Deterministic codebase context maps for AI coding agents."""
2
2
 
3
- __version__ = "1.35.15"
3
+ __version__ = "1.35.16"
@@ -1196,7 +1196,7 @@ def _detect_role(path: str, contract: FileContract) -> str:
1196
1196
  def _extract_mybatis_xml(rel_path: str, source: str) -> FileContract:
1197
1197
  """Extract namespace and SQL operations from a MyBatis *Mapper.xml file."""
1198
1198
  import re as _re
1199
- from xml.etree import ElementTree
1199
+ import defusedxml.ElementTree as ElementTree # type: ignore[import]
1200
1200
 
1201
1201
  _NS_STRIP = _re.compile(r"\{[^}]+\}")
1202
1202
  _SQL_OPS = frozenset({"select", "insert", "update", "delete"})
@@ -4892,7 +4892,7 @@ def mcp_serve() -> None:
4892
4892
  except KeyboardInterrupt:
4893
4893
  log.info("sourcecode-mcp stopped")
4894
4894
  except Exception as exc:
4895
- log.critical("sourcecode-mcp fatal error: %s", exc, exc_info=True)
4895
+ log.critical("sourcecode-mcp fatal error: %s: %s", type(exc).__name__, exc)
4896
4896
  raise typer.Exit(code=1)
4897
4897
 
4898
4898
 
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import re
4
- import xml.etree.ElementTree as ET
4
+ import defusedxml.ElementTree as ET # type: ignore[import]
5
5
  from collections.abc import Iterable
6
6
  from dataclasses import replace
7
7
  from pathlib import Path
@@ -17,6 +17,7 @@ from __future__ import annotations
17
17
 
18
18
  import json
19
19
  import os
20
+ import re
20
21
  import sys
21
22
  from datetime import datetime, timezone
22
23
  from pathlib import Path
@@ -25,18 +26,23 @@ from typing import Optional
25
26
  # ---------------------------------------------------------------------------
26
27
  # Supabase endpoint config — hardcoded for production; override via env for dev
27
28
  # ---------------------------------------------------------------------------
28
- _SUPABASE_URL: str = os.environ.get(
29
- "SOURCECODE_SUPABASE_URL",
30
- "https://qkndlmyekvujjdgthtmz.supabase.co",
31
- )
29
+ _DEFAULT_SUPABASE_URL: str = "https://qkndlmyekvujjdgthtmz.supabase.co"
30
+ _SUPABASE_URL: str = os.environ.get("SOURCECODE_SUPABASE_URL", _DEFAULT_SUPABASE_URL)
32
31
  _SUPABASE_ANON_KEY: str = os.environ.get(
33
32
  "SOURCECODE_SUPABASE_ANON_KEY",
34
33
  "", # Set SOURCECODE_SUPABASE_ANON_KEY to your project anon key
35
34
  )
35
+ if _SUPABASE_URL != _DEFAULT_SUPABASE_URL:
36
+ sys.stderr.write(
37
+ f"[sourcecode] WARNING: SOURCECODE_SUPABASE_URL overridden to {_SUPABASE_URL!r}."
38
+ " License requests will be sent to this server.\n"
39
+ )
40
+ sys.stderr.flush()
36
41
 
37
42
  _LICENSE_DIR: Path = Path.home() / ".sourcecode"
38
43
  _LICENSE_FILE: Path = _LICENSE_DIR / "license.json"
39
44
  _CACHE_TTL_SECONDS: int = 86400 # 24 hours
45
+ _LICENSE_KEY_RE = re.compile(r"^[A-Za-z0-9_\-]{1,200}$")
40
46
 
41
47
  # ---------------------------------------------------------------------------
42
48
  # Per-feature descriptions for upgrade UX
@@ -92,6 +98,21 @@ _license_data: Optional[dict] = None
92
98
  is_pro: bool = False
93
99
 
94
100
 
101
+ def _write_license_file(data: dict) -> None:
102
+ """Atomically write license data via tmp file + rename."""
103
+ payload = json.dumps(data, indent=2, ensure_ascii=False).encode("utf-8")
104
+ tmp = _LICENSE_FILE.with_suffix(".tmp")
105
+ try:
106
+ tmp.write_bytes(payload)
107
+ tmp.replace(_LICENSE_FILE)
108
+ except Exception:
109
+ try:
110
+ tmp.unlink(missing_ok=True)
111
+ except Exception:
112
+ pass
113
+ raise
114
+
115
+
95
116
  def _load_license_file() -> Optional[dict]:
96
117
  """Read ~/.sourcecode/license.json. Returns parsed dict or None."""
97
118
  try:
@@ -173,10 +194,7 @@ def _maybe_revalidate() -> None:
173
194
  _license_data["validated_at"] = datetime.now(timezone.utc).isoformat()
174
195
  is_pro = _license_data.get("plan") == "pro"
175
196
  try:
176
- _LICENSE_FILE.write_text(
177
- json.dumps(_license_data, indent=2, ensure_ascii=False),
178
- encoding="utf-8",
179
- )
197
+ _write_license_file(_license_data)
180
198
  except Exception:
181
199
  pass
182
200
 
@@ -284,6 +302,9 @@ def activate_license(license_key: str) -> None:
284
302
  Outputs JSON to stdout; exits 0 on success, 1 on any failure.
285
303
  Never raises — all error paths emit JSON and call sys.exit(1).
286
304
  """
305
+ if not _LICENSE_KEY_RE.match(license_key):
306
+ _fail("invalid_license", "License key format is invalid.")
307
+
287
308
  if not _SUPABASE_ANON_KEY:
288
309
  _fail("configuration_error", "SOURCECODE_SUPABASE_ANON_KEY not set. Contact support.")
289
310
 
@@ -308,10 +329,7 @@ def activate_license(license_key: str) -> None:
308
329
  "activated_at": now,
309
330
  "validated_at": now,
310
331
  }
311
- _LICENSE_FILE.write_text(
312
- json.dumps(data, indent=2, ensure_ascii=False),
313
- encoding="utf-8",
314
- )
332
+ _write_license_file(data)
315
333
 
316
334
  output = {"status": "activated", "plan": "pro", "features": data["features"]}
317
335
  sys.stdout.write(json.dumps(output, ensure_ascii=False) + "\n")
@@ -20,7 +20,10 @@ _TIMEOUT_S = 3
20
20
 
21
21
 
22
22
  def _endpoint() -> str:
23
- return os.environ.get("SOURCECODE_TELEMETRY_ENDPOINT", _DEFAULT_ENDPOINT)
23
+ override = os.environ.get("SOURCECODE_TELEMETRY_ENDPOINT")
24
+ if override and override.startswith("https://"):
25
+ return override
26
+ return _DEFAULT_ENDPOINT
24
27
 
25
28
 
26
29
  def _send_blocking(payload: dict[str, Any]) -> None:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes