sourcecode 5.8.12__py3-none-any.whl → 5.8.13__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.
Potentially problematic release.
This version of sourcecode might be problematic. Click here for more details.
- sourcecode/__init__.py +1 -1
- sourcecode/_docs/DEFECT-LEDGER.md +3 -2
- sourcecode/_docs/USER_GUIDE.md +3 -3
- sourcecode/cli.py +59 -56
- sourcecode/mcp/runner.py +6 -1
- sourcecode/mcp/server.py +3 -4
- sourcecode/release_info.py +1 -1
- sourcecode/telemetry/__init__.py +5 -4
- sourcecode/telemetry/config.py +14 -19
- sourcecode/telemetry/consent.py +11 -15
- sourcecode/telemetry/events.py +3 -1
- sourcecode/telemetry/filters.py +10 -0
- {sourcecode-5.8.12.dist-info → sourcecode-5.8.13.dist-info}/METADATA +9 -11
- {sourcecode-5.8.12.dist-info → sourcecode-5.8.13.dist-info}/RECORD +18 -18
- {sourcecode-5.8.12.dist-info → sourcecode-5.8.13.dist-info}/WHEEL +0 -0
- {sourcecode-5.8.12.dist-info → sourcecode-5.8.13.dist-info}/entry_points.txt +0 -0
- {sourcecode-5.8.12.dist-info → sourcecode-5.8.13.dist-info}/licenses/LICENSE +0 -0
- {sourcecode-5.8.12.dist-info → sourcecode-5.8.13.dist-info}/licenses/NOTICE +0 -0
sourcecode/__init__.py
CHANGED
|
@@ -16,7 +16,7 @@ The facts these rows are keyed to are published: `ask schema facts-v1` prints th
|
|
|
16
16
|
|
|
17
17
|
## Current Synchronization
|
|
18
18
|
|
|
19
|
-
**As of 2026-08-
|
|
19
|
+
**As of 2026-08-20, release `5.8.13` and the external `5.8.11` re-audit:** this is the current status of
|
|
20
20
|
the 5.8.8/5.8.9 audit queue. The subject remained `saint-server` at `3dde0376`, with a
|
|
21
21
|
byte-identical CIR and the same 53/61 invocables exercised. The score is **78/100**
|
|
22
22
|
(75 in 5.8.8, 80 in 5.8.9). The observations below remain historical evidence; only
|
|
@@ -30,6 +30,7 @@ this table declares present state.
|
|
|
30
30
|
| `AUD-588-B05` | **closed** | `c15f5b6`; changed container-wired components block a false `unaffected` disposition. |
|
|
31
31
|
| `AUD-511-R03` / `AUD-588-B07` | **implemented in 5.8.12** | `47aee1e` gives the published `OUTPUT_TOO_LARGE` envelope precedence over an inconsistent process status and preserves the excerpt in every branch. |
|
|
32
32
|
| `AUD-588-B08` | **closed** | `c084555`; `impact` publishes its independent stdout-byte budget. |
|
|
33
|
+
| `MCP-001` | **closed 5.8.13** | Deep corpus testing reproduced concurrent `CliRunner` stream capture leaking a tool response to the host stdout. `b2c9660` serializes the narrow process-global capture seam; concurrent real MCP calls and a regression test verify response isolation. |
|
|
33
34
|
| `AUD-588-B11` (container/units subset) | **partially implemented in 5.8.12** | `d745d31` discovers nested Maven modules; `273ae8e` suppresses unsupported `pr-impact.unaffected_basis`. `impact` naming, source population units, risk tiers and plan narrative remain open. |
|
|
34
35
|
| `AUD-511-R02` / `AUD-589-B02` | **partially mitigated in 5.8.12, still under investigation** | `b93f230` reuses one `SpringSemanticModel` across every declared `data-exposure` seed; `473f47a` routes `validation` through the shared CIR cache, and `91bd0c0` retains subcommand `--no-cache` compatibility. On the local BroadleafCommerce corpus at the final analyzer fingerprint, a first shared-CIR fill took 10.46 s and its warm `validation --compact` hit took 4.01 s with byte-identical output. This is a same-host cache-state observation, not the 5.8.9/5.8.11 external A/B: the six-run C3-120 comparison and the configured `saint-server` reproduction remain required. |
|
|
35
36
|
| `AUD-588-B02`, `B06`, B11 residuals, `B12` | **partially open in 5.8.12** | `3869c87` excludes explicit EclipseLink from Hibernate applicability and effort; `037223e` publishes provider non-coverage. B11 parity and controlled cost calibration remain required. |
|
|
@@ -594,7 +595,7 @@ class's subject, not its provenance.
|
|
|
594
595
|
|
|
595
596
|
| ID | Item | Found | Severity | Status |
|
|
596
597
|
|---|---|---|---|---|
|
|
597
|
-
| P-1 | Telemetry
|
|
598
|
+
| P-1 | Telemetry default and procurement disclosure | 3.2.0 | **High (procurement)** | **reopened and corrected 5.8.12** — telemetry is on by default by explicit product decision, with `ask telemetry disable`, `SOURCECODE_TELEMETRY=0` and `DO_NOT_TRACK=1` honored before any event is sent. The first-run notice discloses the fields and the disable path. `telemetry status` distinguishes the default from an explicit disabled choice; the privacy policy documents the endpoint, 90-day retention and bounded anonymous fields. This supersedes the historical 3.3.0 opt-in closure for the current release |
|
|
598
599
|
| P-2 | Licence state is ambiguous: `auth status` → `{"status":"unauthenticated","pro":true,"pro_reason":"early-adoption unlock"}`. The buyer cannot tell what it will cost or what they lose when the door closes | 3.2.0 | Medium | **closed 3.4.0** — one authority, `license.entitlement()`: `entitlement` (what runs), `source` (why: `license_key` / `early_adoption_unlock` / `free_tier`), `authenticated` (a separate fact — today one can be entitled without a credential), `paywall_active`, and `when_it_changes`, which states what the user loses when that source stops applying, in the terms the gate uses and **never as a price**. `is_pro` — what every gate reads — is now derived from it rather than computed beside it, which is how the status page came to contradict the commands. The legacy keys stay for consumers, are derived from the authority, and are listed in `deprecated_fields` |
|
|
599
600
|
|
|
600
601
|
| P-3 | **The price is not published.** With P-2 closed the entitlement is unambiguous, but a buyer still cannot see what Pro costs or what a team of 25 pays. Eval #5 lists *"precio Pro público"* among the conditions for the top of its price band, beside the robustness fixes | 3.2.1 (eval #5) | Medium (procurement) | open — packaging question, not a page: the field's own reading is that **the value is frontal** (a first audit replaces 5–15 person-days) **and the recurring half is the CI gate**, so a full seat subscription on a product whose value peaks on run one *"genera churn en el mes 4"*. Model to test: one-off assessment **3–5 k€ per repo** + **8–12 €/dev/month** for the gate. Depends on C3-22: without the gate there is nothing recurring to sell |
|
sourcecode/_docs/USER_GUIDE.md
CHANGED
|
@@ -138,7 +138,7 @@ pipx install sourcecode # isolated install, no venv needed
|
|
|
138
138
|
|
|
139
139
|
# Verify
|
|
140
140
|
ask version
|
|
141
|
-
# ask 5.8.
|
|
141
|
+
# ask 5.8.13
|
|
142
142
|
```
|
|
143
143
|
|
|
144
144
|
Requires Python 3.9+.
|
|
@@ -1199,7 +1199,7 @@ explaining. The rest do one thing; `ask <command> --help` is the whole story.
|
|
|
1199
1199
|
| `ask retrieve` | parked | Typed knowledge queries over the model — kept working, no longer developed |
|
|
1200
1200
|
| `ask baseline capture\|diff\|trend` | supported | Versioned architectural metrics over time; see [`ask trend`](#ask-trend-dir--how-the-architecture-moved) |
|
|
1201
1201
|
| `ask cache status\|warm\|model\|clear\|freshness` | supported | Cache inspection; `ask cache model` states what a warm buys each command |
|
|
1202
|
-
| `ask config` · `ask version` · `ask activate` · `ask auth` · `ask telemetry` · `ask mcp` | supported | Configuration, version, licence, authentication, telemetry (
|
|
1202
|
+
| `ask config` · `ask version` · `ask activate` · `ask auth` · `ask telemetry` · `ask mcp` | supported | Configuration, version, licence, authentication, telemetry (on by default), MCP integration |
|
|
1203
1203
|
|
|
1204
1204
|
## Typical workflows
|
|
1205
1205
|
|
|
@@ -1287,7 +1287,7 @@ ask mcp serve
|
|
|
1287
1287
|
ask mcp remove
|
|
1288
1288
|
```
|
|
1289
1289
|
|
|
1290
|
-
The MCP server exposes structural analysis tools to AI agents without requiring the agent to call the CLI directly. Claude Desktop and Cursor can query impact, endpoints, and context through the MCP protocol.
|
|
1290
|
+
The MCP server exposes structural analysis tools to AI agents without requiring the agent to call the CLI directly. Claude Desktop and Cursor can query impact, endpoints, and context through the MCP protocol. Concurrent requests are accepted safely: ASK serializes only the in-process CLI capture seam, because its stdout/stderr redirection is process-global, so one tool response cannot contaminate another.
|
|
1291
1291
|
|
|
1292
1292
|
---
|
|
1293
1293
|
|
sourcecode/cli.py
CHANGED
|
@@ -3033,13 +3033,59 @@ def _get_command_with_preprocessing(typer_instance: Any) -> Any:
|
|
|
3033
3033
|
|
|
3034
3034
|
_orig_cmd_main = cmd.main
|
|
3035
3035
|
|
|
3036
|
+
_TELEMETRY_COMMANDS = frozenset({
|
|
3037
|
+
"repo-ir", "impact", "endpoints", "export", "validation", "delta", "contract-diff",
|
|
3038
|
+
"plan", "compare", "trend", "timeline", "spring-audit", "verify-edit", "verify", "risk",
|
|
3039
|
+
"enrich", "audit-report", "migrate-recipe", "data-exposure", "posture", "migrate-check",
|
|
3040
|
+
"impact-chain", "pr-impact", "explain", "onboard", "review-pr", "fix-bug", "modernize",
|
|
3041
|
+
"rename-class", "chunk-file", "activate", "selftest", "explain-endpoint", "regress", "version",
|
|
3042
|
+
"schema", "config", "archetype", "cold-start", "telemetry", "mcp", "cache", "baseline",
|
|
3043
|
+
"auth", "retrieve", "prepare-context",
|
|
3044
|
+
})
|
|
3045
|
+
|
|
3046
|
+
def _telemetry_command(args_for_command: Optional[list[str]]) -> str:
|
|
3047
|
+
"""Extract only a registered CLI command, never a path or option value."""
|
|
3048
|
+
tokens = list(args_for_command) if args_for_command is not None else sys.argv[1:]
|
|
3049
|
+
for token in tokens:
|
|
3050
|
+
if token in _TELEMETRY_COMMANDS:
|
|
3051
|
+
return token
|
|
3052
|
+
return "analyze"
|
|
3053
|
+
|
|
3054
|
+
def _telemetry_flags(args_for_command: Optional[list[str]]) -> list[str]:
|
|
3055
|
+
tokens = list(args_for_command) if args_for_command is not None else sys.argv[1:]
|
|
3056
|
+
try:
|
|
3057
|
+
from sourcecode.telemetry.filters import _SAFE_FLAGS
|
|
3058
|
+
return sorted({token for token in tokens if token in _SAFE_FLAGS})
|
|
3059
|
+
except Exception:
|
|
3060
|
+
return []
|
|
3061
|
+
|
|
3036
3062
|
def _cmd_main(args: Optional[list[str]] = None, **kwargs: Any) -> Any:
|
|
3037
3063
|
if args is not None:
|
|
3038
3064
|
# CliRunner / programmatic call: preprocess the explicit args list.
|
|
3039
3065
|
_set_detected_path(".")
|
|
3040
3066
|
args = _preprocess_args(list(args))
|
|
3041
3067
|
# args=None → Click reads sys.argv; _preprocess_argv() in main_entry handled it.
|
|
3042
|
-
|
|
3068
|
+
started = time.monotonic()
|
|
3069
|
+
command = _telemetry_command(args)
|
|
3070
|
+
success = True
|
|
3071
|
+
try:
|
|
3072
|
+
return _orig_cmd_main(args=args, **kwargs)
|
|
3073
|
+
except BaseException:
|
|
3074
|
+
success = False
|
|
3075
|
+
raise
|
|
3076
|
+
finally:
|
|
3077
|
+
try:
|
|
3078
|
+
from sourcecode import telemetry as _tel
|
|
3079
|
+
_tel.record(
|
|
3080
|
+
"execution_completed",
|
|
3081
|
+
cmd=("mcp" if command == "mcp" else "telemetry" if command == "telemetry" else "analyze"),
|
|
3082
|
+
command=command,
|
|
3083
|
+
flags=_telemetry_flags(args),
|
|
3084
|
+
duration_s=time.monotonic() - started,
|
|
3085
|
+
success=success,
|
|
3086
|
+
)
|
|
3087
|
+
except Exception:
|
|
3088
|
+
pass
|
|
3043
3089
|
|
|
3044
3090
|
cmd.main = _cmd_main
|
|
3045
3091
|
return cmd
|
|
@@ -3055,7 +3101,7 @@ try:
|
|
|
3055
3101
|
except Exception:
|
|
3056
3102
|
pass
|
|
3057
3103
|
|
|
3058
|
-
telemetry_app = typer.Typer(help="Manage anonymous telemetry (
|
|
3104
|
+
telemetry_app = typer.Typer(help="Manage anonymous telemetry (on by default; disable any time).", rich_markup_mode="rich")
|
|
3059
3105
|
app.add_typer(telemetry_app, name="telemetry")
|
|
3060
3106
|
|
|
3061
3107
|
mcp_app = typer.Typer(help="MCP integration: setup, status, serve, remove.", rich_markup_mode="rich")
|
|
@@ -3083,9 +3129,8 @@ app.add_typer(retrieve_app, name="retrieve")
|
|
|
3083
3129
|
def _maybe_show_telemetry_notice() -> None:
|
|
3084
3130
|
"""Show first-run telemetry notice once, on interactive TTYs only.
|
|
3085
3131
|
|
|
3086
|
-
Telemetry is
|
|
3087
|
-
|
|
3088
|
-
appears only once.
|
|
3132
|
+
Telemetry is on by default. The notice is a one-time disclosure of what is
|
|
3133
|
+
collected and how to disable it.
|
|
3089
3134
|
"""
|
|
3090
3135
|
try:
|
|
3091
3136
|
from sourcecode.telemetry.config import has_been_asked, mark_asked
|
|
@@ -5314,26 +5359,7 @@ def main(
|
|
|
5314
5359
|
perf.stop("serialize", _perf_serialize)
|
|
5315
5360
|
perf.flush_recorder()
|
|
5316
5361
|
|
|
5317
|
-
# 5.
|
|
5318
|
-
try:
|
|
5319
|
-
from sourcecode import telemetry as _tel
|
|
5320
|
-
_tel.record(
|
|
5321
|
-
"execution_completed",
|
|
5322
|
-
cmd="analyze",
|
|
5323
|
-
flags=_active_flags(
|
|
5324
|
-
dependencies, graph_modules, docs, full_metrics,
|
|
5325
|
-
semantics, architecture, git_context, env_map,
|
|
5326
|
-
code_notes, agent, compact, tree, no_redact, format,
|
|
5327
|
-
),
|
|
5328
|
-
output_fmt=format,
|
|
5329
|
-
file_count=len(sm.file_paths),
|
|
5330
|
-
duration_s=time.monotonic() - _t0,
|
|
5331
|
-
success=True,
|
|
5332
|
-
)
|
|
5333
|
-
except Exception:
|
|
5334
|
-
pass
|
|
5335
|
-
|
|
5336
|
-
# 6. Write output (CLI-04)
|
|
5362
|
+
# 5. Write output (CLI-04)
|
|
5337
5363
|
_progress.finish()
|
|
5338
5364
|
if format == "json":
|
|
5339
5365
|
_uncommitted_fresh, _uncommitted_fresh_basis = _uncommitted_fact(
|
|
@@ -5926,17 +5952,6 @@ def prepare_context_cmd(
|
|
|
5926
5952
|
except Exception:
|
|
5927
5953
|
pass # not JSON (or unreadable) → serve exactly what was stored
|
|
5928
5954
|
_emit_command_output(_cached_pctx, output_path, copy)
|
|
5929
|
-
try:
|
|
5930
|
-
from sourcecode import telemetry as _tel
|
|
5931
|
-
_tel.record(
|
|
5932
|
-
"execution_completed",
|
|
5933
|
-
cmd="prepare-context",
|
|
5934
|
-
feature=task,
|
|
5935
|
-
output_fmt=format,
|
|
5936
|
-
duration_s=0.0,
|
|
5937
|
-
)
|
|
5938
|
-
except Exception:
|
|
5939
|
-
pass
|
|
5940
5955
|
return
|
|
5941
5956
|
|
|
5942
5957
|
_scope_files = None
|
|
@@ -6463,18 +6478,6 @@ def prepare_context_cmd(
|
|
|
6463
6478
|
fmt=("yaml" if format == "yaml" else "json")
|
|
6464
6479
|
)
|
|
6465
6480
|
|
|
6466
|
-
try:
|
|
6467
|
-
from sourcecode import telemetry as _tel
|
|
6468
|
-
_tel.record(
|
|
6469
|
-
"execution_completed",
|
|
6470
|
-
cmd="prepare-context",
|
|
6471
|
-
feature=task,
|
|
6472
|
-
output_fmt=format,
|
|
6473
|
-
duration_s=_time.perf_counter() - _t0,
|
|
6474
|
-
)
|
|
6475
|
-
except Exception:
|
|
6476
|
-
pass
|
|
6477
|
-
|
|
6478
6481
|
from sourcecode.mcp_nudge import nudge_mcp_if_needed as _nudge
|
|
6479
6482
|
_nudge()
|
|
6480
6483
|
|
|
@@ -6491,11 +6494,11 @@ def telemetry_status(
|
|
|
6491
6494
|
enabled = is_enabled()
|
|
6492
6495
|
choice = stored_choice()
|
|
6493
6496
|
status = "enabled" if enabled else "disabled"
|
|
6494
|
-
lines = [f"Telemetry: {status} (
|
|
6495
|
-
#
|
|
6496
|
-
#
|
|
6497
|
+
lines = [f"Telemetry: {status} (on by default; disable with `ask telemetry disable`)"]
|
|
6498
|
+
# The default and an explicit disabled choice are different answers, and a
|
|
6499
|
+
# buyer auditing this needs to be told which one they have.
|
|
6497
6500
|
if choice is None:
|
|
6498
|
-
lines.append(" No choice recorded —
|
|
6501
|
+
lines.append(" No choice recorded — the on-by-default setting applies.")
|
|
6499
6502
|
else:
|
|
6500
6503
|
lines.append(f" Your recorded choice: {'enabled' if choice else 'disabled'}.")
|
|
6501
6504
|
lines.append(f" Config: {config_file_path()}")
|
|
@@ -6508,7 +6511,7 @@ def telemetry_status(
|
|
|
6508
6511
|
|
|
6509
6512
|
@telemetry_app.command("enable")
|
|
6510
6513
|
def telemetry_enable() -> None:
|
|
6511
|
-
"""
|
|
6514
|
+
"""Enable anonymous telemetry and remember the choice."""
|
|
6512
6515
|
from sourcecode.telemetry.config import set_enabled
|
|
6513
6516
|
from sourcecode import telemetry as _tel
|
|
6514
6517
|
set_enabled(True)
|
|
@@ -6521,11 +6524,11 @@ def telemetry_enable() -> None:
|
|
|
6521
6524
|
|
|
6522
6525
|
@telemetry_app.command("disable")
|
|
6523
6526
|
def telemetry_disable() -> None:
|
|
6524
|
-
"""
|
|
6527
|
+
"""Disable anonymous telemetry and remember the choice."""
|
|
6525
6528
|
from sourcecode.telemetry.config import set_enabled
|
|
6526
6529
|
set_enabled(False)
|
|
6527
6530
|
typer.echo("Telemetry disabled. No data will be collected or sent.")
|
|
6528
|
-
typer.echo("Telemetry is
|
|
6531
|
+
typer.echo("Telemetry is enabled by default; this choice is recorded so the notice stops appearing.")
|
|
6529
6532
|
typer.echo("Re-enable at any time: ask telemetry enable")
|
|
6530
6533
|
|
|
6531
6534
|
|
|
@@ -14190,7 +14193,7 @@ def config_cmd(
|
|
|
14190
14193
|
_answer = _TextAnswer(output_path)
|
|
14191
14194
|
_answer.say(f"ask {__version__}")
|
|
14192
14195
|
_answer.say(f"Config: {config_file_path()}")
|
|
14193
|
-
_answer.say(f"Telemetry: {'enabled' if is_enabled() else 'disabled'} (
|
|
14196
|
+
_answer.say(f"Telemetry: {'enabled' if is_enabled() else 'disabled'} (on by default; disable with `ask telemetry disable`)")
|
|
14194
14197
|
_answer.say("")
|
|
14195
14198
|
|
|
14196
14199
|
# F-AX: the declaration may sit outside the analysed tree, and *which* file
|
sourcecode/mcp/runner.py
CHANGED
|
@@ -7,11 +7,15 @@ lookup, no process fork, no stdout encoding issues.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import json
|
|
10
|
+
import threading
|
|
10
11
|
from typing import Any
|
|
11
12
|
|
|
12
13
|
from typer.testing import CliRunner
|
|
13
14
|
|
|
14
15
|
_runner = CliRunner()
|
|
16
|
+
# CliRunner temporarily replaces process-global stdout/stderr. MCP dispatches
|
|
17
|
+
# tools concurrently, so every in-process invocation must share this lock.
|
|
18
|
+
_runner_lock = threading.RLock()
|
|
15
19
|
|
|
16
20
|
|
|
17
21
|
class CommandError(RuntimeError):
|
|
@@ -44,7 +48,8 @@ def run_command(args: list[str]) -> Any:
|
|
|
44
48
|
# Pass raw args to invoke — the _cmd_main hook inside cli.py handles path
|
|
45
49
|
# extraction via _preprocess_args. Pre-processing here would strip the path
|
|
46
50
|
# from args, then _cmd_main would re-process the stripped list and lose it.
|
|
47
|
-
|
|
51
|
+
with _runner_lock:
|
|
52
|
+
result = _runner.invoke(app, list(args))
|
|
48
53
|
|
|
49
54
|
if result.exit_code != 0:
|
|
50
55
|
stdout_raw = getattr(result, "output", "")
|
sourcecode/mcp/server.py
CHANGED
|
@@ -51,9 +51,8 @@ def _record_tool_invocation(name: Any, success: bool, started: float) -> None:
|
|
|
51
51
|
|
|
52
52
|
Aggregate only: which of our own tools ran, whether it succeeded, and a
|
|
53
53
|
duration bucket. Never the arguments — those carry repository paths — and
|
|
54
|
-
never any result content. Honours the same
|
|
55
|
-
|
|
56
|
-
telemetry is off, `record` returns before building anything.
|
|
54
|
+
never any result content. Honours the same default-on setting as every other
|
|
55
|
+
event; `ask telemetry disable` or the documented environment controls stop it.
|
|
57
56
|
"""
|
|
58
57
|
try:
|
|
59
58
|
import time as _time
|
|
@@ -1480,7 +1479,7 @@ def telemetry(action: str) -> dict:
|
|
|
1480
1479
|
"""Manage telemetry settings.
|
|
1481
1480
|
|
|
1482
1481
|
Maps to: ask telemetry <action>
|
|
1483
|
-
action: one of "status" (show current state), "enable"
|
|
1482
|
+
action: one of "status" (show current state), "enable", or "disable".
|
|
1484
1483
|
Valid values: "status" | "enable" | "disable"
|
|
1485
1484
|
"""
|
|
1486
1485
|
# FIX-P2-10: enumerate valid actions in docstring so agents don't guess.
|
sourcecode/release_info.py
CHANGED
|
@@ -27,7 +27,7 @@ from typing import Any, Optional
|
|
|
27
27
|
#: The date `__version__` was released, from that version's CHANGELOG entry.
|
|
28
28
|
#: `tests/test_release_info.py` fails the build if the two disagree, so this is
|
|
29
29
|
#: a copy of a fact rather than a second authority for it.
|
|
30
|
-
RELEASE_DATE = "2026-08-
|
|
30
|
+
RELEASE_DATE = "2026-08-20"
|
|
31
31
|
|
|
32
32
|
#: Releases per day, measured over the 30 releases before this one (the same
|
|
33
33
|
#: computation the test re-runs against the CHANGELOG). Stable across window
|
sourcecode/telemetry/__init__.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
"""sourcecode telemetry — anonymous usage metrics,
|
|
1
|
+
"""sourcecode telemetry — anonymous usage metrics, on by default.
|
|
2
2
|
|
|
3
3
|
Public API:
|
|
4
4
|
is_enabled() → bool
|
|
5
5
|
record(event, **kw) → None (fire-and-forget)
|
|
6
6
|
session_id() → str (ephemeral 8-char hex, new each process)
|
|
7
7
|
|
|
8
|
-
Telemetry is
|
|
9
|
-
|
|
10
|
-
why the default moved.
|
|
8
|
+
Telemetry is enabled by default and stays anonymous. Disable it with `ask telemetry
|
|
9
|
+
disable`, SOURCECODE_TELEMETRY=0, or DO_NOT_TRACK=1.
|
|
11
10
|
|
|
12
11
|
Nothing sensitive (code, paths, secrets, output) is ever collected.
|
|
13
12
|
See docs/privacy.md for full details.
|
|
@@ -72,6 +71,7 @@ def record(
|
|
|
72
71
|
event: str,
|
|
73
72
|
*,
|
|
74
73
|
cmd: str = "analyze",
|
|
74
|
+
command: Optional[str] = None,
|
|
75
75
|
flags: Optional[list[str]] = None,
|
|
76
76
|
output_fmt: str = "json",
|
|
77
77
|
file_count: Optional[int] = None,
|
|
@@ -98,6 +98,7 @@ def record(
|
|
|
98
98
|
os=_platform_os(),
|
|
99
99
|
arch=_platform_arch(),
|
|
100
100
|
cmd=cmd,
|
|
101
|
+
command=command,
|
|
101
102
|
flags=flags or [],
|
|
102
103
|
output_fmt=output_fmt,
|
|
103
104
|
repo_size=(
|
sourcecode/telemetry/config.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"""Persistent telemetry configuration.
|
|
2
2
|
|
|
3
|
-
Telemetry is **
|
|
4
|
-
|
|
3
|
+
Telemetry is **on by default** and stays anonymous. Users can disable it with
|
|
4
|
+
``ask telemetry disable``, ``SOURCECODE_TELEMETRY=0`` or ``DO_NOT_TRACK=1``;
|
|
5
|
+
it never collects source code, paths, secrets or repository content.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*before the first run*, which the product gave them no way to do. Nothing is
|
|
10
|
-
collected before an explicit choice, so there is nothing to disable in time.
|
|
7
|
+
The default is explicit and reversible: users can disable telemetry before a run
|
|
8
|
+
with `SOURCECODE_TELEMETRY=0` or `DO_NOT_TRACK=1`, or persist that choice with
|
|
9
|
+
`ask telemetry disable`.
|
|
11
10
|
|
|
12
11
|
Config file: ~/.config/sourcecode/config.json
|
|
13
12
|
Enable: `ask telemetry enable` or SOURCECODE_TELEMETRY=1
|
|
@@ -43,26 +42,22 @@ def _save(data: dict[str, Any]) -> None:
|
|
|
43
42
|
def stored_choice() -> "bool | None":
|
|
44
43
|
"""The explicit choice on record, or None when the user has made none.
|
|
45
44
|
|
|
46
|
-
`None` is a state, not a synonym for `False`: "
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
`None` is a state, not a synonym for `False`: "on because the default applies"
|
|
46
|
+
and "off because you turned it off" are different answers, and `telemetry
|
|
47
|
+
status` prints them differently.
|
|
49
48
|
"""
|
|
50
49
|
stored = _load().get("telemetry", {}).get("enabled")
|
|
51
50
|
return None if stored is None else bool(stored)
|
|
52
51
|
|
|
53
52
|
|
|
54
53
|
def is_enabled() -> bool:
|
|
55
|
-
"""
|
|
54
|
+
"""Return whether telemetry is enabled. It defaults to enabled.
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
not. Precedence, highest first:
|
|
56
|
+
Precedence, highest first:
|
|
59
57
|
1. SOURCECODE_TELEMETRY env var (0 = off, 1 = on)
|
|
60
58
|
2. DO_NOT_TRACK env var (any value other than ""/"0" turns it off)
|
|
61
59
|
3. config file 'enabled' flag, if the user has made an explicit choice
|
|
62
|
-
4. default:
|
|
63
|
-
|
|
64
|
-
There is no CI special case any more, because there is nothing left for it
|
|
65
|
-
to protect against — the default it used to override is now off.
|
|
60
|
+
4. default: True
|
|
66
61
|
"""
|
|
67
62
|
env = os.environ.get(_ENV_VAR, "").strip()
|
|
68
63
|
if env == "0":
|
|
@@ -75,7 +70,7 @@ def is_enabled() -> bool:
|
|
|
75
70
|
stored = stored_choice()
|
|
76
71
|
if stored is not None:
|
|
77
72
|
return stored
|
|
78
|
-
return
|
|
73
|
+
return True
|
|
79
74
|
|
|
80
75
|
|
|
81
76
|
def has_been_asked() -> bool:
|
|
@@ -100,7 +95,7 @@ def mark_asked() -> None:
|
|
|
100
95
|
def get_install_id() -> str:
|
|
101
96
|
"""Stable anonymous install id — a random UUID v4.
|
|
102
97
|
|
|
103
|
-
Created lazily on first
|
|
98
|
+
Created lazily on first enabled event. NOT derived from hardware, email,
|
|
104
99
|
hostname or any identifier — it only says "the same install across runs",
|
|
105
100
|
which is what enables unique-user, conversion and retention metrics.
|
|
106
101
|
Returns "" if it cannot be persisted (telemetry then degrades to events
|
sourcecode/telemetry/consent.py
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
"""First-run telemetry notice.
|
|
2
2
|
|
|
3
|
-
Telemetry is **
|
|
4
|
-
|
|
5
|
-
exactly once, only on interactive TTYs, and it is an invitation — it states what
|
|
6
|
-
*would* be collected if they said yes, and it never changes the setting.
|
|
3
|
+
Telemetry is **on by default**. The notice is shown exactly once, only on
|
|
4
|
+
interactive TTYs, and states what is collected and how to disable it.
|
|
7
5
|
|
|
8
|
-
The
|
|
9
|
-
|
|
10
|
-
collector is the thing this release removed.
|
|
6
|
+
The disclosure is deliberately printed once so users know what is collected and
|
|
7
|
+
how to disable it before a later run.
|
|
11
8
|
|
|
12
9
|
Notice is written to stderr so it doesn't pollute stdout output.
|
|
13
10
|
"""
|
|
@@ -19,18 +16,17 @@ import sys
|
|
|
19
16
|
|
|
20
17
|
_NOTICE = """\
|
|
21
18
|
\033[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
22
|
-
ask — anonymous telemetry is
|
|
19
|
+
ask — anonymous telemetry is ON by default
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
turn it on. If you would like to help:
|
|
21
|
+
Anonymous usage metadata is collected to improve ASK. To disable it:
|
|
26
22
|
|
|
27
|
-
ask telemetry
|
|
23
|
+
ask telemetry disable
|
|
28
24
|
|
|
29
|
-
|
|
25
|
+
This is collected: tool version, Python version,
|
|
30
26
|
OS, commands used, flags used, MCP tool names invoked,
|
|
31
27
|
approximate repo size, execution duration, errors.
|
|
32
28
|
|
|
33
|
-
Never collected
|
|
29
|
+
Never collected: source code, file paths, file
|
|
34
30
|
names, secrets, tokens, environment variables, or any
|
|
35
31
|
repository content.
|
|
36
32
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m
|
|
@@ -51,10 +47,10 @@ def _is_interactive() -> bool:
|
|
|
51
47
|
|
|
52
48
|
|
|
53
49
|
def show_first_run_notice() -> None:
|
|
54
|
-
"""Print the one-time telemetry
|
|
50
|
+
"""Print the one-time telemetry disclosure on interactive terminals.
|
|
55
51
|
|
|
56
52
|
Never raises. Does nothing on non-interactive / CI environments.
|
|
57
|
-
|
|
53
|
+
Printing this notice does not change the telemetry setting.
|
|
58
54
|
"""
|
|
59
55
|
if not _is_interactive():
|
|
60
56
|
return
|
sourcecode/telemetry/events.py
CHANGED
|
@@ -52,7 +52,8 @@ class TelemetryEvent:
|
|
|
52
52
|
py — Python major.minor (e.g. "3.11")
|
|
53
53
|
os — OS family: linux | macos | windows | other
|
|
54
54
|
arch — CPU architecture: x64 | arm64 | other
|
|
55
|
-
cmd — command: analyze | prepare-context | telemetry
|
|
55
|
+
cmd — command family: analyze | prepare-context | telemetry | mcp | unknown
|
|
56
|
+
command — closed product command identifier, or None
|
|
56
57
|
flags — flag names only (no values)
|
|
57
58
|
output_fmt — json | yaml
|
|
58
59
|
repo_size — tiny | small | medium | large | huge
|
|
@@ -74,6 +75,7 @@ class TelemetryEvent:
|
|
|
74
75
|
os: str = ""
|
|
75
76
|
arch: str = ""
|
|
76
77
|
cmd: str = ""
|
|
78
|
+
command: Optional[str] = None
|
|
77
79
|
flags: list[str] = field(default_factory=list)
|
|
78
80
|
output_fmt: str = "json"
|
|
79
81
|
repo_size: str = "unknown"
|
sourcecode/telemetry/filters.py
CHANGED
|
@@ -57,6 +57,15 @@ _SAFE_FLAGS: frozenset[str] = frozenset({
|
|
|
57
57
|
_SAFE_OS: frozenset[str] = frozenset({"linux", "macos", "windows", "other"})
|
|
58
58
|
_SAFE_ARCH: frozenset[str] = frozenset({"x64", "arm64", "other"})
|
|
59
59
|
_SAFE_CMD: frozenset[str] = frozenset({"analyze", "prepare-context", "telemetry", "mcp", "unknown"})
|
|
60
|
+
_SAFE_COMMANDS: frozenset[str] = frozenset({
|
|
61
|
+
"analyze", "prepare-context", "telemetry", "mcp", "cache", "baseline", "auth", "retrieve",
|
|
62
|
+
"repo-ir", "impact", "endpoints", "export", "validation", "delta", "contract-diff", "plan",
|
|
63
|
+
"compare", "trend", "timeline", "spring-audit", "verify-edit", "verify", "risk", "enrich",
|
|
64
|
+
"audit-report", "migrate-recipe", "data-exposure", "posture", "migrate-check", "impact-chain",
|
|
65
|
+
"pr-impact", "explain", "onboard", "review-pr", "fix-bug", "modernize", "rename-class",
|
|
66
|
+
"chunk-file", "activate", "selftest", "explain-endpoint", "regress", "version", "schema",
|
|
67
|
+
"config", "archetype", "cold-start",
|
|
68
|
+
})
|
|
60
69
|
_SAFE_EVENTS: frozenset[str] = frozenset({
|
|
61
70
|
"command_executed",
|
|
62
71
|
"execution_completed",
|
|
@@ -153,6 +162,7 @@ def sanitize(event: TelemetryEvent) -> dict[str, Any]:
|
|
|
153
162
|
"os": _safe_str(event.os, _SAFE_OS, "other"),
|
|
154
163
|
"arch": _safe_str(event.arch, _SAFE_ARCH, "other"),
|
|
155
164
|
"cmd": _safe_str(event.cmd, _SAFE_CMD, "unknown"),
|
|
165
|
+
"command": _safe_str(event.command or "", _SAFE_COMMANDS, "unknown") if event.command else None,
|
|
156
166
|
"flags": _safe_flags(event.flags),
|
|
157
167
|
"output_fmt": _safe_str(event.output_fmt, _SAFE_FMTS, "json"),
|
|
158
168
|
"repo_size": _safe_str(event.repo_size, _SAFE_SIZES, "unknown"),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 5.8.
|
|
3
|
+
Version: 5.8.13
|
|
4
4
|
Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/HarounDominique/sourcecode
|
|
6
6
|
Project-URL: Repository, https://github.com/HarounDominique/sourcecode
|
|
@@ -49,7 +49,7 @@ Description-Content-Type: text/markdown
|
|
|
49
49
|
|
|
50
50
|
**Context · Impact · Migration · Architecture · Review — everything from one structural model.**
|
|
51
51
|
|
|
52
|
-

|
|
53
53
|

|
|
54
54
|
|
|
55
55
|
Copyright (c) 2026 Dominique Haroun. All rights reserved. ASK Engine 5.7.0 and
|
|
@@ -151,7 +151,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
|
|
|
151
151
|
# pip / pipx
|
|
152
152
|
pipx install sourcecode # or: pip install sourcecode
|
|
153
153
|
|
|
154
|
-
ask version # ask 5.8.
|
|
154
|
+
ask version # ask 5.8.13 — and, on a build that has aged,
|
|
155
155
|
# how many releases have probably shipped since
|
|
156
156
|
```
|
|
157
157
|
|
|
@@ -580,18 +580,16 @@ ask config # version, config file path, telemetry status
|
|
|
580
580
|
ask config /repo # + the repository's own sourcecode.config.json:
|
|
581
581
|
# data labels, custom security annotations,
|
|
582
582
|
# and any declaration that could not be used
|
|
583
|
-
ask telemetry enable # anonymous telemetry is
|
|
583
|
+
ask telemetry enable # ensure anonymous telemetry is enabled
|
|
584
584
|
```
|
|
585
585
|
|
|
586
|
-
**
|
|
587
|
-
|
|
588
|
-
range, and errors: **no source code, paths, secrets, or output**. Turn it off again with
|
|
586
|
+
**Anonymous telemetry is ON by default**. It collects version, OS, commands, flags, duration,
|
|
587
|
+
repo-size range, and errors: **no source code, paths, secrets, or output**. Turn it off with
|
|
589
588
|
`ask telemetry disable`, `export SOURCECODE_TELEMETRY=0`, or `DO_NOT_TRACK=1`.
|
|
590
589
|
|
|
591
|
-
> **Auditing someone else's code — regulated, client-owned or public-sector?**
|
|
592
|
-
>
|
|
593
|
-
>
|
|
594
|
-
> choice you made before is unchanged.
|
|
590
|
+
> **Auditing someone else's code — regulated, client-owned or public-sector?** Set
|
|
591
|
+
> `SOURCECODE_TELEMETRY=0` before the run. The setting is explicit, local and honored before
|
|
592
|
+
> any event is sent.
|
|
595
593
|
|
|
596
594
|
**A question is not a write — `--no-write` / `ASK_READONLY=1`.** One contract over
|
|
597
595
|
every command: nothing is created inside the analysed repository, and a command
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
sourcecode/__init__.py,sha256=
|
|
1
|
+
sourcecode/__init__.py,sha256=WDXhi5kHWMfE8cOqlfy1cyhggsaPJwg3cmS3GE08CxA,309
|
|
2
2
|
sourcecode/adaptive_scanner.py,sha256=yJBKjNpkY6bpueYJ2YnRezen3sYZDecEt7WaaNWdqug,9466
|
|
3
3
|
sourcecode/answer_bounds.py,sha256=_51_DCuYEUmI_xwUFxDMiprSavkNakkLiIBbPjevQ3M,9793
|
|
4
4
|
sourcecode/archetype.py,sha256=uubguXP5ltQt25ACNVm9kX4KRTe7JCqkFfg4H9zckCo,40971
|
|
@@ -25,7 +25,7 @@ sourcecode/chain_rules.py,sha256=Bi6UHfgd-GxWswmnHRcPz5jdbAuqka3Zkz_P-MTvqhw,127
|
|
|
25
25
|
sourcecode/change_plan.py,sha256=wJ896V27a3qb-2vcZhrcOSOqFAwCmEyzbhdbdxM2LlQ,12504
|
|
26
26
|
sourcecode/cir_graphs.py,sha256=RytqSv1WF8kdlfXj2fPQz16LY4akS2kyThbdWL8beCQ,14835
|
|
27
27
|
sourcecode/classifier.py,sha256=JBzPwSSrDG-tUHAbcKB678HRbjLpD-ohzbzzO62mgpo,20114
|
|
28
|
-
sourcecode/cli.py,sha256=
|
|
28
|
+
sourcecode/cli.py,sha256=cAYOBP_CgY4Z7FjciLs2Awtkjg8cGsfjD-ULAqIRqXg,727830
|
|
29
29
|
sourcecode/client_calls.py,sha256=YOPnfRZzRyqmdHvXSVeiunW8cuiuCuWXacNIQRgKMCw,22640
|
|
30
30
|
sourcecode/code_notes_analyzer.py,sha256=EJemNCNc9Dn-1RZYu-aNbK0ELzmsyC4s6FdHi3XyNEI,9392
|
|
31
31
|
sourcecode/compare.py,sha256=Lj8epBqrHLWBhiccE2X0ZbaP2H3hNb7qecoN9Jvsj7c,14794
|
|
@@ -117,7 +117,7 @@ sourcecode/reconciliation.py,sha256=pmqc0JNcAagKGWDcjH2rLDlKlAbfJCVUj86vV--YEXQ,
|
|
|
117
117
|
sourcecode/redactor.py,sha256=SB4hwIvg8h-hvcqKcDWaZvA-aSyn-at-BIRwa0tUv5E,3227
|
|
118
118
|
sourcecode/reference_facts.py,sha256=mx7H-Ax5y8sKAQHrnJCXlgjkUzqZtQTByv9Zy2lxKQQ,15500
|
|
119
119
|
sourcecode/regress.py,sha256=aXN6n7t39OOSOUvUs4HTH7UGVwl-tzhjXjHfDXNtp04,11162
|
|
120
|
-
sourcecode/release_info.py,sha256=
|
|
120
|
+
sourcecode/release_info.py,sha256=l9HiTnxDaaMobb1XUTXACXjPxIzZyRScSkgwcnQ8OjU,6064
|
|
121
121
|
sourcecode/relevance_scorer.py,sha256=0AgEt4KrV73nioMqBgjhGjtY7L2C7L7cSyKtj3IKcrw,9408
|
|
122
122
|
sourcecode/remediation_diff.py,sha256=fGYqPmQF7bO54L8ivztX5PgmW4fVu54gNcG6OEQ192U,9730
|
|
123
123
|
sourcecode/remedies.py,sha256=V2_cD4pLq8bKRkzF-3RGFoiu1xWYZS384WDVp1MrlZw,10225
|
|
@@ -203,8 +203,8 @@ sourcecode/mcp/__init__.py,sha256=XU4HfRGbdid8wdUA0x_4f7uKZD1z3mv_XUY_WU_T9Mw,17
|
|
|
203
203
|
sourcecode/mcp/dependency_import.py,sha256=wfvw1rmDE3n2mHDj-yHnCuy9HZ7TtPqsHG2BU-Scl1k,4146
|
|
204
204
|
sourcecode/mcp/orchestrator.py,sha256=imbOxkzsQh91as8a3OdSU7VG2L3A1faUldiKwA2jMSQ,36825
|
|
205
205
|
sourcecode/mcp/registry.py,sha256=kydzpUGGKckWM_F_GeGkWG1Z_qU3R8mZSbBWYKtDewU,69326
|
|
206
|
-
sourcecode/mcp/runner.py,sha256=
|
|
207
|
-
sourcecode/mcp/server.py,sha256=
|
|
206
|
+
sourcecode/mcp/runner.py,sha256=dRvI0xS2wa8DH0diYjJiAoaGeVdtf389PekWwwh8wRI,3083
|
|
207
|
+
sourcecode/mcp/server.py,sha256=1CRISYBwPuAdSaNFVeupjYr2nfK6hmBv8J1nfdCLQJ8,67510
|
|
208
208
|
sourcecode/mcp/onboarding/__init__.py,sha256=sj2PWqEBmMc4zBNkomg89WtL0M6S7A9yb7_wAuSWNP4,66
|
|
209
209
|
sourcecode/mcp/onboarding/applier.py,sha256=Sx9vHTaXr_M1Bs4uMjO7qa_a2_p4J9oz93oJsKQ7ds4,3298
|
|
210
210
|
sourcecode/mcp/onboarding/backup.py,sha256=ihqGOR8QTX8HASRSEDyfFyXr5bkXrygPHamv4p9KTmk,1452
|
|
@@ -234,19 +234,19 @@ sourcecode/schemas/envelope-v1.schema.json,sha256=Zu5D2cspa_biP5-JMWY0H6oYGyAyA4
|
|
|
234
234
|
sourcecode/schemas/pr-impact-v1.schema.json,sha256=fC4DLqY--N5iJpm5wCxbUeILianYbhNDNYV3n4D5gFg,3756
|
|
235
235
|
sourcecode/schemas/verify-edit-v1.schema.json,sha256=0jp-yoFIdmfq-4IrzrOPCAsEN7JcKg6cjq7-87_Ez0U,3537
|
|
236
236
|
sourcecode/schemas/verify-v1.schema.json,sha256=rY1h_ub3hMAKCHO6WmnyKDtI4b37xLAEC6uuoEhKR64,3441
|
|
237
|
-
sourcecode/telemetry/__init__.py,sha256=
|
|
238
|
-
sourcecode/telemetry/config.py,sha256=
|
|
239
|
-
sourcecode/telemetry/consent.py,sha256
|
|
240
|
-
sourcecode/telemetry/events.py,sha256=
|
|
241
|
-
sourcecode/telemetry/filters.py,sha256
|
|
237
|
+
sourcecode/telemetry/__init__.py,sha256=5jg6mIrhnt59FgxQsQcihxkHCWM07UFQFcuGwMPa9v8,3489
|
|
238
|
+
sourcecode/telemetry/config.py,sha256=QPuTK-oc-Bg_EQftyFxLHPSnLRiZ5NegWYfX4BcD8iI,3842
|
|
239
|
+
sourcecode/telemetry/consent.py,sha256=-Wb8BFGXEexOs8M0Eja7F-T6ZtLNPeRoZnHcHvlP7-Q,2153
|
|
240
|
+
sourcecode/telemetry/events.py,sha256=l3Z2SQUO4_C2D2ItXOOdVNimAmHedUHnUxqYFTxnsAE,2900
|
|
241
|
+
sourcecode/telemetry/filters.py,sha256=-lqT2oorECuqEIdeHb--7AZ6BCaUx0bya720a-Z5x6w,7335
|
|
242
242
|
sourcecode/telemetry/transport.py,sha256=4gGHsq0WeY9VywEZXA3vUxykfiYnw9uuqfjAAec7F8o,1681
|
|
243
|
-
sourcecode/_docs/DEFECT-LEDGER.md,sha256=
|
|
243
|
+
sourcecode/_docs/DEFECT-LEDGER.md,sha256=KAUiNrCH5Az8129zeECJtgsv1C3CKngpoJuBzoM5uEA,742903
|
|
244
244
|
sourcecode/_docs/LICENSE,sha256=23-fk61oSWGVmkWyka-FIM0rhAPM2hcYHnsaridL8Uo,1859
|
|
245
245
|
sourcecode/_docs/NOTICE,sha256=Br-AA8Y3iJo1WXa5uP8QBpzqI5nDu3iGLbFyvDt3BOs,321
|
|
246
|
-
sourcecode/_docs/USER_GUIDE.md,sha256=
|
|
247
|
-
sourcecode-5.8.
|
|
248
|
-
sourcecode-5.8.
|
|
249
|
-
sourcecode-5.8.
|
|
250
|
-
sourcecode-5.8.
|
|
251
|
-
sourcecode-5.8.
|
|
252
|
-
sourcecode-5.8.
|
|
246
|
+
sourcecode/_docs/USER_GUIDE.md,sha256=yylOietj_jwPaOc_WQCkanFhoUV57HJBMDJBtA_g1jA,87303
|
|
247
|
+
sourcecode-5.8.13.dist-info/METADATA,sha256=TXvApuuSukNSBO_SAM-rgK7dS-yjXQcFpu4Ssj5FP50,51372
|
|
248
|
+
sourcecode-5.8.13.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
249
|
+
sourcecode-5.8.13.dist-info/entry_points.txt,sha256=-JEAdChrK5We51kZcb7OaDcyil-dHBjBPL-NhuO-QY8,89
|
|
250
|
+
sourcecode-5.8.13.dist-info/licenses/LICENSE,sha256=23-fk61oSWGVmkWyka-FIM0rhAPM2hcYHnsaridL8Uo,1859
|
|
251
|
+
sourcecode-5.8.13.dist-info/licenses/NOTICE,sha256=Br-AA8Y3iJo1WXa5uP8QBpzqI5nDu3iGLbFyvDt3BOs,321
|
|
252
|
+
sourcecode-5.8.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|