raise-cli 2.2.1__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.
- raise_cli/__init__.py +38 -0
- raise_cli/__main__.py +30 -0
- raise_cli/adapters/__init__.py +91 -0
- raise_cli/adapters/declarative/__init__.py +26 -0
- raise_cli/adapters/declarative/adapter.py +267 -0
- raise_cli/adapters/declarative/discovery.py +94 -0
- raise_cli/adapters/declarative/expressions.py +150 -0
- raise_cli/adapters/declarative/reference/__init__.py +1 -0
- raise_cli/adapters/declarative/reference/github.yaml +143 -0
- raise_cli/adapters/declarative/schema.py +98 -0
- raise_cli/adapters/filesystem.py +299 -0
- raise_cli/adapters/mcp_bridge.py +10 -0
- raise_cli/adapters/mcp_confluence.py +246 -0
- raise_cli/adapters/mcp_jira.py +405 -0
- raise_cli/adapters/models.py +205 -0
- raise_cli/adapters/protocols.py +180 -0
- raise_cli/adapters/registry.py +90 -0
- raise_cli/adapters/sync.py +149 -0
- raise_cli/agents/__init__.py +14 -0
- raise_cli/agents/antigravity.yaml +8 -0
- raise_cli/agents/claude.yaml +8 -0
- raise_cli/agents/copilot.yaml +8 -0
- raise_cli/agents/copilot_plugin.py +124 -0
- raise_cli/agents/cursor.yaml +7 -0
- raise_cli/agents/roo.yaml +8 -0
- raise_cli/agents/windsurf.yaml +8 -0
- raise_cli/artifacts/__init__.py +30 -0
- raise_cli/artifacts/models.py +43 -0
- raise_cli/artifacts/reader.py +55 -0
- raise_cli/artifacts/renderer.py +104 -0
- raise_cli/artifacts/story_design.py +69 -0
- raise_cli/artifacts/writer.py +45 -0
- raise_cli/backlog/__init__.py +1 -0
- raise_cli/backlog/sync.py +115 -0
- raise_cli/cli/__init__.py +3 -0
- raise_cli/cli/commands/__init__.py +3 -0
- raise_cli/cli/commands/_resolve.py +153 -0
- raise_cli/cli/commands/adapters.py +362 -0
- raise_cli/cli/commands/artifact.py +137 -0
- raise_cli/cli/commands/backlog.py +333 -0
- raise_cli/cli/commands/base.py +31 -0
- raise_cli/cli/commands/discover.py +551 -0
- raise_cli/cli/commands/docs.py +130 -0
- raise_cli/cli/commands/doctor.py +177 -0
- raise_cli/cli/commands/gate.py +223 -0
- raise_cli/cli/commands/graph.py +1086 -0
- raise_cli/cli/commands/info.py +81 -0
- raise_cli/cli/commands/init.py +746 -0
- raise_cli/cli/commands/journal.py +167 -0
- raise_cli/cli/commands/mcp.py +524 -0
- raise_cli/cli/commands/memory.py +467 -0
- raise_cli/cli/commands/pattern.py +348 -0
- raise_cli/cli/commands/profile.py +59 -0
- raise_cli/cli/commands/publish.py +80 -0
- raise_cli/cli/commands/release.py +338 -0
- raise_cli/cli/commands/session.py +528 -0
- raise_cli/cli/commands/signal.py +410 -0
- raise_cli/cli/commands/skill.py +350 -0
- raise_cli/cli/commands/skill_set.py +145 -0
- raise_cli/cli/error_handler.py +158 -0
- raise_cli/cli/main.py +163 -0
- raise_cli/compat.py +66 -0
- raise_cli/config/__init__.py +41 -0
- raise_cli/config/agent_plugin.py +105 -0
- raise_cli/config/agent_registry.py +233 -0
- raise_cli/config/agents.py +120 -0
- raise_cli/config/ide.py +32 -0
- raise_cli/config/paths.py +379 -0
- raise_cli/config/settings.py +180 -0
- raise_cli/context/__init__.py +42 -0
- raise_cli/context/analyzers/__init__.py +16 -0
- raise_cli/context/analyzers/models.py +36 -0
- raise_cli/context/analyzers/protocol.py +43 -0
- raise_cli/context/analyzers/python.py +292 -0
- raise_cli/context/builder.py +1569 -0
- raise_cli/context/diff.py +213 -0
- raise_cli/context/extractors/__init__.py +13 -0
- raise_cli/context/extractors/skills.py +121 -0
- raise_cli/core/__init__.py +37 -0
- raise_cli/core/files.py +66 -0
- raise_cli/core/text.py +174 -0
- raise_cli/core/tools.py +441 -0
- raise_cli/discovery/__init__.py +50 -0
- raise_cli/discovery/analyzer.py +691 -0
- raise_cli/discovery/drift.py +355 -0
- raise_cli/discovery/scanner.py +1687 -0
- raise_cli/doctor/__init__.py +4 -0
- raise_cli/doctor/checks/__init__.py +1 -0
- raise_cli/doctor/checks/environment.py +110 -0
- raise_cli/doctor/checks/project.py +238 -0
- raise_cli/doctor/fix.py +80 -0
- raise_cli/doctor/models.py +56 -0
- raise_cli/doctor/protocol.py +43 -0
- raise_cli/doctor/registry.py +100 -0
- raise_cli/doctor/report.py +141 -0
- raise_cli/doctor/runner.py +95 -0
- raise_cli/engines/__init__.py +3 -0
- raise_cli/exceptions.py +215 -0
- raise_cli/gates/__init__.py +19 -0
- raise_cli/gates/builtin/__init__.py +1 -0
- raise_cli/gates/builtin/coverage.py +52 -0
- raise_cli/gates/builtin/lint.py +48 -0
- raise_cli/gates/builtin/tests.py +48 -0
- raise_cli/gates/builtin/types.py +48 -0
- raise_cli/gates/models.py +40 -0
- raise_cli/gates/protocol.py +41 -0
- raise_cli/gates/registry.py +141 -0
- raise_cli/governance/__init__.py +11 -0
- raise_cli/governance/extractor.py +412 -0
- raise_cli/governance/models.py +134 -0
- raise_cli/governance/parsers/__init__.py +35 -0
- raise_cli/governance/parsers/_convert.py +38 -0
- raise_cli/governance/parsers/adr.py +274 -0
- raise_cli/governance/parsers/backlog.py +356 -0
- raise_cli/governance/parsers/constitution.py +119 -0
- raise_cli/governance/parsers/epic.py +323 -0
- raise_cli/governance/parsers/glossary.py +316 -0
- raise_cli/governance/parsers/guardrails.py +345 -0
- raise_cli/governance/parsers/prd.py +112 -0
- raise_cli/governance/parsers/roadmap.py +118 -0
- raise_cli/governance/parsers/vision.py +116 -0
- raise_cli/graph/__init__.py +1 -0
- raise_cli/graph/backends/__init__.py +57 -0
- raise_cli/graph/backends/api.py +137 -0
- raise_cli/graph/backends/dual.py +139 -0
- raise_cli/graph/backends/pending.py +84 -0
- raise_cli/handlers/__init__.py +3 -0
- raise_cli/hooks/__init__.py +54 -0
- raise_cli/hooks/builtin/__init__.py +1 -0
- raise_cli/hooks/builtin/backlog.py +216 -0
- raise_cli/hooks/builtin/gate_bridge.py +83 -0
- raise_cli/hooks/builtin/jira_sync.py +127 -0
- raise_cli/hooks/builtin/memory.py +117 -0
- raise_cli/hooks/builtin/telemetry.py +72 -0
- raise_cli/hooks/emitter.py +184 -0
- raise_cli/hooks/events.py +262 -0
- raise_cli/hooks/protocol.py +38 -0
- raise_cli/hooks/registry.py +117 -0
- raise_cli/mcp/__init__.py +33 -0
- raise_cli/mcp/bridge.py +218 -0
- raise_cli/mcp/models.py +43 -0
- raise_cli/mcp/registry.py +77 -0
- raise_cli/mcp/schema.py +41 -0
- raise_cli/memory/__init__.py +58 -0
- raise_cli/memory/loader.py +247 -0
- raise_cli/memory/migration.py +241 -0
- raise_cli/memory/models.py +169 -0
- raise_cli/memory/writer.py +598 -0
- raise_cli/onboarding/__init__.py +103 -0
- raise_cli/onboarding/bootstrap.py +324 -0
- raise_cli/onboarding/claudemd.py +17 -0
- raise_cli/onboarding/conventions.py +742 -0
- raise_cli/onboarding/detection.py +374 -0
- raise_cli/onboarding/governance.py +443 -0
- raise_cli/onboarding/instructions.py +672 -0
- raise_cli/onboarding/manifest.py +201 -0
- raise_cli/onboarding/memory_md.py +399 -0
- raise_cli/onboarding/migration.py +207 -0
- raise_cli/onboarding/profile.py +624 -0
- raise_cli/onboarding/skill_conflict.py +100 -0
- raise_cli/onboarding/skill_manifest.py +176 -0
- raise_cli/onboarding/skills.py +437 -0
- raise_cli/onboarding/workflows.py +101 -0
- raise_cli/output/__init__.py +28 -0
- raise_cli/output/console.py +394 -0
- raise_cli/output/formatters/__init__.py +9 -0
- raise_cli/output/formatters/adapters.py +135 -0
- raise_cli/output/formatters/discover.py +439 -0
- raise_cli/output/formatters/skill.py +298 -0
- raise_cli/publish/__init__.py +3 -0
- raise_cli/publish/changelog.py +80 -0
- raise_cli/publish/check.py +179 -0
- raise_cli/publish/version.py +172 -0
- raise_cli/rai_base/__init__.py +22 -0
- raise_cli/rai_base/framework/__init__.py +7 -0
- raise_cli/rai_base/framework/methodology.yaml +233 -0
- raise_cli/rai_base/governance/__init__.py +1 -0
- raise_cli/rai_base/governance/architecture/__init__.py +1 -0
- raise_cli/rai_base/governance/architecture/domain-model.md +20 -0
- raise_cli/rai_base/governance/architecture/system-context.md +34 -0
- raise_cli/rai_base/governance/architecture/system-design.md +24 -0
- raise_cli/rai_base/governance/backlog.md +8 -0
- raise_cli/rai_base/governance/guardrails.md +17 -0
- raise_cli/rai_base/governance/prd.md +25 -0
- raise_cli/rai_base/governance/vision.md +16 -0
- raise_cli/rai_base/identity/__init__.py +8 -0
- raise_cli/rai_base/identity/core.md +119 -0
- raise_cli/rai_base/identity/perspective.md +119 -0
- raise_cli/rai_base/memory/__init__.py +7 -0
- raise_cli/rai_base/memory/patterns-base.jsonl +55 -0
- raise_cli/schemas/__init__.py +3 -0
- raise_cli/schemas/journal.py +49 -0
- raise_cli/schemas/session_state.py +117 -0
- raise_cli/session/__init__.py +5 -0
- raise_cli/session/bundle.py +820 -0
- raise_cli/session/close.py +268 -0
- raise_cli/session/journal.py +119 -0
- raise_cli/session/resolver.py +126 -0
- raise_cli/session/state.py +187 -0
- raise_cli/skills/__init__.py +44 -0
- raise_cli/skills/locator.py +141 -0
- raise_cli/skills/name_checker.py +199 -0
- raise_cli/skills/parser.py +145 -0
- raise_cli/skills/scaffold.py +212 -0
- raise_cli/skills/schema.py +132 -0
- raise_cli/skills/skillsets.py +195 -0
- raise_cli/skills/validator.py +197 -0
- raise_cli/skills_base/__init__.py +80 -0
- raise_cli/skills_base/contract-template.md +60 -0
- raise_cli/skills_base/preamble.md +37 -0
- raise_cli/skills_base/rai-architecture-review/SKILL.md +137 -0
- raise_cli/skills_base/rai-debug/SKILL.md +171 -0
- raise_cli/skills_base/rai-discover/SKILL.md +167 -0
- raise_cli/skills_base/rai-discover-document/SKILL.md +128 -0
- raise_cli/skills_base/rai-discover-scan/SKILL.md +147 -0
- raise_cli/skills_base/rai-discover-start/SKILL.md +145 -0
- raise_cli/skills_base/rai-discover-validate/SKILL.md +142 -0
- raise_cli/skills_base/rai-docs-update/SKILL.md +142 -0
- raise_cli/skills_base/rai-doctor/SKILL.md +120 -0
- raise_cli/skills_base/rai-epic-close/SKILL.md +165 -0
- raise_cli/skills_base/rai-epic-close/templates/retrospective.md +68 -0
- raise_cli/skills_base/rai-epic-design/SKILL.md +146 -0
- raise_cli/skills_base/rai-epic-design/templates/design.md +24 -0
- raise_cli/skills_base/rai-epic-design/templates/scope.md +76 -0
- raise_cli/skills_base/rai-epic-plan/SKILL.md +153 -0
- raise_cli/skills_base/rai-epic-plan/_references/sequencing-strategies.md +67 -0
- raise_cli/skills_base/rai-epic-plan/templates/plan-section.md +49 -0
- raise_cli/skills_base/rai-epic-run/SKILL.md +208 -0
- raise_cli/skills_base/rai-epic-start/SKILL.md +136 -0
- raise_cli/skills_base/rai-epic-start/templates/brief.md +34 -0
- raise_cli/skills_base/rai-mcp-add/SKILL.md +176 -0
- raise_cli/skills_base/rai-mcp-remove/SKILL.md +120 -0
- raise_cli/skills_base/rai-mcp-status/SKILL.md +147 -0
- raise_cli/skills_base/rai-problem-shape/SKILL.md +138 -0
- raise_cli/skills_base/rai-project-create/SKILL.md +144 -0
- raise_cli/skills_base/rai-project-onboard/SKILL.md +162 -0
- raise_cli/skills_base/rai-quality-review/SKILL.md +189 -0
- raise_cli/skills_base/rai-research/SKILL.md +143 -0
- raise_cli/skills_base/rai-research/references/research-prompt-template.md +317 -0
- raise_cli/skills_base/rai-session-close/SKILL.md +176 -0
- raise_cli/skills_base/rai-session-start/SKILL.md +110 -0
- raise_cli/skills_base/rai-story-close/SKILL.md +198 -0
- raise_cli/skills_base/rai-story-design/SKILL.md +203 -0
- raise_cli/skills_base/rai-story-design/references/tech-design-story-v2.md +293 -0
- raise_cli/skills_base/rai-story-implement/SKILL.md +115 -0
- raise_cli/skills_base/rai-story-plan/SKILL.md +135 -0
- raise_cli/skills_base/rai-story-review/SKILL.md +178 -0
- raise_cli/skills_base/rai-story-run/SKILL.md +282 -0
- raise_cli/skills_base/rai-story-start/SKILL.md +166 -0
- raise_cli/skills_base/rai-story-start/templates/story.md +38 -0
- raise_cli/skills_base/rai-welcome/SKILL.md +134 -0
- raise_cli/telemetry/__init__.py +42 -0
- raise_cli/telemetry/schemas.py +285 -0
- raise_cli/telemetry/writer.py +217 -0
- raise_cli/tier/__init__.py +0 -0
- raise_cli/tier/context.py +134 -0
- raise_cli/viz/__init__.py +7 -0
- raise_cli/viz/generator.py +406 -0
- raise_cli-2.2.1.dist-info/METADATA +433 -0
- raise_cli-2.2.1.dist-info/RECORD +264 -0
- raise_cli-2.2.1.dist-info/WHEEL +4 -0
- raise_cli-2.2.1.dist-info/entry_points.txt +40 -0
- raise_cli-2.2.1.dist-info/licenses/LICENSE +190 -0
- raise_cli-2.2.1.dist-info/licenses/NOTICE +4 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
"""Formatters for discovery command results.
|
|
2
|
+
|
|
3
|
+
Provides format-aware output for scan and drift results.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.table import Table
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from raise_cli.discovery.analyzer import AnalysisResult
|
|
17
|
+
from raise_cli.discovery.drift import DriftWarning
|
|
18
|
+
from raise_cli.discovery.scanner import ScanResult
|
|
19
|
+
|
|
20
|
+
# Module-level console for output
|
|
21
|
+
_console = Console()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def format_scan_result(
|
|
25
|
+
result: ScanResult,
|
|
26
|
+
path: Path,
|
|
27
|
+
output_format: str,
|
|
28
|
+
language: str | None = None,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Format and print scan results.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
result: Scan result containing symbols and metadata.
|
|
34
|
+
path: Path that was scanned.
|
|
35
|
+
output_format: Output format ("json", "summary", or "human").
|
|
36
|
+
language: Language filter used (for display).
|
|
37
|
+
"""
|
|
38
|
+
if output_format == "json":
|
|
39
|
+
_format_scan_json(result)
|
|
40
|
+
elif output_format == "summary":
|
|
41
|
+
_format_scan_summary(result, path, language)
|
|
42
|
+
else:
|
|
43
|
+
_format_scan_human(result, path)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _format_scan_json(result: ScanResult) -> None:
|
|
47
|
+
"""Format scan result as JSON."""
|
|
48
|
+
output_data = {
|
|
49
|
+
"files_scanned": result.files_scanned,
|
|
50
|
+
"symbols": [s.model_dump() for s in result.symbols],
|
|
51
|
+
"errors": result.errors,
|
|
52
|
+
}
|
|
53
|
+
_console.print_json(json.dumps(output_data))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _format_scan_summary(
|
|
57
|
+
result: ScanResult,
|
|
58
|
+
path: Path,
|
|
59
|
+
language: str | None,
|
|
60
|
+
) -> None:
|
|
61
|
+
"""Format scan result as summary statistics."""
|
|
62
|
+
classes = sum(1 for s in result.symbols if s.kind == "class")
|
|
63
|
+
functions = sum(1 for s in result.symbols if s.kind == "function")
|
|
64
|
+
methods = sum(1 for s in result.symbols if s.kind == "method")
|
|
65
|
+
modules = sum(1 for s in result.symbols if s.kind == "module")
|
|
66
|
+
interfaces = sum(1 for s in result.symbols if s.kind == "interface")
|
|
67
|
+
enums = sum(1 for s in result.symbols if s.kind == "enum")
|
|
68
|
+
type_aliases = sum(1 for s in result.symbols if s.kind == "type_alias")
|
|
69
|
+
constants = sum(1 for s in result.symbols if s.kind == "constant")
|
|
70
|
+
traits = sum(1 for s in result.symbols if s.kind == "trait")
|
|
71
|
+
components = sum(1 for s in result.symbols if s.kind == "component")
|
|
72
|
+
|
|
73
|
+
lang_str = f" ({language})" if language else " (auto-detect)"
|
|
74
|
+
_console.print(f"[bold]Scan Summary:[/bold] {path}{lang_str}")
|
|
75
|
+
_console.print(f" Files scanned: {result.files_scanned}")
|
|
76
|
+
_console.print(f" Symbols found: {len(result.symbols)}")
|
|
77
|
+
_console.print(f" - Classes: {classes}")
|
|
78
|
+
_console.print(f" - Functions: {functions}")
|
|
79
|
+
_console.print(f" - Methods: {methods}")
|
|
80
|
+
if interfaces > 0:
|
|
81
|
+
_console.print(f" - Interfaces: {interfaces}")
|
|
82
|
+
if enums > 0:
|
|
83
|
+
_console.print(f" - Enums: {enums}")
|
|
84
|
+
if type_aliases > 0:
|
|
85
|
+
_console.print(f" - Type aliases: {type_aliases}")
|
|
86
|
+
if constants > 0:
|
|
87
|
+
_console.print(f" - Constants: {constants}")
|
|
88
|
+
if traits > 0:
|
|
89
|
+
_console.print(f" - Traits: {traits}")
|
|
90
|
+
if components > 0:
|
|
91
|
+
_console.print(f" - Components: {components}")
|
|
92
|
+
if modules > 0:
|
|
93
|
+
_console.print(f" - Modules with docstrings: {modules}")
|
|
94
|
+
if result.errors:
|
|
95
|
+
_console.print(f" [yellow]Errors: {len(result.errors)}[/yellow]")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _format_scan_human(result: ScanResult, path: Path) -> None:
|
|
99
|
+
"""Format scan result as human-readable table."""
|
|
100
|
+
if not result.symbols:
|
|
101
|
+
_console.print(f"[yellow]No symbols found in {path}[/yellow]")
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
table = Table(title=f"Symbols in {path}")
|
|
105
|
+
table.add_column("Kind", style="cyan", width=10)
|
|
106
|
+
table.add_column("Name", style="green")
|
|
107
|
+
table.add_column("File", style="dim")
|
|
108
|
+
table.add_column("Line", justify="right", style="dim")
|
|
109
|
+
|
|
110
|
+
# Group by file for readability
|
|
111
|
+
symbols_by_file: dict[str, list[tuple[str, str, int]]] = {}
|
|
112
|
+
for s in result.symbols:
|
|
113
|
+
if s.file not in symbols_by_file:
|
|
114
|
+
symbols_by_file[s.file] = []
|
|
115
|
+
display_name = f" {s.name}" if s.parent else s.name
|
|
116
|
+
symbols_by_file[s.file].append((s.kind, display_name, s.line))
|
|
117
|
+
|
|
118
|
+
for file_path, symbols in sorted(symbols_by_file.items()):
|
|
119
|
+
for kind, name, line in sorted(symbols, key=lambda x: x[2]):
|
|
120
|
+
table.add_row(kind, name, file_path, str(line))
|
|
121
|
+
|
|
122
|
+
_console.print(table)
|
|
123
|
+
_console.print(
|
|
124
|
+
f"\n[dim]{result.files_scanned} files scanned, "
|
|
125
|
+
f"{len(result.symbols)} symbols found[/dim]"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
if result.errors:
|
|
129
|
+
_console.print(f"\n[yellow]Warnings ({len(result.errors)}):[/yellow]")
|
|
130
|
+
for error in result.errors[:5]:
|
|
131
|
+
_console.print(f" [dim]{error}[/dim]")
|
|
132
|
+
if len(result.errors) > 5:
|
|
133
|
+
_console.print(f" [dim]... and {len(result.errors) - 5} more[/dim]")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def format_drift_result(
|
|
137
|
+
warnings: list[DriftWarning],
|
|
138
|
+
files_scanned: int,
|
|
139
|
+
symbols_checked: int,
|
|
140
|
+
output_format: str,
|
|
141
|
+
) -> None:
|
|
142
|
+
"""Format and print drift detection results.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
warnings: List of drift warnings found.
|
|
146
|
+
files_scanned: Number of files scanned.
|
|
147
|
+
symbols_checked: Number of symbols checked.
|
|
148
|
+
output_format: Output format ("json", "summary", or "human").
|
|
149
|
+
"""
|
|
150
|
+
if output_format == "json":
|
|
151
|
+
_format_drift_json(warnings, files_scanned, symbols_checked)
|
|
152
|
+
elif output_format == "summary":
|
|
153
|
+
_format_drift_summary(warnings, files_scanned, symbols_checked)
|
|
154
|
+
else:
|
|
155
|
+
_format_drift_human(warnings, files_scanned, symbols_checked)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _format_drift_json(
|
|
159
|
+
warnings: list[DriftWarning],
|
|
160
|
+
files_scanned: int,
|
|
161
|
+
symbols_checked: int,
|
|
162
|
+
) -> None:
|
|
163
|
+
"""Format drift result as JSON."""
|
|
164
|
+
_console.print_json(
|
|
165
|
+
json.dumps(
|
|
166
|
+
{
|
|
167
|
+
"status": "drift" if warnings else "clean",
|
|
168
|
+
"warnings": [w.model_dump() for w in warnings],
|
|
169
|
+
"warning_count": len(warnings),
|
|
170
|
+
"files_scanned": files_scanned,
|
|
171
|
+
"symbols_checked": symbols_checked,
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _format_drift_summary(
|
|
178
|
+
warnings: list[DriftWarning],
|
|
179
|
+
files_scanned: int,
|
|
180
|
+
symbols_checked: int,
|
|
181
|
+
) -> None:
|
|
182
|
+
"""Format drift result as summary statistics."""
|
|
183
|
+
_console.print("[bold]Drift Detection Summary[/bold]")
|
|
184
|
+
_console.print(f" Files scanned: {files_scanned}")
|
|
185
|
+
_console.print(f" Symbols checked: {symbols_checked}")
|
|
186
|
+
_console.print(f" Warnings: {len(warnings)}")
|
|
187
|
+
if warnings:
|
|
188
|
+
by_severity: dict[str, int] = {}
|
|
189
|
+
for w in warnings:
|
|
190
|
+
by_severity[w.severity] = by_severity.get(w.severity, 0) + 1
|
|
191
|
+
for sev, count in sorted(by_severity.items()):
|
|
192
|
+
_console.print(f" - {sev}: {count}")
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _format_drift_human(
|
|
196
|
+
warnings: list[DriftWarning],
|
|
197
|
+
files_scanned: int,
|
|
198
|
+
symbols_checked: int,
|
|
199
|
+
) -> None:
|
|
200
|
+
"""Format drift result as human-readable output."""
|
|
201
|
+
if not warnings:
|
|
202
|
+
_console.print("[bold green]No drift detected[/bold green]")
|
|
203
|
+
_console.print(
|
|
204
|
+
f"[dim]Scanned {files_scanned} files, "
|
|
205
|
+
f"checked {symbols_checked} symbols[/dim]"
|
|
206
|
+
)
|
|
207
|
+
return
|
|
208
|
+
|
|
209
|
+
_console.print(
|
|
210
|
+
f"[bold yellow]Drift detected: {len(warnings)} warning(s)[/bold yellow]\n"
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
for warning in warnings:
|
|
214
|
+
severity_color = {
|
|
215
|
+
"error": "red",
|
|
216
|
+
"warning": "yellow",
|
|
217
|
+
"info": "blue",
|
|
218
|
+
}.get(warning.severity, "white")
|
|
219
|
+
|
|
220
|
+
_console.print(
|
|
221
|
+
f"[{severity_color}]{warning.severity.upper()}[/{severity_color}] "
|
|
222
|
+
f"[bold]{warning.file}[/bold]"
|
|
223
|
+
)
|
|
224
|
+
_console.print(f" {warning.issue}")
|
|
225
|
+
if warning.suggestion:
|
|
226
|
+
_console.print(f" [dim]Suggestion: {warning.suggestion}[/dim]")
|
|
227
|
+
_console.print()
|
|
228
|
+
|
|
229
|
+
_console.print(
|
|
230
|
+
f"[dim]Scanned {files_scanned} files, checked {symbols_checked} symbols[/dim]"
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def format_build_result(
|
|
235
|
+
input_path: Path,
|
|
236
|
+
graph_path: Path,
|
|
237
|
+
component_count: int,
|
|
238
|
+
components_in_graph: int,
|
|
239
|
+
node_count: int,
|
|
240
|
+
edge_count: int,
|
|
241
|
+
categories: dict[str, int],
|
|
242
|
+
sample_components: list[tuple[str, str, str]],
|
|
243
|
+
output_format: str,
|
|
244
|
+
) -> None:
|
|
245
|
+
"""Format and print discover build results.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
input_path: Path to the input components file.
|
|
249
|
+
graph_path: Path to the output graph file.
|
|
250
|
+
component_count: Number of components loaded from input.
|
|
251
|
+
components_in_graph: Number of component nodes in graph.
|
|
252
|
+
node_count: Total nodes in graph.
|
|
253
|
+
edge_count: Total edges in graph.
|
|
254
|
+
categories: Component counts by category.
|
|
255
|
+
sample_components: List of (name, kind, content_preview) tuples.
|
|
256
|
+
output_format: Output format ("json", "summary", or "human").
|
|
257
|
+
"""
|
|
258
|
+
if output_format == "json":
|
|
259
|
+
_format_build_json(
|
|
260
|
+
input_path,
|
|
261
|
+
graph_path,
|
|
262
|
+
component_count,
|
|
263
|
+
components_in_graph,
|
|
264
|
+
node_count,
|
|
265
|
+
edge_count,
|
|
266
|
+
)
|
|
267
|
+
elif output_format == "summary":
|
|
268
|
+
_format_build_summary(components_in_graph, node_count, edge_count)
|
|
269
|
+
else:
|
|
270
|
+
_format_build_human(
|
|
271
|
+
input_path,
|
|
272
|
+
graph_path,
|
|
273
|
+
components_in_graph,
|
|
274
|
+
node_count,
|
|
275
|
+
edge_count,
|
|
276
|
+
categories,
|
|
277
|
+
sample_components,
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _format_build_json(
|
|
282
|
+
input_path: Path,
|
|
283
|
+
graph_path: Path,
|
|
284
|
+
component_count: int,
|
|
285
|
+
components_in_graph: int,
|
|
286
|
+
node_count: int,
|
|
287
|
+
edge_count: int,
|
|
288
|
+
) -> None:
|
|
289
|
+
"""Format build result as JSON."""
|
|
290
|
+
output_data = {
|
|
291
|
+
"status": "success",
|
|
292
|
+
"input_file": str(input_path),
|
|
293
|
+
"graph_file": str(graph_path),
|
|
294
|
+
"components_loaded": component_count,
|
|
295
|
+
"components_in_graph": components_in_graph,
|
|
296
|
+
"total_nodes": node_count,
|
|
297
|
+
"total_edges": edge_count,
|
|
298
|
+
}
|
|
299
|
+
_console.print_json(json.dumps(output_data))
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _format_build_summary(
|
|
303
|
+
components_in_graph: int,
|
|
304
|
+
node_count: int,
|
|
305
|
+
edge_count: int,
|
|
306
|
+
) -> None:
|
|
307
|
+
"""Format build result as summary statistics."""
|
|
308
|
+
_console.print("[bold]Graph Build Summary[/bold]")
|
|
309
|
+
_console.print(f" Components loaded: {components_in_graph}")
|
|
310
|
+
_console.print(f" Total nodes: {node_count}")
|
|
311
|
+
_console.print(f" Total edges: {edge_count}")
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def _format_build_human(
|
|
315
|
+
input_path: Path,
|
|
316
|
+
graph_path: Path,
|
|
317
|
+
components_in_graph: int,
|
|
318
|
+
node_count: int,
|
|
319
|
+
edge_count: int,
|
|
320
|
+
categories: dict[str, int],
|
|
321
|
+
sample_components: list[tuple[str, str, str]],
|
|
322
|
+
) -> None:
|
|
323
|
+
"""Format build result as human-readable output."""
|
|
324
|
+
_console.print("[bold green]Graph built successfully[/bold green]\n")
|
|
325
|
+
_console.print(f"[bold]Input:[/bold] {input_path}")
|
|
326
|
+
_console.print(f"[bold]Output:[/bold] {graph_path}\n")
|
|
327
|
+
|
|
328
|
+
# Component summary
|
|
329
|
+
_console.print(f"[bold]Components:[/bold] {components_in_graph} loaded")
|
|
330
|
+
|
|
331
|
+
# Show by category if available
|
|
332
|
+
if categories:
|
|
333
|
+
_console.print("\n[bold]By Category:[/bold]")
|
|
334
|
+
for cat, count in sorted(categories.items()):
|
|
335
|
+
_console.print(f" {cat}: {count}")
|
|
336
|
+
|
|
337
|
+
# Graph totals
|
|
338
|
+
_console.print("\n[bold]Graph Totals:[/bold]")
|
|
339
|
+
_console.print(f" Nodes: {node_count}")
|
|
340
|
+
_console.print(f" Edges: {edge_count}")
|
|
341
|
+
|
|
342
|
+
# Sample components
|
|
343
|
+
if sample_components:
|
|
344
|
+
_console.print("\n[bold]Sample Components:[/bold]")
|
|
345
|
+
for name, kind, content in sample_components[:3]:
|
|
346
|
+
_console.print(f" [cyan]{name}[/cyan] ({kind}) — {content}...")
|
|
347
|
+
|
|
348
|
+
# Next steps
|
|
349
|
+
_console.print("\n[dim]Query components:[/dim]")
|
|
350
|
+
_console.print(' [dim]raise context query "keyword" --types component[/dim]')
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def format_analyze_result(
|
|
354
|
+
result: AnalysisResult,
|
|
355
|
+
output_format: str,
|
|
356
|
+
) -> None:
|
|
357
|
+
"""Format and print analysis results.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
result: Analysis result from the analyze pipeline.
|
|
361
|
+
output_format: Output format ("json", "summary", or "human").
|
|
362
|
+
"""
|
|
363
|
+
if output_format == "json":
|
|
364
|
+
_format_analyze_json(result)
|
|
365
|
+
elif output_format == "summary":
|
|
366
|
+
_format_analyze_summary(result)
|
|
367
|
+
else:
|
|
368
|
+
_format_analyze_human(result)
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _format_analyze_json(result: AnalysisResult) -> None:
|
|
372
|
+
"""Format analysis result as JSON."""
|
|
373
|
+
_console.print_json(json.dumps(result.model_dump(), default=str))
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _format_analyze_summary(result: AnalysisResult) -> None:
|
|
377
|
+
"""Format analysis result as summary statistics."""
|
|
378
|
+
summary = result.scan_summary
|
|
379
|
+
dist = result.confidence_distribution
|
|
380
|
+
total = sum(dist.values())
|
|
381
|
+
|
|
382
|
+
_console.print("[bold]Discovery Analysis Summary[/bold]")
|
|
383
|
+
_console.print(f" Files scanned: {summary.get('files_scanned', 0)}")
|
|
384
|
+
_console.print(
|
|
385
|
+
f" Symbols: {summary.get('total_symbols', 0)} "
|
|
386
|
+
f"({summary.get('public_symbols', 0)} public, "
|
|
387
|
+
f"{summary.get('internal_symbols', 0)} internal)"
|
|
388
|
+
)
|
|
389
|
+
_console.print(f" Components: {total}")
|
|
390
|
+
_console.print(f" High confidence: {dist.get('high', 0)}")
|
|
391
|
+
_console.print(f" Medium confidence: {dist.get('medium', 0)}")
|
|
392
|
+
_console.print(f" Low confidence: {dist.get('low', 0)}")
|
|
393
|
+
_console.print(f" Module groups: {len(result.module_groups)}")
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _format_analyze_human(result: AnalysisResult) -> None:
|
|
397
|
+
"""Format analysis result as human-readable output."""
|
|
398
|
+
summary = result.scan_summary
|
|
399
|
+
dist = result.confidence_distribution
|
|
400
|
+
total = sum(dist.values())
|
|
401
|
+
|
|
402
|
+
_console.print("[bold]Discovery Analysis[/bold]")
|
|
403
|
+
_console.print("=" * 40)
|
|
404
|
+
_console.print(
|
|
405
|
+
f"\nScanned: {summary.get('files_scanned', 0)} files, "
|
|
406
|
+
f"{summary.get('total_symbols', 0)} symbols "
|
|
407
|
+
f"({summary.get('public_symbols', 0)} public, "
|
|
408
|
+
f"{summary.get('internal_symbols', 0)} internal)"
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
# Confidence distribution
|
|
412
|
+
_console.print("\n[bold]Confidence Distribution:[/bold]")
|
|
413
|
+
if total > 0:
|
|
414
|
+
high = dist.get("high", 0)
|
|
415
|
+
med = dist.get("medium", 0)
|
|
416
|
+
low = dist.get("low", 0)
|
|
417
|
+
_console.print(
|
|
418
|
+
f" [green]High (auto-validate):[/green] {high} ({high * 100 // total}%)"
|
|
419
|
+
)
|
|
420
|
+
_console.print(
|
|
421
|
+
f" [yellow]Medium (batch review):[/yellow] {med} ({med * 100 // total}%)"
|
|
422
|
+
)
|
|
423
|
+
_console.print(
|
|
424
|
+
f" [red]Low (needs review):[/red] {low} ({low * 100 // total}%)"
|
|
425
|
+
)
|
|
426
|
+
else:
|
|
427
|
+
_console.print(" No components to analyze")
|
|
428
|
+
|
|
429
|
+
# Category breakdown
|
|
430
|
+
if result.categories:
|
|
431
|
+
_console.print("\n[bold]Category Breakdown:[/bold]")
|
|
432
|
+
for cat, count in sorted(result.categories.items(), key=lambda x: -x[1]):
|
|
433
|
+
_console.print(f" {cat}: {count}")
|
|
434
|
+
|
|
435
|
+
# Module groups
|
|
436
|
+
if result.module_groups:
|
|
437
|
+
_console.print(f"\n[bold]Module Groups:[/bold] {len(result.module_groups)}")
|
|
438
|
+
for module_path, comp_ids in sorted(result.module_groups.items()):
|
|
439
|
+
_console.print(f" {module_path} [{len(comp_ids)} components]")
|