scc-cli 1.4.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.
Potentially problematic release.
This version of scc-cli might be problematic. Click here for more details.
- scc_cli/__init__.py +15 -0
- scc_cli/audit/__init__.py +37 -0
- scc_cli/audit/parser.py +191 -0
- scc_cli/audit/reader.py +180 -0
- scc_cli/auth.py +145 -0
- scc_cli/claude_adapter.py +485 -0
- scc_cli/cli.py +259 -0
- scc_cli/cli_admin.py +706 -0
- scc_cli/cli_audit.py +245 -0
- scc_cli/cli_common.py +166 -0
- scc_cli/cli_config.py +527 -0
- scc_cli/cli_exceptions.py +705 -0
- scc_cli/cli_helpers.py +244 -0
- scc_cli/cli_init.py +272 -0
- scc_cli/cli_launch.py +1454 -0
- scc_cli/cli_org.py +1428 -0
- scc_cli/cli_support.py +322 -0
- scc_cli/cli_team.py +892 -0
- scc_cli/cli_worktree.py +865 -0
- scc_cli/config.py +583 -0
- scc_cli/console.py +562 -0
- scc_cli/constants.py +79 -0
- scc_cli/contexts.py +377 -0
- scc_cli/deprecation.py +54 -0
- scc_cli/deps.py +189 -0
- scc_cli/docker/__init__.py +127 -0
- scc_cli/docker/core.py +466 -0
- scc_cli/docker/credentials.py +726 -0
- scc_cli/docker/launch.py +604 -0
- scc_cli/doctor/__init__.py +99 -0
- scc_cli/doctor/checks.py +1074 -0
- scc_cli/doctor/render.py +346 -0
- scc_cli/doctor/types.py +66 -0
- scc_cli/errors.py +288 -0
- scc_cli/evaluation/__init__.py +27 -0
- scc_cli/evaluation/apply_exceptions.py +207 -0
- scc_cli/evaluation/evaluate.py +97 -0
- scc_cli/evaluation/models.py +80 -0
- scc_cli/exit_codes.py +55 -0
- scc_cli/git.py +1521 -0
- scc_cli/json_command.py +166 -0
- scc_cli/json_output.py +96 -0
- scc_cli/kinds.py +62 -0
- scc_cli/marketplace/__init__.py +123 -0
- scc_cli/marketplace/adapter.py +74 -0
- scc_cli/marketplace/compute.py +377 -0
- scc_cli/marketplace/constants.py +87 -0
- scc_cli/marketplace/managed.py +135 -0
- scc_cli/marketplace/materialize.py +723 -0
- scc_cli/marketplace/normalize.py +548 -0
- scc_cli/marketplace/render.py +257 -0
- scc_cli/marketplace/resolve.py +459 -0
- scc_cli/marketplace/schema.py +506 -0
- scc_cli/marketplace/sync.py +260 -0
- scc_cli/marketplace/team_cache.py +195 -0
- scc_cli/marketplace/team_fetch.py +688 -0
- scc_cli/marketplace/trust.py +244 -0
- scc_cli/models/__init__.py +41 -0
- scc_cli/models/exceptions.py +273 -0
- scc_cli/models/plugin_audit.py +434 -0
- scc_cli/org_templates.py +269 -0
- scc_cli/output_mode.py +167 -0
- scc_cli/panels.py +113 -0
- scc_cli/platform.py +350 -0
- scc_cli/profiles.py +960 -0
- scc_cli/remote.py +443 -0
- scc_cli/schemas/__init__.py +1 -0
- scc_cli/schemas/org-v1.schema.json +456 -0
- scc_cli/schemas/team-config.v1.schema.json +163 -0
- scc_cli/sessions.py +425 -0
- scc_cli/setup.py +588 -0
- scc_cli/source_resolver.py +470 -0
- scc_cli/stats.py +378 -0
- scc_cli/stores/__init__.py +13 -0
- scc_cli/stores/exception_store.py +251 -0
- scc_cli/subprocess_utils.py +88 -0
- scc_cli/teams.py +382 -0
- scc_cli/templates/__init__.py +2 -0
- scc_cli/templates/org/__init__.py +0 -0
- scc_cli/templates/org/minimal.json +19 -0
- scc_cli/templates/org/reference.json +74 -0
- scc_cli/templates/org/strict.json +38 -0
- scc_cli/templates/org/teams.json +42 -0
- scc_cli/templates/statusline.sh +75 -0
- scc_cli/theme.py +348 -0
- scc_cli/ui/__init__.py +124 -0
- scc_cli/ui/branding.py +68 -0
- scc_cli/ui/chrome.py +395 -0
- scc_cli/ui/dashboard/__init__.py +62 -0
- scc_cli/ui/dashboard/_dashboard.py +677 -0
- scc_cli/ui/dashboard/loaders.py +395 -0
- scc_cli/ui/dashboard/models.py +184 -0
- scc_cli/ui/dashboard/orchestrator.py +390 -0
- scc_cli/ui/formatters.py +443 -0
- scc_cli/ui/gate.py +350 -0
- scc_cli/ui/help.py +157 -0
- scc_cli/ui/keys.py +538 -0
- scc_cli/ui/list_screen.py +431 -0
- scc_cli/ui/picker.py +700 -0
- scc_cli/ui/prompts.py +200 -0
- scc_cli/ui/wizard.py +675 -0
- scc_cli/update.py +680 -0
- scc_cli/utils/__init__.py +39 -0
- scc_cli/utils/fixit.py +264 -0
- scc_cli/utils/fuzzy.py +124 -0
- scc_cli/utils/locks.py +101 -0
- scc_cli/utils/ttl.py +376 -0
- scc_cli/validate.py +455 -0
- scc_cli-1.4.1.dist-info/METADATA +369 -0
- scc_cli-1.4.1.dist-info/RECORD +113 -0
- scc_cli-1.4.1.dist-info/WHEEL +4 -0
- scc_cli-1.4.1.dist-info/entry_points.txt +2 -0
- scc_cli-1.4.1.dist-info/licenses/LICENSE +21 -0
scc_cli/ui/prompts.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Simple Rich-based prompts for CLI interactions.
|
|
2
|
+
|
|
3
|
+
This module provides straightforward prompt utilities for user input that don't
|
|
4
|
+
require full TUI screens. For more complex interactive pickers with keyboard
|
|
5
|
+
navigation, see picker.py and wizard.py.
|
|
6
|
+
|
|
7
|
+
Functions:
|
|
8
|
+
render_error: Display an SCCError with user-friendly formatting
|
|
9
|
+
select_session: Interactive session selection from a list
|
|
10
|
+
select_team: Interactive team selection menu
|
|
11
|
+
prompt_custom_workspace: Prompt for custom workspace path
|
|
12
|
+
prompt_repo_url: Prompt for Git repository URL
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import TYPE_CHECKING, Any
|
|
17
|
+
|
|
18
|
+
from rich import box
|
|
19
|
+
from rich.console import Console
|
|
20
|
+
from rich.panel import Panel
|
|
21
|
+
from rich.prompt import Confirm, IntPrompt, Prompt
|
|
22
|
+
from rich.table import Table
|
|
23
|
+
|
|
24
|
+
from scc_cli.theme import Borders, Colors
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from scc_cli.errors import SCCError
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def render_error(console: Console, error: "SCCError", debug: bool = False) -> None:
|
|
31
|
+
"""Render an error with user-friendly formatting.
|
|
32
|
+
|
|
33
|
+
Philosophy: "One message, one action"
|
|
34
|
+
- Display what went wrong (user_message)
|
|
35
|
+
- Display what to do next (suggested_action)
|
|
36
|
+
- Display debug info only if --debug flag is used
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
console: Rich console for output.
|
|
40
|
+
error: The SCCError to render.
|
|
41
|
+
debug: Whether to show debug context.
|
|
42
|
+
"""
|
|
43
|
+
lines = []
|
|
44
|
+
|
|
45
|
+
# Main error message
|
|
46
|
+
lines.append(f"[bold]{error.user_message}[/bold]")
|
|
47
|
+
|
|
48
|
+
# Suggested action (if available)
|
|
49
|
+
if error.suggested_action:
|
|
50
|
+
lines.append("")
|
|
51
|
+
lines.append(f"[{Colors.SECONDARY}]->[/{Colors.SECONDARY}] {error.suggested_action}")
|
|
52
|
+
|
|
53
|
+
# Debug context (only with --debug)
|
|
54
|
+
if debug and error.debug_context:
|
|
55
|
+
lines.append("")
|
|
56
|
+
lines.append(f"[{Colors.SECONDARY}]--- Debug Info ---[/{Colors.SECONDARY}]")
|
|
57
|
+
lines.append(f"[{Colors.SECONDARY}]{error.debug_context}[/{Colors.SECONDARY}]")
|
|
58
|
+
elif error.debug_context and not debug:
|
|
59
|
+
lines.append("")
|
|
60
|
+
lines.append(
|
|
61
|
+
f"[{Colors.SECONDARY}]Run with --debug for technical details[/{Colors.SECONDARY}]"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Create panel with error styling
|
|
65
|
+
panel = Panel(
|
|
66
|
+
"\n".join(lines),
|
|
67
|
+
title=f"[{Colors.ERROR_BOLD}]Error[/{Colors.ERROR_BOLD}]",
|
|
68
|
+
border_style=Borders.PANEL_ERROR,
|
|
69
|
+
padding=(0, 1),
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
console.print()
|
|
73
|
+
console.print(panel)
|
|
74
|
+
console.print()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def select_session(console: Console, sessions_list: list[dict[str, Any]]) -> dict[str, Any] | None:
|
|
78
|
+
"""Display an interactive session selection menu.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
console: Rich console for output.
|
|
82
|
+
sessions_list: List of session dicts with 'name', 'workspace', 'last_used', etc.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Selected session dict or None if cancelled.
|
|
86
|
+
"""
|
|
87
|
+
if not sessions_list:
|
|
88
|
+
console.print(f"[{Colors.WARNING}]No sessions available.[/{Colors.WARNING}]")
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
console.print(f"\n[{Colors.BRAND_BOLD}]Select a session:[/{Colors.BRAND_BOLD}]\n")
|
|
92
|
+
|
|
93
|
+
table = Table(box=box.SIMPLE, show_header=False, padding=(0, 2))
|
|
94
|
+
table.add_column("Option", style=Colors.WARNING, width=4)
|
|
95
|
+
table.add_column("Name", style=Colors.BRAND)
|
|
96
|
+
table.add_column("Workspace", style=Colors.PRIMARY)
|
|
97
|
+
table.add_column("Last Used", style=Colors.SECONDARY)
|
|
98
|
+
|
|
99
|
+
for i, session in enumerate(sessions_list, 1):
|
|
100
|
+
name = session.get("name", "-")
|
|
101
|
+
workspace = session.get("workspace", "-")
|
|
102
|
+
last_used = session.get("last_used", "-")
|
|
103
|
+
table.add_row(f"[{i}]", name, workspace, last_used)
|
|
104
|
+
|
|
105
|
+
table.add_row("[0]", "<- Cancel", "", "")
|
|
106
|
+
|
|
107
|
+
console.print(table)
|
|
108
|
+
|
|
109
|
+
valid_choices = [str(i) for i in range(0, len(sessions_list) + 1)]
|
|
110
|
+
choice = IntPrompt.ask(
|
|
111
|
+
f"\n[{Colors.BRAND}]Select session[/{Colors.BRAND}]",
|
|
112
|
+
default=1,
|
|
113
|
+
choices=valid_choices,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if choice == 0:
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
return sessions_list[choice - 1]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def select_team(console: Console, cfg: dict[str, Any]) -> str | None:
|
|
123
|
+
"""Display an interactive team selection menu and return the chosen team.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
console: Rich console for output.
|
|
127
|
+
cfg: Configuration dict containing 'profiles' key with team definitions.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Selected team name or None if no teams available.
|
|
131
|
+
"""
|
|
132
|
+
teams: dict[str, Any] = cfg.get("profiles", {})
|
|
133
|
+
team_list: list[str] = list(teams.keys())
|
|
134
|
+
|
|
135
|
+
if not team_list:
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
console.print(f"\n[{Colors.BRAND_BOLD}]Select your team:[/{Colors.BRAND_BOLD}]\n")
|
|
139
|
+
|
|
140
|
+
table = Table(box=box.SIMPLE, show_header=False, padding=(0, 2))
|
|
141
|
+
table.add_column("Option", style=Colors.WARNING, width=4)
|
|
142
|
+
table.add_column("Team", style=Colors.BRAND)
|
|
143
|
+
table.add_column("Description", style=Colors.PRIMARY)
|
|
144
|
+
|
|
145
|
+
for i, team_name in enumerate(team_list, 1):
|
|
146
|
+
team_info = teams[team_name]
|
|
147
|
+
desc = team_info.get("description", "")
|
|
148
|
+
table.add_row(f"[{i}]", team_name, desc)
|
|
149
|
+
|
|
150
|
+
console.print(table)
|
|
151
|
+
|
|
152
|
+
choice = IntPrompt.ask(
|
|
153
|
+
f"\n[{Colors.BRAND}]Select team[/{Colors.BRAND}]",
|
|
154
|
+
default=1,
|
|
155
|
+
choices=[str(i) for i in range(1, len(team_list) + 1)],
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
selected = team_list[choice - 1]
|
|
159
|
+
console.print(f"\n[{Colors.SUCCESS}]Selected: {selected}[/{Colors.SUCCESS}]")
|
|
160
|
+
|
|
161
|
+
return selected
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def prompt_custom_workspace(console: Console) -> str | None:
|
|
165
|
+
"""Prompt the user to enter a custom workspace path.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
console: Rich console for output.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Resolved absolute path string, or None if cancelled or path invalid.
|
|
172
|
+
"""
|
|
173
|
+
path = Prompt.ask(f"\n[{Colors.BRAND}]Enter workspace path[/{Colors.BRAND}]")
|
|
174
|
+
|
|
175
|
+
if not path:
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
expanded = Path(path).expanduser().resolve()
|
|
179
|
+
|
|
180
|
+
if not expanded.exists():
|
|
181
|
+
console.print(f"[{Colors.ERROR}]Path does not exist: {expanded}[/{Colors.ERROR}]")
|
|
182
|
+
if Confirm.ask(f"[{Colors.BRAND}]Create this directory?[/{Colors.BRAND}]", default=False):
|
|
183
|
+
expanded.mkdir(parents=True, exist_ok=True)
|
|
184
|
+
return str(expanded)
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
return str(expanded)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def prompt_repo_url(console: Console) -> str:
|
|
191
|
+
"""Prompt the user to enter a Git repository URL.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
console: Rich console for output.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
The entered URL string (may be empty if user pressed Enter).
|
|
198
|
+
"""
|
|
199
|
+
url = Prompt.ask(f"\n[{Colors.BRAND}]Repository URL (HTTPS or SSH)[/{Colors.BRAND}]")
|
|
200
|
+
return url
|