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.

Files changed (112) hide show
  1. scc_cli/__init__.py +15 -0
  2. scc_cli/audit/__init__.py +37 -0
  3. scc_cli/audit/parser.py +191 -0
  4. scc_cli/audit/reader.py +180 -0
  5. scc_cli/auth.py +145 -0
  6. scc_cli/claude_adapter.py +485 -0
  7. scc_cli/cli.py +259 -0
  8. scc_cli/cli_admin.py +683 -0
  9. scc_cli/cli_audit.py +245 -0
  10. scc_cli/cli_common.py +166 -0
  11. scc_cli/cli_config.py +527 -0
  12. scc_cli/cli_exceptions.py +705 -0
  13. scc_cli/cli_helpers.py +244 -0
  14. scc_cli/cli_init.py +272 -0
  15. scc_cli/cli_launch.py +1400 -0
  16. scc_cli/cli_org.py +1433 -0
  17. scc_cli/cli_support.py +322 -0
  18. scc_cli/cli_team.py +858 -0
  19. scc_cli/cli_worktree.py +865 -0
  20. scc_cli/config.py +583 -0
  21. scc_cli/console.py +562 -0
  22. scc_cli/constants.py +79 -0
  23. scc_cli/contexts.py +377 -0
  24. scc_cli/deprecation.py +54 -0
  25. scc_cli/deps.py +189 -0
  26. scc_cli/docker/__init__.py +127 -0
  27. scc_cli/docker/core.py +466 -0
  28. scc_cli/docker/credentials.py +726 -0
  29. scc_cli/docker/launch.py +603 -0
  30. scc_cli/doctor/__init__.py +99 -0
  31. scc_cli/doctor/checks.py +1082 -0
  32. scc_cli/doctor/render.py +346 -0
  33. scc_cli/doctor/types.py +66 -0
  34. scc_cli/errors.py +288 -0
  35. scc_cli/evaluation/__init__.py +27 -0
  36. scc_cli/evaluation/apply_exceptions.py +207 -0
  37. scc_cli/evaluation/evaluate.py +97 -0
  38. scc_cli/evaluation/models.py +80 -0
  39. scc_cli/exit_codes.py +55 -0
  40. scc_cli/git.py +1405 -0
  41. scc_cli/json_command.py +166 -0
  42. scc_cli/json_output.py +96 -0
  43. scc_cli/kinds.py +62 -0
  44. scc_cli/marketplace/__init__.py +123 -0
  45. scc_cli/marketplace/compute.py +377 -0
  46. scc_cli/marketplace/constants.py +87 -0
  47. scc_cli/marketplace/managed.py +135 -0
  48. scc_cli/marketplace/materialize.py +723 -0
  49. scc_cli/marketplace/normalize.py +548 -0
  50. scc_cli/marketplace/render.py +238 -0
  51. scc_cli/marketplace/resolve.py +459 -0
  52. scc_cli/marketplace/schema.py +502 -0
  53. scc_cli/marketplace/sync.py +257 -0
  54. scc_cli/marketplace/team_cache.py +195 -0
  55. scc_cli/marketplace/team_fetch.py +688 -0
  56. scc_cli/marketplace/trust.py +244 -0
  57. scc_cli/models/__init__.py +41 -0
  58. scc_cli/models/exceptions.py +273 -0
  59. scc_cli/models/plugin_audit.py +434 -0
  60. scc_cli/org_templates.py +269 -0
  61. scc_cli/output_mode.py +167 -0
  62. scc_cli/panels.py +113 -0
  63. scc_cli/platform.py +350 -0
  64. scc_cli/profiles.py +1034 -0
  65. scc_cli/remote.py +443 -0
  66. scc_cli/schemas/__init__.py +1 -0
  67. scc_cli/schemas/org-v1.schema.json +456 -0
  68. scc_cli/schemas/team-config.v1.schema.json +163 -0
  69. scc_cli/sessions.py +425 -0
  70. scc_cli/setup.py +582 -0
  71. scc_cli/source_resolver.py +470 -0
  72. scc_cli/stats.py +378 -0
  73. scc_cli/stores/__init__.py +13 -0
  74. scc_cli/stores/exception_store.py +251 -0
  75. scc_cli/subprocess_utils.py +88 -0
  76. scc_cli/teams.py +339 -0
  77. scc_cli/templates/__init__.py +2 -0
  78. scc_cli/templates/org/__init__.py +0 -0
  79. scc_cli/templates/org/minimal.json +19 -0
  80. scc_cli/templates/org/reference.json +74 -0
  81. scc_cli/templates/org/strict.json +38 -0
  82. scc_cli/templates/org/teams.json +42 -0
  83. scc_cli/templates/statusline.sh +75 -0
  84. scc_cli/theme.py +348 -0
  85. scc_cli/ui/__init__.py +124 -0
  86. scc_cli/ui/branding.py +68 -0
  87. scc_cli/ui/chrome.py +395 -0
  88. scc_cli/ui/dashboard/__init__.py +62 -0
  89. scc_cli/ui/dashboard/_dashboard.py +669 -0
  90. scc_cli/ui/dashboard/loaders.py +369 -0
  91. scc_cli/ui/dashboard/models.py +184 -0
  92. scc_cli/ui/dashboard/orchestrator.py +337 -0
  93. scc_cli/ui/formatters.py +443 -0
  94. scc_cli/ui/gate.py +350 -0
  95. scc_cli/ui/help.py +157 -0
  96. scc_cli/ui/keys.py +521 -0
  97. scc_cli/ui/list_screen.py +431 -0
  98. scc_cli/ui/picker.py +700 -0
  99. scc_cli/ui/prompts.py +200 -0
  100. scc_cli/ui/wizard.py +490 -0
  101. scc_cli/update.py +680 -0
  102. scc_cli/utils/__init__.py +39 -0
  103. scc_cli/utils/fixit.py +264 -0
  104. scc_cli/utils/fuzzy.py +124 -0
  105. scc_cli/utils/locks.py +101 -0
  106. scc_cli/utils/ttl.py +376 -0
  107. scc_cli/validate.py +455 -0
  108. scc_cli-1.4.0.dist-info/METADATA +369 -0
  109. scc_cli-1.4.0.dist-info/RECORD +112 -0
  110. scc_cli-1.4.0.dist-info/WHEEL +4 -0
  111. scc_cli-1.4.0.dist-info/entry_points.txt +2 -0
  112. 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()