scc-cli 1.4.0__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 +683 -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 +1400 -0
- scc_cli/cli_org.py +1433 -0
- scc_cli/cli_support.py +322 -0
- scc_cli/cli_team.py +858 -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 +603 -0
- scc_cli/doctor/__init__.py +99 -0
- scc_cli/doctor/checks.py +1082 -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 +1405 -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/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 +238 -0
- scc_cli/marketplace/resolve.py +459 -0
- scc_cli/marketplace/schema.py +502 -0
- scc_cli/marketplace/sync.py +257 -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 +1034 -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 +582 -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 +339 -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 +669 -0
- scc_cli/ui/dashboard/loaders.py +369 -0
- scc_cli/ui/dashboard/models.py +184 -0
- scc_cli/ui/dashboard/orchestrator.py +337 -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 +521 -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 +490 -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.0.dist-info/METADATA +369 -0
- scc_cli-1.4.0.dist-info/RECORD +112 -0
- scc_cli-1.4.0.dist-info/WHEEL +4 -0
- scc_cli-1.4.0.dist-info/entry_points.txt +2 -0
- scc_cli-1.4.0.dist-info/licenses/LICENSE +21 -0
scc_cli/cli.py
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
SCC - Sandboxed Claude CLI
|
|
4
|
+
|
|
5
|
+
A command-line tool for safely running Claude Code in Docker sandboxes
|
|
6
|
+
with team-specific configurations and worktree management.
|
|
7
|
+
|
|
8
|
+
This module serves as the thin orchestrator that composes commands from:
|
|
9
|
+
- cli_launch.py: Start command and interactive mode
|
|
10
|
+
- cli_worktree.py: Worktree, session, and container management
|
|
11
|
+
- cli_config.py: Teams, setup, and configuration commands
|
|
12
|
+
- cli_admin.py: Doctor, update, statusline, and stats commands
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from importlib.metadata import PackageNotFoundError
|
|
16
|
+
from importlib.metadata import version as get_installed_version
|
|
17
|
+
|
|
18
|
+
import typer
|
|
19
|
+
|
|
20
|
+
from .cli_admin import (
|
|
21
|
+
doctor_cmd,
|
|
22
|
+
stats_app,
|
|
23
|
+
status_cmd,
|
|
24
|
+
statusline_cmd,
|
|
25
|
+
update_cmd,
|
|
26
|
+
)
|
|
27
|
+
from .cli_audit import audit_app
|
|
28
|
+
from .cli_common import console, state
|
|
29
|
+
from .cli_config import (
|
|
30
|
+
config_cmd,
|
|
31
|
+
setup_cmd,
|
|
32
|
+
)
|
|
33
|
+
from .cli_exceptions import exceptions_app, unblock_cmd
|
|
34
|
+
from .cli_init import init_cmd
|
|
35
|
+
|
|
36
|
+
# Import command functions from domain modules
|
|
37
|
+
from .cli_launch import start
|
|
38
|
+
from .cli_org import org_app
|
|
39
|
+
from .cli_support import support_app
|
|
40
|
+
from .cli_team import team_app
|
|
41
|
+
from .cli_worktree import (
|
|
42
|
+
container_app,
|
|
43
|
+
context_app,
|
|
44
|
+
list_cmd,
|
|
45
|
+
prune_cmd,
|
|
46
|
+
session_app,
|
|
47
|
+
sessions_cmd,
|
|
48
|
+
stop_cmd,
|
|
49
|
+
worktree_app,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
53
|
+
# App Configuration
|
|
54
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
app = typer.Typer(
|
|
57
|
+
name="scc-cli",
|
|
58
|
+
help="Safely run Claude Code with team configurations and worktree management.",
|
|
59
|
+
no_args_is_help=False,
|
|
60
|
+
rich_markup_mode="rich",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
65
|
+
# Global Callback (--debug flag)
|
|
66
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@app.callback(invoke_without_command=True)
|
|
70
|
+
def main_callback(
|
|
71
|
+
ctx: typer.Context,
|
|
72
|
+
debug: bool = typer.Option(
|
|
73
|
+
False,
|
|
74
|
+
"--debug",
|
|
75
|
+
help="Show detailed error information for troubleshooting.",
|
|
76
|
+
is_eager=True,
|
|
77
|
+
),
|
|
78
|
+
version: bool = typer.Option(
|
|
79
|
+
False,
|
|
80
|
+
"--version",
|
|
81
|
+
"-v",
|
|
82
|
+
help="Show version and exit.",
|
|
83
|
+
is_eager=True,
|
|
84
|
+
),
|
|
85
|
+
interactive: bool = typer.Option(
|
|
86
|
+
False,
|
|
87
|
+
"-i",
|
|
88
|
+
"--interactive",
|
|
89
|
+
help="Force interactive workspace picker (shortcut for 'scc start -i').",
|
|
90
|
+
),
|
|
91
|
+
) -> None:
|
|
92
|
+
"""
|
|
93
|
+
[bold cyan]SCC[/bold cyan] - Sandboxed Claude CLI
|
|
94
|
+
|
|
95
|
+
Safely run Claude Code in Docker sandboxes with team configurations.
|
|
96
|
+
"""
|
|
97
|
+
state.debug = debug
|
|
98
|
+
|
|
99
|
+
if version:
|
|
100
|
+
from .ui.branding import get_version_header
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
pkg_version = get_installed_version("scc-cli")
|
|
104
|
+
except PackageNotFoundError:
|
|
105
|
+
pkg_version = "unknown"
|
|
106
|
+
console.print(get_version_header(pkg_version))
|
|
107
|
+
raise typer.Exit()
|
|
108
|
+
|
|
109
|
+
# If no command provided and not showing version, use context-aware routing
|
|
110
|
+
if ctx.invoked_subcommand is None:
|
|
111
|
+
from pathlib import Path
|
|
112
|
+
|
|
113
|
+
from .ui.gate import is_interactive_allowed
|
|
114
|
+
from .ui.wizard import _is_valid_workspace
|
|
115
|
+
|
|
116
|
+
# Context detection: check if CWD is a valid workspace
|
|
117
|
+
cwd = Path.cwd()
|
|
118
|
+
workspace_detected = _is_valid_workspace(cwd)
|
|
119
|
+
|
|
120
|
+
if is_interactive_allowed():
|
|
121
|
+
if interactive:
|
|
122
|
+
# -i flag: force interactive workspace picker via start -i
|
|
123
|
+
ctx.invoke(
|
|
124
|
+
start,
|
|
125
|
+
workspace=None,
|
|
126
|
+
team=None,
|
|
127
|
+
session_name=None,
|
|
128
|
+
resume=False,
|
|
129
|
+
select=False,
|
|
130
|
+
continue_session=False,
|
|
131
|
+
worktree_name=None,
|
|
132
|
+
fresh=False,
|
|
133
|
+
install_deps=False,
|
|
134
|
+
offline=False,
|
|
135
|
+
standalone=False,
|
|
136
|
+
dry_run=False,
|
|
137
|
+
json_output=False,
|
|
138
|
+
pretty=False,
|
|
139
|
+
)
|
|
140
|
+
elif workspace_detected:
|
|
141
|
+
# User is in a valid workspace → use smart start flow
|
|
142
|
+
# This shows Quick Resume (if sessions exist) or launches immediately
|
|
143
|
+
ctx.invoke(
|
|
144
|
+
start,
|
|
145
|
+
workspace=str(cwd),
|
|
146
|
+
team=None,
|
|
147
|
+
session_name=None,
|
|
148
|
+
resume=False,
|
|
149
|
+
select=False,
|
|
150
|
+
continue_session=False,
|
|
151
|
+
worktree_name=None,
|
|
152
|
+
fresh=False,
|
|
153
|
+
install_deps=False,
|
|
154
|
+
offline=False,
|
|
155
|
+
standalone=False,
|
|
156
|
+
dry_run=False,
|
|
157
|
+
json_output=False,
|
|
158
|
+
pretty=False,
|
|
159
|
+
)
|
|
160
|
+
else:
|
|
161
|
+
# No workspace context (e.g., $HOME) → show dashboard
|
|
162
|
+
from .ui.dashboard import run_dashboard
|
|
163
|
+
|
|
164
|
+
run_dashboard()
|
|
165
|
+
else:
|
|
166
|
+
# Non-interactive - invoke start with defaults
|
|
167
|
+
# NOTE: Must pass ALL defaults explicitly - ctx.invoke() doesn't resolve
|
|
168
|
+
# typer.Argument/Option defaults, it passes raw ArgumentInfo/OptionInfo
|
|
169
|
+
ctx.invoke(
|
|
170
|
+
start,
|
|
171
|
+
workspace=str(cwd) if workspace_detected else None,
|
|
172
|
+
team=None,
|
|
173
|
+
session_name=None,
|
|
174
|
+
resume=False,
|
|
175
|
+
select=False,
|
|
176
|
+
continue_session=False,
|
|
177
|
+
worktree_name=None,
|
|
178
|
+
fresh=False,
|
|
179
|
+
install_deps=False,
|
|
180
|
+
offline=False,
|
|
181
|
+
standalone=False,
|
|
182
|
+
dry_run=False,
|
|
183
|
+
json_output=False,
|
|
184
|
+
pretty=False,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
189
|
+
# Help Panel Group Names
|
|
190
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
PANEL_SESSION = "Session Management"
|
|
193
|
+
PANEL_WORKSPACE = "Workspace"
|
|
194
|
+
PANEL_CONFIG = "Configuration"
|
|
195
|
+
PANEL_ADMIN = "Administration"
|
|
196
|
+
PANEL_GOVERNANCE = "Governance"
|
|
197
|
+
|
|
198
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
199
|
+
# Register Commands from Domain Modules
|
|
200
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
201
|
+
|
|
202
|
+
# Launch commands
|
|
203
|
+
app.command(rich_help_panel=PANEL_SESSION)(start)
|
|
204
|
+
|
|
205
|
+
# Worktree command group
|
|
206
|
+
app.add_typer(worktree_app, name="worktree", rich_help_panel=PANEL_WORKSPACE)
|
|
207
|
+
|
|
208
|
+
# Session and container commands
|
|
209
|
+
app.command(name="sessions", rich_help_panel=PANEL_SESSION)(sessions_cmd)
|
|
210
|
+
app.command(name="list", rich_help_panel=PANEL_SESSION)(list_cmd)
|
|
211
|
+
app.command(name="stop", rich_help_panel=PANEL_SESSION)(stop_cmd)
|
|
212
|
+
app.command(name="prune", rich_help_panel=PANEL_SESSION)(prune_cmd)
|
|
213
|
+
|
|
214
|
+
# Configuration commands
|
|
215
|
+
app.add_typer(team_app, name="team", rich_help_panel=PANEL_CONFIG)
|
|
216
|
+
app.command(name="setup", rich_help_panel=PANEL_CONFIG)(setup_cmd)
|
|
217
|
+
app.command(name="config", rich_help_panel=PANEL_CONFIG)(config_cmd)
|
|
218
|
+
app.command(name="init", rich_help_panel=PANEL_CONFIG)(init_cmd)
|
|
219
|
+
|
|
220
|
+
# Admin commands
|
|
221
|
+
app.command(name="doctor", rich_help_panel=PANEL_ADMIN)(doctor_cmd)
|
|
222
|
+
app.command(name="update", rich_help_panel=PANEL_ADMIN)(update_cmd)
|
|
223
|
+
app.command(name="status", rich_help_panel=PANEL_ADMIN)(status_cmd)
|
|
224
|
+
app.command(name="statusline", rich_help_panel=PANEL_ADMIN)(statusline_cmd)
|
|
225
|
+
|
|
226
|
+
# Add stats sub-app
|
|
227
|
+
app.add_typer(stats_app, name="stats", rich_help_panel=PANEL_ADMIN)
|
|
228
|
+
|
|
229
|
+
# Exception management commands
|
|
230
|
+
app.add_typer(exceptions_app, name="exceptions", rich_help_panel=PANEL_GOVERNANCE)
|
|
231
|
+
app.command(name="unblock", rich_help_panel=PANEL_GOVERNANCE)(unblock_cmd)
|
|
232
|
+
|
|
233
|
+
# Audit commands
|
|
234
|
+
app.add_typer(audit_app, name="audit", rich_help_panel=PANEL_GOVERNANCE)
|
|
235
|
+
|
|
236
|
+
# Support commands
|
|
237
|
+
app.add_typer(support_app, name="support", rich_help_panel=PANEL_GOVERNANCE)
|
|
238
|
+
|
|
239
|
+
# Org admin commands
|
|
240
|
+
app.add_typer(org_app, name="org", rich_help_panel=PANEL_GOVERNANCE)
|
|
241
|
+
|
|
242
|
+
# Symmetric alias apps (Phase 8)
|
|
243
|
+
app.add_typer(session_app, name="session", rich_help_panel=PANEL_WORKSPACE)
|
|
244
|
+
app.add_typer(container_app, name="container", rich_help_panel=PANEL_WORKSPACE)
|
|
245
|
+
app.add_typer(context_app, name="context", rich_help_panel=PANEL_WORKSPACE)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
249
|
+
# Entry Point
|
|
250
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def main() -> None:
|
|
254
|
+
"""Entry point for the CLI."""
|
|
255
|
+
app()
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
if __name__ == "__main__":
|
|
259
|
+
main()
|