sourcecode 0.49.0__tar.gz → 1.0.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.
Files changed (150) hide show
  1. {sourcecode-0.49.0 → sourcecode-1.0.0}/PKG-INFO +1 -1
  2. {sourcecode-0.49.0 → sourcecode-1.0.0}/pyproject.toml +1 -1
  3. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/__init__.py +1 -1
  4. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/serializer.py +77 -39
  5. {sourcecode-0.49.0 → sourcecode-1.0.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
  6. {sourcecode-0.49.0 → sourcecode-1.0.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
  7. {sourcecode-0.49.0 → sourcecode-1.0.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
  8. {sourcecode-0.49.0 → sourcecode-1.0.0}/.gitignore +0 -0
  9. {sourcecode-0.49.0 → sourcecode-1.0.0}/.ruff.toml +0 -0
  10. {sourcecode-0.49.0 → sourcecode-1.0.0}/CONTRIBUTING.md +0 -0
  11. {sourcecode-0.49.0 → sourcecode-1.0.0}/LICENSE +0 -0
  12. {sourcecode-0.49.0 → sourcecode-1.0.0}/README.md +0 -0
  13. {sourcecode-0.49.0 → sourcecode-1.0.0}/SECURITY.md +0 -0
  14. {sourcecode-0.49.0 → sourcecode-1.0.0}/docs/privacy.md +0 -0
  15. {sourcecode-0.49.0 → sourcecode-1.0.0}/docs/schema.md +0 -0
  16. {sourcecode-0.49.0 → sourcecode-1.0.0}/raw +0 -0
  17. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/adaptive_scanner.py +0 -0
  18. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/architecture_analyzer.py +0 -0
  19. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/architecture_summary.py +0 -0
  20. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/ast_extractor.py +0 -0
  21. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/classifier.py +0 -0
  22. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/cli.py +0 -0
  23. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  24. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/confidence_analyzer.py +0 -0
  25. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/context_scorer.py +0 -0
  26. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/context_summarizer.py +0 -0
  27. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/contract_model.py +0 -0
  28. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/contract_pipeline.py +0 -0
  29. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/coverage_parser.py +0 -0
  30. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/dependency_analyzer.py +0 -0
  31. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/__init__.py +0 -0
  32. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/base.py +0 -0
  33. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  34. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/dart.py +0 -0
  35. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/dotnet.py +0 -0
  36. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/elixir.py +0 -0
  37. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/go.py +0 -0
  38. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/heuristic.py +0 -0
  39. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/hybrid.py +0 -0
  40. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/java.py +0 -0
  41. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  42. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/nodejs.py +0 -0
  43. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/parsers.py +0 -0
  44. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/php.py +0 -0
  45. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/project.py +0 -0
  46. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/python.py +0 -0
  47. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/ruby.py +0 -0
  48. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/rust.py +0 -0
  49. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/systems.py +0 -0
  50. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/terraform.py +0 -0
  51. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/detectors/tooling.py +0 -0
  52. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/doc_analyzer.py +0 -0
  53. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  54. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/env_analyzer.py +0 -0
  55. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/file_classifier.py +0 -0
  56. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/git_analyzer.py +0 -0
  57. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/graph_analyzer.py +0 -0
  58. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/metrics_analyzer.py +0 -0
  59. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/prepare_context.py +0 -0
  60. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/ranking_engine.py +0 -0
  61. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/redactor.py +0 -0
  62. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/relevance_scorer.py +0 -0
  63. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/repo_classifier.py +0 -0
  64. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/runtime_classifier.py +0 -0
  65. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/scanner.py +0 -0
  66. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/schema.py +0 -0
  67. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/semantic_analyzer.py +0 -0
  68. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/summarizer.py +0 -0
  69. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/telemetry/__init__.py +0 -0
  70. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/telemetry/config.py +0 -0
  71. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/telemetry/consent.py +0 -0
  72. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/telemetry/events.py +0 -0
  73. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/telemetry/filters.py +0 -0
  74. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/telemetry/transport.py +0 -0
  75. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/tree_utils.py +0 -0
  76. {sourcecode-0.49.0 → sourcecode-1.0.0}/src/sourcecode/workspace.py +0 -0
  77. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/__init__.py +0 -0
  78. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/conftest.py +0 -0
  79. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/coverage.xml +0 -0
  80. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  81. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
  82. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  83. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/go_service/go.mod +0 -0
  84. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/jacoco.xml +0 -0
  85. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/lcov.info +0 -0
  86. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  87. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/nextjs_app/package.json +0 -0
  88. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  89. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  90. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  91. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  92. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  93. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  94. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_architecture_analyzer.py +0 -0
  95. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_architecture_summary.py +0 -0
  96. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_ast_extractor.py +0 -0
  97. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_block1_reliability.py +0 -0
  98. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_block2_coverage.py +0 -0
  99. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_block5_quality.py +0 -0
  100. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_classifier.py +0 -0
  101. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_cli.py +0 -0
  102. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_code_notes_analyzer.py +0 -0
  103. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_context_scorer.py +0 -0
  104. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_contract_pipeline.py +0 -0
  105. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_coverage_parser.py +0 -0
  106. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_cross_consistency.py +0 -0
  107. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_dependency_analyzer_node_python.py +0 -0
  108. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
  109. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_dependency_schema.py +0 -0
  110. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_detector_dotnet.py +0 -0
  111. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_detector_go_rust_java.py +0 -0
  112. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_detector_nodejs.py +0 -0
  113. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_detector_php_ruby_dart.py +0 -0
  114. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_detector_python.py +0 -0
  115. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_detector_universal_managed.py +0 -0
  116. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_detector_universal_systems.py +0 -0
  117. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_detectors_base.py +0 -0
  118. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_doc_analyzer_jsdom.py +0 -0
  119. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_doc_analyzer_python.py +0 -0
  120. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_graph_analyzer_polyglot.py +0 -0
  121. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_graph_analyzer_python_node.py +0 -0
  122. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_graph_schema.py +0 -0
  123. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_hybrid_inference.py +0 -0
  124. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_integration.py +0 -0
  125. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_integration_dependencies.py +0 -0
  126. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_integration_detection.py +0 -0
  127. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_integration_docs.py +0 -0
  128. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_integration_graph_modules.py +0 -0
  129. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_integration_lqn.py +0 -0
  130. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_integration_metrics.py +0 -0
  131. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_integration_multistack.py +0 -0
  132. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_integration_semantics.py +0 -0
  133. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_integration_universal.py +0 -0
  134. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_metrics_analyzer.py +0 -0
  135. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_packaging.py +0 -0
  136. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_phase1_improvements.py +0 -0
  137. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_pipeline_integrity.py +0 -0
  138. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_real_projects.py +0 -0
  139. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_redactor.py +0 -0
  140. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_scanner.py +0 -0
  141. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_schema.py +0 -0
  142. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_schema_normalization.py +0 -0
  143. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_semantic_analyzer_node.py +0 -0
  144. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_semantic_analyzer_python.py +0 -0
  145. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_semantic_import_resolution.py +0 -0
  146. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_semantic_schema.py +0 -0
  147. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_signal_hierarchy.py +0 -0
  148. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_summarizer.py +0 -0
  149. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_telemetry.py +0 -0
  150. {sourcecode-0.49.0 → sourcecode-1.0.0}/tests/test_workspace_analyzer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 0.49.0
3
+ Version: 1.0.0
4
4
  Summary: Deterministic codebase context for AI coding agents
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "0.49.0"
7
+ version = "1.0.0"
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__ = "0.49.0"
3
+ __version__ = "1.0.0"
@@ -350,49 +350,72 @@ def _section_confidence(sm: SourceMap) -> dict[str, str]:
350
350
 
351
351
 
352
352
  def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
353
- """Context package ready for prompt or handoff (~600-800 tokens).
353
+ """Context package ready for prompt or handoff (~300-500 tokens).
354
354
 
355
355
  Answers: what it is, where it enters, what depends on what,
356
356
  what signals matter, and what uncertainty exists.
357
357
 
358
358
  Includes: project_type, project_summary, architecture_summary,
359
- stacks, entry_points, dependency_summary + key_dependencies (when analyzed),
359
+ stacks (minimal), entry_points (path+kind only), key_dependencies (name+version+role),
360
360
  env_summary (when analyzed), code_notes_summary (when analyzed),
361
- confidence_summary, anomalies, analysis_gaps.
361
+ confidence (overall only), analysis_gaps.
362
362
 
363
- Excludes: file_tree, raw dependency lists, docs, module_graph.
364
- Empty sections are explained when relevant.
363
+ Excludes: file_tree, raw dependency lists, docs, module_graph, verbose metadata.
365
364
  """
366
- dep_summary_dict: Any = None
365
+ # Key dependencies — name + version + role only (no ecosystem, source, manifests)
367
366
  key_deps: Any = None
368
367
  if sm.dependency_summary is not None and sm.dependency_summary.requested:
369
- dep_summary_dict = asdict(sm.dependency_summary)
370
- dep_summary_dict.pop("dependencies", None)
371
368
  key_deps = [
372
- asdict(d) for d in sm.key_dependencies
369
+ {
370
+ "name": d.name,
371
+ **({"version": d.declared_version} if d.declared_version else {}),
372
+ **({"role": d.role} if d.role and d.role != "runtime" else {}),
373
+ }
374
+ for d in sm.key_dependencies
373
375
  if (d.role or "unknown") in _PRODUCTION_DEP_ROLES and d.scope not in {"dev"}
374
376
  ][:_KEY_DEPS_CAP]
375
- elif sm.dependency_summary is None or not sm.dependency_summary.requested:
376
- dep_summary_dict = None # "not analyzed" — agent should add --dependencies
377
377
 
378
+ # Dependency summary — requested flag + count + source only
379
+ dep_summary_dict: Any = None
380
+ if sm.dependency_summary is not None and sm.dependency_summary.requested:
381
+ ds = sm.dependency_summary
382
+ dep_summary_dict = {
383
+ "requested": True,
384
+ "total_count": ds.total_count,
385
+ "direct": ds.direct_count,
386
+ **({"sources": ds.sources} if ds.sources else {}),
387
+ }
388
+
389
+ # Env map — key + required + category only (drop type_hint, files list)
378
390
  env_summary_dict: Any = None
379
391
  env_map_items: Any = None
380
392
  if sm.env_summary is not None and sm.env_summary.requested:
381
- env_summary_dict = asdict(sm.env_summary)
393
+ env_summary_dict = {
394
+ "total": sm.env_summary.total,
395
+ "required": sm.env_summary.required_count,
396
+ **({"categories": sm.env_summary.categories} if sm.env_summary.categories else {}),
397
+ }
382
398
  if sm.env_map:
383
399
  _sorted_env = sorted(
384
400
  sm.env_map,
385
401
  key=lambda e: (not getattr(e, "required", False), getattr(e, "key", "")),
386
402
  )
387
403
  env_map_items = [
388
- {k: v for k, v in asdict(e).items() if v is not None and v != "" and v != []}
404
+ {
405
+ "key": getattr(e, "key", ""),
406
+ **({"required": True} if getattr(e, "required", False) else {}),
407
+ **({"category": getattr(e, "category", None)} if getattr(e, "category", None) else {}),
408
+ }
389
409
  for e in _sorted_env[:_ENV_MAP_CAP]
390
410
  ]
391
411
 
412
+ # Code notes — kind + path + line + truncated text only
392
413
  code_notes_summary_dict: Any = None
393
414
  code_notes_items: Any = None
394
415
  if sm.code_notes_summary is not None and sm.code_notes_summary.requested:
395
- code_notes_summary_dict = asdict(sm.code_notes_summary)
416
+ cn = sm.code_notes_summary
417
+ by_kind = {k: v for k, v in cn.by_kind.items() if v > 0}
418
+ code_notes_summary_dict = {"total": cn.total, **({"by_kind": by_kind} if by_kind else {})}
396
419
  if sm.code_notes:
397
420
  _SEVERITY_ORDER = {"BUG": 0, "FIXME": 1, "DEPRECATED": 2, "TODO": 3, "HACK": 4, "WARNING": 5}
398
421
  _sorted_notes = sorted(
@@ -400,43 +423,62 @@ def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
400
423
  key=lambda n: (_SEVERITY_ORDER.get(getattr(n, "kind", "").upper(), 9), getattr(n, "path", "")),
401
424
  )
402
425
  code_notes_items = [
403
- {k: v for k, v in asdict(n).items() if v is not None}
426
+ {
427
+ "kind": getattr(n, "kind", ""),
428
+ "path": getattr(n, "path", ""),
429
+ "line": getattr(n, "line", None),
430
+ **({"text": getattr(n, "text", "")[:60]} if getattr(n, "text", "") else {}),
431
+ }
404
432
  for n in _sorted_notes[:_CODE_NOTES_CAP]
405
433
  ]
406
434
 
407
- # Entry points: production runtime only, capped.
408
- # Development entries shown separately; auxiliary omitted from compact view.
435
+ # Entry points path + kind + confidence only
409
436
  ep_groups = _entry_point_groups(sm.entry_points)
410
- entry_points_compact = ep_groups["production"][:_EP_PRODUCTION_CAP]
411
- if not entry_points_compact:
412
- entry_points_compact = [] # truth signal: no production runtime detected
437
+ entry_points_compact = [
438
+ {
439
+ "path": ep["path"],
440
+ **({"kind": ep["kind"]} if ep.get("kind") else {}),
441
+ **({"confidence": ep["confidence"]} if ep.get("confidence") else {}),
442
+ }
443
+ for ep in ep_groups["production"][:_EP_PRODUCTION_CAP]
444
+ ]
413
445
 
414
- # Confidence summary
446
+ # Stacks — name + method + confidence + frameworks (names only)
447
+ stacks_compact = [
448
+ {
449
+ "stack": s.stack,
450
+ "detection_method": s.detection_method,
451
+ "confidence": s.confidence,
452
+ **({"primary": True} if s.primary else {}),
453
+ **({"frameworks": [f.name for f in s.frameworks]} if s.frameworks else {}),
454
+ **({"package_manager": s.package_manager} if s.package_manager else {}),
455
+ }
456
+ for s in sm.stacks
457
+ ]
458
+
459
+ # Confidence — overall only + anomalies
415
460
  conf_dict: Any = None
416
- anomalies: Any = None
417
461
  if sm.confidence_summary is not None:
418
- conf_dict = asdict(sm.confidence_summary)
419
- if sm.confidence_summary.anomalies:
420
- anomalies = sm.confidence_summary.anomalies
462
+ cs = sm.confidence_summary
463
+ conf_dict = {"overall": cs.overall, "stack": cs.stack_confidence, "entry_points": cs.entry_point_confidence}
464
+ if cs.anomalies:
465
+ conf_dict["anomalies"] = cs.anomalies
421
466
 
422
467
  # Analysis gaps
423
468
  gaps_list: Any = None
424
469
  if sm.analysis_gaps:
425
- gaps_list = [asdict(g) for g in sm.analysis_gaps]
426
-
427
- context_summary_dict: Any = None
428
- if sm.context_summary is not None and sm.context_summary.requested:
429
- context_summary_dict = asdict(sm.context_summary)
470
+ gaps_list = [
471
+ {"area": g.area, "reason": g.reason, "impact": g.impact}
472
+ for g in sm.analysis_gaps
473
+ ]
430
474
 
431
475
  result: dict[str, Any] = {
432
476
  "schema_version": sm.metadata.schema_version,
433
477
  "project_type": sm.project_type,
434
478
  "project_summary": sm.project_summary,
435
479
  "architecture_summary": sm.architecture_summary,
436
- "context_summary": context_summary_dict,
437
- "stacks": [asdict(stack) for stack in sm.stacks],
480
+ "stacks": stacks_compact,
438
481
  "entry_points": entry_points_compact,
439
- "development_entry_points": (ep_groups["development"][:_EP_DEV_CAP] or None),
440
482
  "dependency_summary": dep_summary_dict,
441
483
  "key_dependencies": key_deps,
442
484
  "env_summary": env_summary_dict,
@@ -444,14 +486,10 @@ def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
444
486
  "code_notes_summary": code_notes_summary_dict,
445
487
  "code_notes": code_notes_items,
446
488
  "confidence_summary": conf_dict,
447
- "anomalies": anomalies,
448
489
  "analysis_gaps": gaps_list,
449
490
  }
450
- # Strip keys that are fully None and not informative
451
- return {k: v for k, v in result.items() if v is not None or k in (
452
- "project_type", "project_summary", "architecture_summary",
453
- "dependency_summary", "confidence_summary",
454
- )}
491
+ _always_include = {"project_type", "project_summary", "architecture_summary", "dependency_summary"}
492
+ return {k: v for k, v in result.items() if v is not None or k in _always_include}
455
493
 
456
494
 
457
495
  def normalize_source_map(sm: SourceMap) -> SourceMap:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes