sourcecode 0.33.0__tar.gz → 0.34.0__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-0.33.0 → sourcecode-0.34.0}/PKG-INFO +1 -1
- {sourcecode-0.33.0 → sourcecode-0.34.0}/pyproject.toml +1 -1
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/ast_extractor.py +48 -3
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/cli.py +28 -9
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/relevance_scorer.py +40 -6
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/serializer.py +288 -53
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_ast_extractor.py +4 -2
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_contract_pipeline.py +17 -14
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration.py +9 -7
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_detection.py +4 -4
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_lqn.py +4 -3
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_metrics.py +2 -2
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_multistack.py +2 -2
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_universal.py +3 -3
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_pipeline_integrity.py +7 -7
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_real_projects.py +4 -4
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_signal_hierarchy.py +6 -6
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_summarizer.py +4 -4
- {sourcecode-0.33.0 → sourcecode-0.34.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/.gitignore +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/.ruff.toml +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/CONTRIBUTING.md +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/LICENSE +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/README.md +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/SECURITY.md +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/docs/privacy.md +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/docs/schema.md +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/raw +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/__init__.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/conftest.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/lcov.info +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_architecture_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_architecture_summary.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_classifier.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_cli.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_coverage_parser.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_cross_consistency.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_dependency_schema.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_nodejs.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_python.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detectors_base.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_graph_schema.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_docs.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_semantics.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_packaging.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_redactor.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_scanner.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_schema.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_schema_normalization.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_semantic_schema.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_telemetry.py +0 -0
- {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_workspace_analyzer.py +0 -0
|
@@ -13,6 +13,7 @@ Install tree-sitter for best TS/JS results:
|
|
|
13
13
|
|
|
14
14
|
import ast
|
|
15
15
|
import re
|
|
16
|
+
import sys
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
from typing import Any, Iterator, Optional
|
|
18
19
|
|
|
@@ -31,6 +32,45 @@ from sourcecode.contract_model import (
|
|
|
31
32
|
|
|
32
33
|
_MAX_FILE_SIZE = 200_000 # bytes — skip files larger than this
|
|
33
34
|
|
|
35
|
+
# Python stdlib module names — used to filter noise from import lists.
|
|
36
|
+
# sys.stdlib_module_names is available in Python 3.10+; fall back to a
|
|
37
|
+
# curated set for 3.9 compatibility.
|
|
38
|
+
if hasattr(sys, "stdlib_module_names"):
|
|
39
|
+
_PY_STDLIB: frozenset[str] = sys.stdlib_module_names # type: ignore[attr-defined]
|
|
40
|
+
else:
|
|
41
|
+
_PY_STDLIB: frozenset[str] = frozenset({ # type: ignore[no-redef]
|
|
42
|
+
"__future__", "_thread", "abc", "aifc", "argparse", "array", "ast",
|
|
43
|
+
"asynchat", "asyncio", "asyncore", "atexit", "audioop", "base64",
|
|
44
|
+
"bdb", "binascii", "binhex", "bisect", "builtins", "bz2", "calendar",
|
|
45
|
+
"cgi", "cgitb", "chunk", "cmath", "cmd", "code", "codecs", "codeop",
|
|
46
|
+
"collections", "colorsys", "compileall", "concurrent", "configparser",
|
|
47
|
+
"contextlib", "contextvars", "copy", "copyreg", "cProfile", "csv",
|
|
48
|
+
"ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal",
|
|
49
|
+
"difflib", "dis", "doctest", "email", "encodings", "enum", "errno",
|
|
50
|
+
"faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "fractions",
|
|
51
|
+
"ftplib", "functools", "gc", "getopt", "getpass", "gettext", "glob",
|
|
52
|
+
"grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "idlelib",
|
|
53
|
+
"imaplib", "importlib", "inspect", "io", "ipaddress", "itertools",
|
|
54
|
+
"json", "keyword", "lib2to3", "linecache", "locale", "logging", "lzma",
|
|
55
|
+
"mailbox", "marshal", "math", "mimetypes", "mmap", "modulefinder",
|
|
56
|
+
"multiprocessing", "netrc", "nntplib", "numbers", "operator", "optparse",
|
|
57
|
+
"os", "pathlib", "pdb", "pickle", "pickletools", "pipes", "pkgutil",
|
|
58
|
+
"platform", "plistlib", "poplib", "posix", "posixpath", "pprint",
|
|
59
|
+
"profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc",
|
|
60
|
+
"queue", "quopri", "random", "re", "readline", "reprlib", "resource",
|
|
61
|
+
"rlcompleter", "runpy", "sched", "secrets", "select", "selectors",
|
|
62
|
+
"shelve", "shlex", "shutil", "signal", "site", "smtpd", "smtplib",
|
|
63
|
+
"sndhdr", "socket", "socketserver", "sqlite3", "ssl", "stat",
|
|
64
|
+
"statistics", "string", "stringprep", "struct", "subprocess", "sunau",
|
|
65
|
+
"symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile",
|
|
66
|
+
"tempfile", "termios", "test", "textwrap", "threading", "time",
|
|
67
|
+
"timeit", "tkinter", "token", "tokenize", "tomllib", "trace",
|
|
68
|
+
"traceback", "tracemalloc", "tty", "types", "typing", "unicodedata",
|
|
69
|
+
"unittest", "urllib", "uuid", "venv", "warnings", "wave", "weakref",
|
|
70
|
+
"webbrowser", "wsgiref", "xml", "xmlrpc", "zipapp", "zipfile",
|
|
71
|
+
"zipimport", "zlib", "zoneinfo",
|
|
72
|
+
})
|
|
73
|
+
|
|
34
74
|
_LANGUAGE_MAP: dict[str, str] = {
|
|
35
75
|
".py": "python",
|
|
36
76
|
".ts": "typescript",
|
|
@@ -729,9 +769,10 @@ def _py_signature(node: ast.FunctionDef | ast.AsyncFunctionDef) -> str:
|
|
|
729
769
|
sig += f" -> {ast.unparse(node.returns)}"
|
|
730
770
|
except Exception:
|
|
731
771
|
pass
|
|
732
|
-
#
|
|
733
|
-
|
|
734
|
-
|
|
772
|
+
# Keep full signature — serializer applies per-mode compression.
|
|
773
|
+
# Hard cap at 2000 to prevent pathological cases.
|
|
774
|
+
if len(sig) > 2000:
|
|
775
|
+
sig = sig[:1997] + "..."
|
|
735
776
|
return sig
|
|
736
777
|
|
|
737
778
|
|
|
@@ -840,6 +881,10 @@ def _extract_python(path: str, source: str) -> FileContract:
|
|
|
840
881
|
if exported or name in all_names:
|
|
841
882
|
exports.append(ExportRecord(name=name, kind="class"))
|
|
842
883
|
|
|
884
|
+
# Filter stdlib from imports — they add noise without signal for agents
|
|
885
|
+
_stdlib_roots = {m.split(".")[0] for m in _PY_STDLIB}
|
|
886
|
+
imports = [i for i in imports if i.source.split(".")[0] not in _stdlib_roots]
|
|
887
|
+
|
|
843
888
|
deps = sorted({
|
|
844
889
|
imp.source.split(".")[0]
|
|
845
890
|
for imp in imports
|
|
@@ -516,11 +516,13 @@ def main(
|
|
|
516
516
|
"contract",
|
|
517
517
|
"--mode",
|
|
518
518
|
help=(
|
|
519
|
-
"Output mode: contract (default) | hybrid | raw. "
|
|
520
|
-
"contract: per-file
|
|
519
|
+
"Output mode: contract|minimal (default) | standard | deep | hybrid | raw. "
|
|
520
|
+
"contract/minimal: minimal per-file contracts — exports, signatures, deps. Smallest output. "
|
|
521
|
+
"standard: full per-file detail with imports, relevance scores, extraction method. "
|
|
522
|
+
"deep: standard + optional analysis sections (deps, env, git). "
|
|
521
523
|
"hybrid: contracts + compact bodies for top-ranked files. "
|
|
522
524
|
"raw: legacy project-level analysis (stacks, entry points, dependencies). "
|
|
523
|
-
"contract
|
|
525
|
+
"contract/minimal is the recommended default for AI coding agents."
|
|
524
526
|
),
|
|
525
527
|
),
|
|
526
528
|
max_symbols: Optional[int] = typer.Option(
|
|
@@ -587,7 +589,7 @@ def main(
|
|
|
587
589
|
_t0 = time.monotonic()
|
|
588
590
|
|
|
589
591
|
# Validate new flag choices
|
|
590
|
-
_MODE_CHOICES = ("contract", "hybrid", "raw")
|
|
592
|
+
_MODE_CHOICES = ("contract", "minimal", "standard", "deep", "hybrid", "raw")
|
|
591
593
|
if mode not in _MODE_CHOICES:
|
|
592
594
|
typer.echo(
|
|
593
595
|
f"Error: invalid value '{mode}' for --mode. Valid options: {', '.join(_MODE_CHOICES)}",
|
|
@@ -631,6 +633,13 @@ def main(
|
|
|
631
633
|
typer.echo(f"Error: '{target}' is not a directory.", err=True)
|
|
632
634
|
raise typer.Exit(code=1)
|
|
633
635
|
|
|
636
|
+
# Normalize mode aliases
|
|
637
|
+
_CONTRACT_MODES = frozenset({"contract", "minimal", "standard", "deep", "hybrid"})
|
|
638
|
+
if mode == "minimal":
|
|
639
|
+
mode = "contract" # minimal is the canonical default contract rendering
|
|
640
|
+
elif mode not in _CONTRACT_MODES and mode != "raw":
|
|
641
|
+
mode = "contract" # unknown → safe default
|
|
642
|
+
|
|
634
643
|
# Legacy flags imply raw mode unless --mode was explicitly overridden.
|
|
635
644
|
# These flags produce standard_view-only output sections not in contract_view.
|
|
636
645
|
# Preserves backward compat: callers using any legacy flag get their previous format.
|
|
@@ -639,9 +648,17 @@ def main(
|
|
|
639
648
|
compact or agent or tree or format == "yaml" or trace_pipeline
|
|
640
649
|
or docs or semantics or graph_modules or full_metrics or architecture
|
|
641
650
|
)
|
|
642
|
-
if mode
|
|
651
|
+
if mode in ("contract", "standard", "deep") and _legacy_flags_active:
|
|
643
652
|
mode = "raw"
|
|
644
653
|
|
|
654
|
+
# Map mode to contract_view depth
|
|
655
|
+
_CONTRACT_DEPTH = {
|
|
656
|
+
"contract": "minimal",
|
|
657
|
+
"standard": "standard",
|
|
658
|
+
"deep": "deep",
|
|
659
|
+
"hybrid": "minimal", # hybrid adds bodies via pipeline, minimal header
|
|
660
|
+
}
|
|
661
|
+
|
|
645
662
|
# --- Import analysis modules ---
|
|
646
663
|
from dataclasses import asdict, replace
|
|
647
664
|
|
|
@@ -1226,8 +1243,9 @@ def main(
|
|
|
1226
1243
|
))
|
|
1227
1244
|
sm = _replace(sm, pipeline_trace=_trace.build_trace())
|
|
1228
1245
|
|
|
1229
|
-
# Contract pipeline — runs for mode=contract|hybrid (skip for raw)
|
|
1230
|
-
|
|
1246
|
+
# Contract pipeline — runs for mode=contract|standard|deep|hybrid (skip for raw)
|
|
1247
|
+
_is_contract_mode = mode in ("contract", "standard", "deep", "hybrid")
|
|
1248
|
+
if _is_contract_mode:
|
|
1231
1249
|
from sourcecode.contract_pipeline import ContractPipeline
|
|
1232
1250
|
_cp = ContractPipeline()
|
|
1233
1251
|
_contracts, _contract_summary = _cp.run(
|
|
@@ -1249,9 +1267,10 @@ def main(
|
|
|
1249
1267
|
typer.echo(f"[contract] {len(_contracts)} files extracted ({_contract_summary.method_breakdown})", err=True)
|
|
1250
1268
|
|
|
1251
1269
|
# 4. Serialize
|
|
1252
|
-
if
|
|
1270
|
+
if _is_contract_mode:
|
|
1253
1271
|
from sourcecode.serializer import contract_view as _contract_view
|
|
1254
|
-
|
|
1272
|
+
_depth = _CONTRACT_DEPTH.get(mode, "minimal")
|
|
1273
|
+
data = _contract_view(sm, emit_graph=emit_graph, depth=_depth)
|
|
1255
1274
|
if not no_redact:
|
|
1256
1275
|
data = redact_dict(data)
|
|
1257
1276
|
content = json.dumps(data, indent=2, ensure_ascii=False)
|
|
@@ -82,8 +82,30 @@ _AUXILIARY_DIR_PATTERNS: list[re.Pattern[str]] = [
|
|
|
82
82
|
re.compile(r"(?:^|/)scripts?(?:/|$)"),
|
|
83
83
|
re.compile(r"(?:^|/)tools?(?:/|$)"),
|
|
84
84
|
re.compile(r"(?:^|/)ci(?:/|$)"),
|
|
85
|
+
re.compile(r"(?:^|/)migrations?(?:/|$)"),
|
|
86
|
+
re.compile(r"(?:^|/)generated?(?:/|$)"),
|
|
87
|
+
re.compile(r"(?:^|/)storybook(?:/|$)"),
|
|
88
|
+
re.compile(r"(?:^|/)stories(?:/|$)"),
|
|
85
89
|
]
|
|
86
90
|
|
|
91
|
+
# Test file patterns — scored low, excluded from default contract output
|
|
92
|
+
_TEST_FILE_PATTERNS: tuple[str, ...] = (
|
|
93
|
+
"_test.", ".test.", ".spec.", "test_", "conftest", "_spec.",
|
|
94
|
+
)
|
|
95
|
+
_TEST_DIR_MARKERS: frozenset[str] = frozenset({
|
|
96
|
+
"/test/", "/tests/", "/spec/", "/specs/", "/__tests__/", "/__mocks__/",
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
# Config/tooling filenames that are low runtime-relevance
|
|
100
|
+
_LOW_RUNTIME_STEMS: frozenset[str] = frozenset({
|
|
101
|
+
"setup", "setup.cfg", "pyproject", "package", "package-lock",
|
|
102
|
+
"yarn.lock", "pnpm-lock", "composer", "gemfile", "podfile",
|
|
103
|
+
"dockerfile", "docker-compose", "makefile", "rakefile",
|
|
104
|
+
"gruntfile", "gulpfile", "webpack.config", "vite.config",
|
|
105
|
+
"rollup.config", "babel.config", "jest.config", "vitest.config",
|
|
106
|
+
"tsconfig", "jsconfig", ".eslintrc", ".prettierrc", ".editorconfig",
|
|
107
|
+
})
|
|
108
|
+
|
|
87
109
|
_HIGH_VALUE_SUFFIXES: frozenset[str] = frozenset({
|
|
88
110
|
".py", ".ts", ".tsx", ".js", ".jsx", ".mjs",
|
|
89
111
|
".go", ".java", ".kt", ".rs", ".rb", ".cs",
|
|
@@ -114,7 +136,7 @@ class RelevanceScorer:
|
|
|
114
136
|
|
|
115
137
|
base = 0.3
|
|
116
138
|
|
|
117
|
-
# Package role boost
|
|
139
|
+
# Package role boost — runtime code scores high, tooling/docs low
|
|
118
140
|
role = self._package_role(norm)
|
|
119
141
|
role_boost = {
|
|
120
142
|
"runtime_core": 0.4,
|
|
@@ -124,10 +146,10 @@ class RelevanceScorer:
|
|
|
124
146
|
"composition_layer": 0.2,
|
|
125
147
|
"plugin_package": 0.15,
|
|
126
148
|
"infrastructure_layer": 0.15,
|
|
127
|
-
"tooling_layer": -0.
|
|
128
|
-
"docs_layer": -0.
|
|
129
|
-
"test_layer": 0.
|
|
130
|
-
"benchmark_layer": -0.
|
|
149
|
+
"tooling_layer": -0.15,
|
|
150
|
+
"docs_layer": -0.25,
|
|
151
|
+
"test_layer": -0.1,
|
|
152
|
+
"benchmark_layer": -0.25,
|
|
131
153
|
}.get(role, 0.0)
|
|
132
154
|
base += role_boost
|
|
133
155
|
|
|
@@ -141,7 +163,19 @@ class RelevanceScorer:
|
|
|
141
163
|
if stem in _ENTRYPOINT_STEMS:
|
|
142
164
|
base += 0.15
|
|
143
165
|
|
|
144
|
-
#
|
|
166
|
+
# Test file penalty — tests are useful for coverage but not for
|
|
167
|
+
# understanding architecture or editing production code
|
|
168
|
+
fname = Path(norm).name.lower()
|
|
169
|
+
if (any(m in f"/{norm}/" for m in _TEST_DIR_MARKERS)
|
|
170
|
+
or any(fname.startswith(p.strip(".")) or p in fname
|
|
171
|
+
for p in _TEST_FILE_PATTERNS)):
|
|
172
|
+
base -= 0.25
|
|
173
|
+
|
|
174
|
+
# Config/tooling filename penalty
|
|
175
|
+
if stem.lower() in _LOW_RUNTIME_STEMS:
|
|
176
|
+
base -= 0.2
|
|
177
|
+
|
|
178
|
+
# Auxiliary dir penalty
|
|
145
179
|
if self._is_auxiliary(norm):
|
|
146
180
|
base -= 0.2
|
|
147
181
|
|