sourcecode 1.35.15__py3-none-any.whl → 1.35.16__py3-none-any.whl

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/__init__.py CHANGED
@@ -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"})
sourcecode/cli.py CHANGED
@@ -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
sourcecode/license.py CHANGED
@@ -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:
@@ -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
  ---
@@ -1,13 +1,13 @@
1
- sourcecode/__init__.py,sha256=cfSxdJ1Ut5rv-mW6fk0pRREJG25MhsYUleGDv8xHWRE,104
1
+ sourcecode/__init__.py,sha256=jc7t99MAOVoZuqPXgeqrR2Amq4B-LnZtcO_-sTvoMSo,104
2
2
  sourcecode/adaptive_scanner.py,sha256=XffluXKzJUXrMtjEiAOnSNPZnztdIcts17T9ouHeID0,10521
3
3
  sourcecode/architecture_analyzer.py,sha256=qh749a7ykPtGmQI1MR9y6j8TtL_jBdVYFx9YRsLqOMw,44121
4
4
  sourcecode/architecture_summary.py,sha256=z34_6v7cSwy98cof2UVciGho7SCrZ93tiqMmq5WNzRQ,20405
5
- sourcecode/ast_extractor.py,sha256=_btmeOJIe3t-NicF94D5ZAesa2YIJ0_QNExGnbHxGFE,50578
5
+ sourcecode/ast_extractor.py,sha256=sa6CmLpn-k5G3_Hzxn8hAlZ5-TS-EVzXDD0Gvxd2jzs,50613
6
6
  sourcecode/cache.py,sha256=wAyPrXN5DqiGivnMpeEuun2xHDKfBer2_oBsh6kj_vc,30447
7
7
  sourcecode/canonical_ir.py,sha256=uwpwCnJxMh_eiIVg4cOLv7-aZthvmDFcG4azCOycLkw,24281
8
8
  sourcecode/cir_graphs.py,sha256=rZi8JV4ZrAa2WSCeyNa4JIEKQ_yZzDZTsrvVz2KfuKA,8919
9
9
  sourcecode/classifier.py,sha256=2lYoSH3vOTkXZYPU7Go2WIet1-IuNzTWVhc-ULnXtgw,8024
10
- sourcecode/cli.py,sha256=HgpX5PJ4zoMxVNWt3ZZ5W1ViVGfIxKk4tOQEb6u-iyU,224559
10
+ sourcecode/cli.py,sha256=uQXXwKp1qnviXG-Qgnl34_5ioPeKPuXLDh7IXXZ3aaA,224568
11
11
  sourcecode/code_notes_analyzer.py,sha256=EJemNCNc9Dn-1RZYu-aNbK0ELzmsyC4s6FdHi3XyNEI,9392
12
12
  sourcecode/confidence_analyzer.py,sha256=_jckZSxksV-OU38vbkxfVNBnWCtlCq8Vwfg23x1uspA,19054
13
13
  sourcecode/context_scorer.py,sha256=QpChSpsmaAYz91rXA4Ue5xzQmNz_ZboZN09YOHScq1U,14679
@@ -15,7 +15,7 @@ sourcecode/context_summarizer.py,sha256=zlbm8ytdvJToohU108-dwBmEl52xl0gXpf6PZBOW
15
15
  sourcecode/contract_model.py,sha256=nRxJKPMs1VHwFTa8AVXhGmaLjti3Lr2sjHDpWgv1bfE,3917
16
16
  sourcecode/contract_pipeline.py,sha256=gvTdDniedm_mjq4vaHqnBY2UkQ0s00gtXqzTLILNXHc,28719
17
17
  sourcecode/coverage_parser.py,sha256=q0LeZJaX1bnntLu-ImksdBsMlpsVmk_iUfSaB4eaJGo,19702
18
- sourcecode/dependency_analyzer.py,sha256=Hh4I9B1_0mHNnUXYhZeLIHd-B2fYu7kt9x1abG7VVO0,56285
18
+ sourcecode/dependency_analyzer.py,sha256=5yUBN_Z75RWmBIbsfnMasPSUn-4IaLipt0A3b3LNVfc,56310
19
19
  sourcecode/doc_analyzer.py,sha256=05bjTUbDbmnbajD_cgRnACzS8T7xxBKVX4CjkJlhZg8,24411
20
20
  sourcecode/entrypoint_classifier.py,sha256=jhTYlyqDJH2AtdEcLVaRU3lYRTJuF8DkxVzl4-W3zWE,5322
21
21
  sourcecode/env_analyzer.py,sha256=aNTyYgQk5noJDfJU6FmasmESOHfiomyJw5EvZqjy6qc,22213
@@ -26,7 +26,7 @@ sourcecode/flow_analyzer.py,sha256=dSiuY4w49k29jW_EPXUOND9B5uVbuCA7kjnuHi-pIWA,2
26
26
  sourcecode/fqn_utils.py,sha256=XLU7zDkNBXz_RZkIUNfpPmp1nekWtqP-fxV92tDV1vg,2158
27
27
  sourcecode/git_analyzer.py,sha256=JStxTQXNjBWi_wLdwhsZs9mT-v50cSJIz4Agzn6Kh9I,13362
28
28
  sourcecode/graph_analyzer.py,sha256=DHR8fY69oU_Pi4SYaWboX6EoEFrctQKB9dsjpqwGMzw,62403
29
- sourcecode/license.py,sha256=B3NNCHg1t8Le0_dViwAXnpWTplXA_5ihxh2bs774vWE,11782
29
+ sourcecode/license.py,sha256=-sPY4VuSYSe5dZyy7uFoWn9tHFcKlQkhZU0kgbwypo8,12499
30
30
  sourcecode/mcp_nudge.py,sha256=5ELU_ixzh6uA83NXLOZT8h00OhL53okfQdji3jyKOjg,2917
31
31
  sourcecode/metrics_analyzer.py,sha256=m0ENgtqKeBL17kUIK3fmGkgo7UfXBNHxCMj0H_Y5K7c,22750
32
32
  sourcecode/output_budget.py,sha256=Js9yUlfQtPhqBl9R6wn_9UHVjjJc3GtLcqyfjf5t50Q,9869
@@ -92,9 +92,9 @@ sourcecode/telemetry/config.py,sha256=Pir0WHp4z-9Qclnn2NDZ3vwitqsMkOAJckmwjUSxrk
92
92
  sourcecode/telemetry/consent.py,sha256=wLMvGNJeSSyZoNkQXpoUioY6mMv4Qdvuw7S9jAEWnII,2237
93
93
  sourcecode/telemetry/events.py,sha256=oEvvulfsv5GIDWG2174gSS6tNB95w38AIYiYeifGKlE,2294
94
94
  sourcecode/telemetry/filters.py,sha256=Asa71oRl7q3Wt_FMwuufIZJFzSYdgRNKS8LHCIyFeYE,4805
95
- sourcecode/telemetry/transport.py,sha256=KJeIPCPWMdmbCP3ySGs2iUlia34U6vWne2dZsUezesw,1560
96
- sourcecode-1.35.15.dist-info/METADATA,sha256=UwU_XvS_CUWBrkoCOzMcwPMnKwuvADpKnWzX107_Ms8,21266
97
- sourcecode-1.35.15.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
98
- sourcecode-1.35.15.dist-info/entry_points.txt,sha256=ex3F9rmbXeyDIoFQHtkEqTsKSaJow8F0LrVu8XfIktQ,57
99
- sourcecode-1.35.15.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
100
- sourcecode-1.35.15.dist-info/RECORD,,
95
+ sourcecode/telemetry/transport.py,sha256=QSslxIwij8YkRWcVvxykODDrkiN_GAAEu3dUP7KIWeE,1651
96
+ sourcecode-1.35.16.dist-info/METADATA,sha256=LkCx5nRHlMV_wsznbY9xRh0muC06f_qtM6K9aHP2WbM,21297
97
+ sourcecode-1.35.16.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
98
+ sourcecode-1.35.16.dist-info/entry_points.txt,sha256=ex3F9rmbXeyDIoFQHtkEqTsKSaJow8F0LrVu8XfIktQ,57
99
+ sourcecode-1.35.16.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
100
+ sourcecode-1.35.16.dist-info/RECORD,,