tweek 0.3.1__py3-none-any.whl → 0.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.
- tweek/__init__.py +2 -2
- tweek/audit.py +2 -2
- tweek/cli.py +78 -6605
- tweek/cli_config.py +643 -0
- tweek/cli_configure.py +413 -0
- tweek/cli_core.py +718 -0
- tweek/cli_dry_run.py +390 -0
- tweek/cli_helpers.py +316 -0
- tweek/cli_install.py +1666 -0
- tweek/cli_logs.py +301 -0
- tweek/cli_mcp.py +148 -0
- tweek/cli_memory.py +343 -0
- tweek/cli_plugins.py +748 -0
- tweek/cli_protect.py +564 -0
- tweek/cli_proxy.py +405 -0
- tweek/cli_security.py +236 -0
- tweek/cli_skills.py +289 -0
- tweek/cli_uninstall.py +551 -0
- tweek/cli_vault.py +313 -0
- tweek/config/allowed_dirs.yaml +16 -17
- tweek/config/families.yaml +4 -1
- tweek/config/manager.py +17 -0
- tweek/config/patterns.yaml +29 -5
- tweek/config/templates/config.yaml.template +212 -0
- tweek/config/templates/env.template +45 -0
- tweek/config/templates/overrides.yaml.template +121 -0
- tweek/config/templates/tweek.yaml.template +20 -0
- tweek/config/templates.py +136 -0
- tweek/config/tiers.yaml +5 -4
- tweek/diagnostics.py +112 -32
- tweek/hooks/overrides.py +4 -0
- tweek/hooks/post_tool_use.py +46 -1
- tweek/hooks/pre_tool_use.py +149 -49
- tweek/integrations/openclaw.py +84 -0
- tweek/licensing.py +1 -1
- tweek/mcp/__init__.py +7 -9
- tweek/mcp/clients/chatgpt.py +2 -2
- tweek/mcp/clients/claude_desktop.py +2 -2
- tweek/mcp/clients/gemini.py +2 -2
- tweek/mcp/proxy.py +165 -1
- tweek/memory/provenance.py +438 -0
- tweek/memory/queries.py +2 -0
- tweek/memory/safety.py +23 -4
- tweek/memory/schemas.py +1 -0
- tweek/memory/store.py +101 -71
- tweek/plugins/screening/heuristic_scorer.py +1 -1
- tweek/security/integrity.py +77 -0
- tweek/security/llm_reviewer.py +170 -74
- tweek/security/local_reviewer.py +44 -2
- tweek/security/model_registry.py +73 -7
- tweek/skill_template/overrides-reference.md +1 -1
- tweek/skills/context.py +221 -0
- tweek/skills/scanner.py +2 -2
- {tweek-0.3.1.dist-info → tweek-0.4.1.dist-info}/METADATA +8 -7
- {tweek-0.3.1.dist-info → tweek-0.4.1.dist-info}/RECORD +60 -38
- tweek/mcp/server.py +0 -320
- {tweek-0.3.1.dist-info → tweek-0.4.1.dist-info}/WHEEL +0 -0
- {tweek-0.3.1.dist-info → tweek-0.4.1.dist-info}/entry_points.txt +0 -0
- {tweek-0.3.1.dist-info → tweek-0.4.1.dist-info}/licenses/LICENSE +0 -0
- {tweek-0.3.1.dist-info → tweek-0.4.1.dist-info}/licenses/NOTICE +0 -0
- {tweek-0.3.1.dist-info → tweek-0.4.1.dist-info}/top_level.txt +0 -0
tweek/cli_configure.py
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Tweek CLI Configure Command
|
|
4
|
+
|
|
5
|
+
Post-install configuration for Tweek components that are not required
|
|
6
|
+
during the initial quick install. Each subcommand handles one aspect
|
|
7
|
+
of configuration independently.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
tweek configure Show available configuration options
|
|
11
|
+
tweek configure llm Configure LLM review provider
|
|
12
|
+
tweek configure preset Change security preset
|
|
13
|
+
tweek configure vault Scan .env files and migrate to vault
|
|
14
|
+
tweek configure proxy Set up proxy for OpenClaw or other tools
|
|
15
|
+
tweek configure mcp Protect MCP-capable AI tools
|
|
16
|
+
tweek configure sandbox Set up Linux sandbox (firejail)
|
|
17
|
+
tweek configure wizard Run the full interactive setup wizard
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import click
|
|
22
|
+
|
|
23
|
+
from tweek.cli_helpers import console, print_success, print_warning
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@click.group()
|
|
27
|
+
def configure():
|
|
28
|
+
"""Configure Tweek components after installation.
|
|
29
|
+
|
|
30
|
+
Run 'tweek configure' to see available options. Each subcommand
|
|
31
|
+
handles one aspect of configuration independently.
|
|
32
|
+
"""
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# tweek configure llm
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
@configure.command()
|
|
41
|
+
def llm():
|
|
42
|
+
"""Configure the LLM review provider for semantic analysis.
|
|
43
|
+
|
|
44
|
+
Sets up the cloud or local LLM used for Layer 3 security screening.
|
|
45
|
+
Supports Anthropic, OpenAI, Google, xAI, or any OpenAI-compatible endpoint.
|
|
46
|
+
"""
|
|
47
|
+
from pathlib import Path
|
|
48
|
+
|
|
49
|
+
tweek_dir = Path("~/.tweek").expanduser()
|
|
50
|
+
tweek_dir.mkdir(parents=True, exist_ok=True)
|
|
51
|
+
|
|
52
|
+
from tweek.cli_install import _configure_llm_provider
|
|
53
|
+
result = _configure_llm_provider(tweek_dir, interactive=True, quick=False)
|
|
54
|
+
|
|
55
|
+
if result.get("provider_display"):
|
|
56
|
+
console.print()
|
|
57
|
+
print_success(f"LLM provider: {result['provider_display']}")
|
|
58
|
+
if result.get("model_display"):
|
|
59
|
+
console.print(f" Model: {result['model_display']}")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
# tweek configure preset
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
@configure.command()
|
|
67
|
+
@click.argument("name", required=False,
|
|
68
|
+
type=click.Choice(["paranoid", "cautious", "balanced", "trusted"]))
|
|
69
|
+
def preset(name):
|
|
70
|
+
"""Change the security preset.
|
|
71
|
+
|
|
72
|
+
Presets control tool security tiers and enforcement thresholds.
|
|
73
|
+
|
|
74
|
+
\b
|
|
75
|
+
Presets:
|
|
76
|
+
paranoid Maximum security, prompt on everything
|
|
77
|
+
balanced Smart defaults with provenance tracking (recommended)
|
|
78
|
+
cautious Prompt on risky operations
|
|
79
|
+
trusted Minimal prompts, trust AI decisions
|
|
80
|
+
"""
|
|
81
|
+
from tweek.config.manager import ConfigManager
|
|
82
|
+
|
|
83
|
+
cfg = ConfigManager()
|
|
84
|
+
|
|
85
|
+
if name is None:
|
|
86
|
+
# Interactive selection
|
|
87
|
+
console.print("[bold]Security Presets[/bold]")
|
|
88
|
+
console.print()
|
|
89
|
+
console.print(" [cyan]1.[/cyan] paranoid \u2014 Maximum security, prompt on everything")
|
|
90
|
+
console.print(" [cyan]2.[/cyan] balanced \u2014 Smart defaults with provenance tracking [green](recommended)[/green]")
|
|
91
|
+
console.print(" [cyan]3.[/cyan] cautious \u2014 Prompt on risky operations")
|
|
92
|
+
console.print(" [cyan]4.[/cyan] trusted \u2014 Minimal prompts, trust AI decisions")
|
|
93
|
+
console.print()
|
|
94
|
+
|
|
95
|
+
choice = click.prompt("Select preset", type=click.IntRange(1, 4), default=2)
|
|
96
|
+
name = {1: "paranoid", 2: "balanced", 3: "cautious", 4: "trusted"}[choice]
|
|
97
|
+
|
|
98
|
+
cfg.apply_preset(name)
|
|
99
|
+
print_success(f"Applied {name} preset")
|
|
100
|
+
if name == "balanced":
|
|
101
|
+
console.print("[white] Clean sessions get fewer prompts; tainted sessions get extra scrutiny[/white]")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# ---------------------------------------------------------------------------
|
|
105
|
+
# tweek configure vault
|
|
106
|
+
# ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
@configure.command()
|
|
109
|
+
@click.option("--dry-run", is_flag=True, help="Show what would be migrated without making changes")
|
|
110
|
+
def vault(dry_run):
|
|
111
|
+
"""Scan for .env files and migrate credentials to the secure vault.
|
|
112
|
+
|
|
113
|
+
Finds .env files in common locations, identifies credential keys,
|
|
114
|
+
and offers to migrate them to the system keychain.
|
|
115
|
+
"""
|
|
116
|
+
from tweek.cli_install import scan_for_env_files
|
|
117
|
+
from rich.table import Table
|
|
118
|
+
|
|
119
|
+
console.print("[cyan]Scanning for .env files with credentials...[/cyan]\n")
|
|
120
|
+
|
|
121
|
+
env_files = scan_for_env_files()
|
|
122
|
+
|
|
123
|
+
if not env_files:
|
|
124
|
+
console.print("[white]No .env files with credentials found.[/white]")
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
table = Table(title="Found .env Files")
|
|
128
|
+
table.add_column("#", style="white")
|
|
129
|
+
table.add_column("Path")
|
|
130
|
+
table.add_column("Credentials", justify="right")
|
|
131
|
+
|
|
132
|
+
for i, (path, keys) in enumerate(env_files, 1):
|
|
133
|
+
from pathlib import Path as P
|
|
134
|
+
try:
|
|
135
|
+
display_path = path.relative_to(P.cwd())
|
|
136
|
+
except ValueError:
|
|
137
|
+
display_path = path
|
|
138
|
+
table.add_row(str(i), str(display_path), str(len(keys)))
|
|
139
|
+
|
|
140
|
+
console.print(table)
|
|
141
|
+
|
|
142
|
+
if dry_run:
|
|
143
|
+
console.print("\n[white]Dry run \u2014 no changes made.[/white]")
|
|
144
|
+
for path, keys in env_files:
|
|
145
|
+
console.print(f"\n {path}:")
|
|
146
|
+
for key in keys:
|
|
147
|
+
console.print(f" \u2022 {key}")
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
# Interactive migration
|
|
151
|
+
console.print("\n[yellow]Migrate these credentials to secure storage?[/yellow]")
|
|
152
|
+
if not click.confirm("Proceed?"):
|
|
153
|
+
console.print("[white]Skipped.[/white]")
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
from tweek.vault import get_vault, VAULT_AVAILABLE
|
|
158
|
+
if not VAULT_AVAILABLE:
|
|
159
|
+
print_warning("Vault not available. Install keyring: pip install keyring")
|
|
160
|
+
return
|
|
161
|
+
vault_store = get_vault()
|
|
162
|
+
except ImportError:
|
|
163
|
+
print_warning("Vault module not available.")
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
for path, keys in env_files:
|
|
167
|
+
from pathlib import Path as P
|
|
168
|
+
try:
|
|
169
|
+
display_path = path.relative_to(P.cwd())
|
|
170
|
+
except ValueError:
|
|
171
|
+
display_path = path
|
|
172
|
+
|
|
173
|
+
console.print(f"\n[cyan]{display_path}[/cyan]")
|
|
174
|
+
|
|
175
|
+
suggested_skill = path.parent.name
|
|
176
|
+
if suggested_skill in (".", "", "~"):
|
|
177
|
+
suggested_skill = "default"
|
|
178
|
+
|
|
179
|
+
skill = click.prompt(" Skill name", default=suggested_skill)
|
|
180
|
+
|
|
181
|
+
console.print(f" [white]Credentials to migrate:[/white]")
|
|
182
|
+
for key in keys:
|
|
183
|
+
console.print(f" \u2022 {key}")
|
|
184
|
+
|
|
185
|
+
if click.confirm(f" Migrate {len(keys)} credentials to '{skill}'?"):
|
|
186
|
+
try:
|
|
187
|
+
from tweek.vault import migrate_env_to_vault
|
|
188
|
+
results = migrate_env_to_vault(path, skill, vault_store, dry_run=False)
|
|
189
|
+
successful = sum(1 for _, s in results if s)
|
|
190
|
+
print_success(f"Migrated {successful}/{len(results)} credentials")
|
|
191
|
+
except Exception as e:
|
|
192
|
+
print_warning(f"Migration failed: {e}")
|
|
193
|
+
else:
|
|
194
|
+
console.print(" [white]Skipped[/white]")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# ---------------------------------------------------------------------------
|
|
198
|
+
# tweek configure proxy
|
|
199
|
+
# ---------------------------------------------------------------------------
|
|
200
|
+
|
|
201
|
+
@configure.command()
|
|
202
|
+
@click.option("--force", is_flag=True, help="Force proxy to override existing configurations")
|
|
203
|
+
def proxy(force):
|
|
204
|
+
"""Set up Tweek proxy for OpenClaw or other API interceptors.
|
|
205
|
+
|
|
206
|
+
Detects OpenClaw and other proxy configurations, then offers to
|
|
207
|
+
set up Tweek as a security layer.
|
|
208
|
+
"""
|
|
209
|
+
try:
|
|
210
|
+
from tweek.proxy import detect_proxy_conflicts, get_openclaw_status
|
|
211
|
+
except ImportError:
|
|
212
|
+
print_warning("Proxy module not available.")
|
|
213
|
+
return
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
openclaw_status = get_openclaw_status()
|
|
217
|
+
except Exception as e:
|
|
218
|
+
print_warning(f"Could not check OpenClaw status: {e}")
|
|
219
|
+
return
|
|
220
|
+
|
|
221
|
+
if openclaw_status["installed"]:
|
|
222
|
+
console.print("[green]\u2713[/green] OpenClaw detected")
|
|
223
|
+
if openclaw_status["gateway_active"]:
|
|
224
|
+
console.print(f" Gateway running on port {openclaw_status['port']}")
|
|
225
|
+
elif openclaw_status["running"]:
|
|
226
|
+
console.print(f" Process running (port {openclaw_status['port']})")
|
|
227
|
+
else:
|
|
228
|
+
console.print(" Installed but not currently running")
|
|
229
|
+
console.print()
|
|
230
|
+
|
|
231
|
+
if force or click.confirm("Configure Tweek to protect OpenClaw?", default=True):
|
|
232
|
+
_apply_proxy_config(force=True)
|
|
233
|
+
else:
|
|
234
|
+
console.print("[white]Skipped. Run 'tweek protect openclaw' later.[/white]")
|
|
235
|
+
else:
|
|
236
|
+
console.print("[white]OpenClaw not detected on this system.[/white]")
|
|
237
|
+
|
|
238
|
+
# Check for other proxy conflicts
|
|
239
|
+
try:
|
|
240
|
+
conflicts = detect_proxy_conflicts()
|
|
241
|
+
non_openclaw = [c for c in conflicts if c.tool_name != "openclaw"]
|
|
242
|
+
if non_openclaw:
|
|
243
|
+
console.print("\n[yellow]Other proxy conflicts:[/yellow]")
|
|
244
|
+
for conflict in non_openclaw:
|
|
245
|
+
console.print(f" \u2022 {conflict.description}")
|
|
246
|
+
except Exception:
|
|
247
|
+
pass
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _apply_proxy_config(force: bool = False) -> None:
|
|
251
|
+
"""Write proxy configuration to ~/.tweek/config.yaml."""
|
|
252
|
+
import yaml
|
|
253
|
+
from pathlib import Path
|
|
254
|
+
|
|
255
|
+
try:
|
|
256
|
+
from tweek.proxy import TWEEK_DEFAULT_PORT
|
|
257
|
+
except ImportError:
|
|
258
|
+
TWEEK_DEFAULT_PORT = 8766
|
|
259
|
+
|
|
260
|
+
tweek_dir = Path("~/.tweek").expanduser()
|
|
261
|
+
tweek_dir.mkdir(parents=True, exist_ok=True)
|
|
262
|
+
config_path = tweek_dir / "config.yaml"
|
|
263
|
+
|
|
264
|
+
if config_path.exists():
|
|
265
|
+
with open(config_path) as f:
|
|
266
|
+
config = yaml.safe_load(f) or {}
|
|
267
|
+
else:
|
|
268
|
+
config = {}
|
|
269
|
+
|
|
270
|
+
config["proxy"] = config.get("proxy", {})
|
|
271
|
+
config["proxy"]["enabled"] = True
|
|
272
|
+
config["proxy"]["port"] = TWEEK_DEFAULT_PORT
|
|
273
|
+
config["proxy"]["override_openclaw"] = force
|
|
274
|
+
config["proxy"]["auto_start"] = False
|
|
275
|
+
|
|
276
|
+
with open(config_path, "w") as f:
|
|
277
|
+
yaml.dump(config, f, default_flow_style=False)
|
|
278
|
+
|
|
279
|
+
print_success("Proxy configuration saved")
|
|
280
|
+
console.print(f" [white]Config: {config_path}[/white]")
|
|
281
|
+
console.print(" [white]Run 'tweek proxy start' to begin intercepting API calls[/white]")
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
# ---------------------------------------------------------------------------
|
|
285
|
+
# tweek configure mcp
|
|
286
|
+
# ---------------------------------------------------------------------------
|
|
287
|
+
|
|
288
|
+
@configure.command()
|
|
289
|
+
def mcp():
|
|
290
|
+
"""Protect MCP-capable AI tools (Claude Desktop, ChatGPT, Gemini CLI).
|
|
291
|
+
|
|
292
|
+
Scans for installed MCP clients and offers to add Tweek as an MCP
|
|
293
|
+
security server for each one.
|
|
294
|
+
"""
|
|
295
|
+
from tweek.cli_helpers import _detect_all_tools
|
|
296
|
+
|
|
297
|
+
try:
|
|
298
|
+
all_tools = _detect_all_tools()
|
|
299
|
+
except Exception as e:
|
|
300
|
+
print_warning(f"Could not detect AI tools: {e}")
|
|
301
|
+
return
|
|
302
|
+
|
|
303
|
+
# Filter to MCP-capable tools
|
|
304
|
+
mcp_tool_ids = {"claude-desktop", "chatgpt", "gemini"}
|
|
305
|
+
mcp_tools = [
|
|
306
|
+
(tool_id, label, installed, protected)
|
|
307
|
+
for tool_id, label, installed, protected, _detail in all_tools
|
|
308
|
+
if tool_id in mcp_tool_ids
|
|
309
|
+
]
|
|
310
|
+
|
|
311
|
+
if not mcp_tools:
|
|
312
|
+
console.print("[white]No MCP-capable AI tools detected.[/white]")
|
|
313
|
+
return
|
|
314
|
+
|
|
315
|
+
console.print("[bold]MCP-Capable AI Tools[/bold]\n")
|
|
316
|
+
|
|
317
|
+
any_unprotected = False
|
|
318
|
+
for tool_id, label, installed, protected in mcp_tools:
|
|
319
|
+
if not installed:
|
|
320
|
+
console.print(f" [white]\u25cb[/white] {label} \u2014 not installed")
|
|
321
|
+
elif protected:
|
|
322
|
+
console.print(f" [green]\u2713[/green] {label} \u2014 protected")
|
|
323
|
+
else:
|
|
324
|
+
console.print(f" [yellow]\u26a0[/yellow] {label} \u2014 not protected")
|
|
325
|
+
any_unprotected = True
|
|
326
|
+
|
|
327
|
+
if not any_unprotected:
|
|
328
|
+
console.print("\n[white]All detected MCP tools are already protected.[/white]")
|
|
329
|
+
return
|
|
330
|
+
|
|
331
|
+
console.print()
|
|
332
|
+
unprotected = [
|
|
333
|
+
(tool_id, label)
|
|
334
|
+
for tool_id, label, installed, protected in mcp_tools
|
|
335
|
+
if installed and not protected
|
|
336
|
+
]
|
|
337
|
+
|
|
338
|
+
for tool_id, label in unprotected:
|
|
339
|
+
if click.confirm(f" Protect {label}?", default=True):
|
|
340
|
+
try:
|
|
341
|
+
from tweek.cli_protect import _protect_mcp_client
|
|
342
|
+
_protect_mcp_client(tool_id)
|
|
343
|
+
print_success(f"{label} protected")
|
|
344
|
+
except Exception as e:
|
|
345
|
+
print_warning(f"Could not configure {label}: {e}")
|
|
346
|
+
else:
|
|
347
|
+
console.print(f" [white]Skipped {label}[/white]")
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# ---------------------------------------------------------------------------
|
|
351
|
+
# tweek configure sandbox
|
|
352
|
+
# ---------------------------------------------------------------------------
|
|
353
|
+
|
|
354
|
+
@configure.command()
|
|
355
|
+
def sandbox():
|
|
356
|
+
"""Set up Linux sandbox (firejail) for command isolation.
|
|
357
|
+
|
|
358
|
+
Only applicable on Linux systems. Checks if firejail is installed
|
|
359
|
+
and offers to install it if not.
|
|
360
|
+
"""
|
|
361
|
+
from tweek.platform import IS_LINUX, get_capabilities
|
|
362
|
+
|
|
363
|
+
if not IS_LINUX:
|
|
364
|
+
console.print("[white]Sandbox is only available on Linux.[/white]")
|
|
365
|
+
console.print(f"[white]Your platform: {get_capabilities().platform.value}[/white]")
|
|
366
|
+
return
|
|
367
|
+
|
|
368
|
+
caps = get_capabilities()
|
|
369
|
+
if caps.sandbox_available:
|
|
370
|
+
print_success(f"Sandbox already available: {caps.sandbox_tool}")
|
|
371
|
+
return
|
|
372
|
+
|
|
373
|
+
console.print("[yellow]Sandbox (firejail) not installed.[/yellow]")
|
|
374
|
+
console.print(f"[white]Install with: {caps.sandbox_install_hint}[/white]")
|
|
375
|
+
|
|
376
|
+
try:
|
|
377
|
+
from tweek.sandbox.linux import prompt_install_firejail
|
|
378
|
+
prompt_install_firejail(console)
|
|
379
|
+
except ImportError:
|
|
380
|
+
console.print("[white]Run the install command shown above manually.[/white]")
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
# ---------------------------------------------------------------------------
|
|
384
|
+
# tweek configure wizard
|
|
385
|
+
# ---------------------------------------------------------------------------
|
|
386
|
+
|
|
387
|
+
@configure.command()
|
|
388
|
+
@click.pass_context
|
|
389
|
+
def wizard(ctx):
|
|
390
|
+
"""Run the full interactive setup wizard.
|
|
391
|
+
|
|
392
|
+
This is the same interactive experience as 'tweek install' without
|
|
393
|
+
the --quick flag. Use it to reconfigure all Tweek settings at once.
|
|
394
|
+
"""
|
|
395
|
+
from tweek.cli_install import install
|
|
396
|
+
|
|
397
|
+
console.print("[bold]Starting full configuration wizard...[/bold]")
|
|
398
|
+
console.print("[white]This will walk through all configuration options.[/white]\n")
|
|
399
|
+
|
|
400
|
+
# Invoke the install command in interactive mode
|
|
401
|
+
ctx.invoke(
|
|
402
|
+
install,
|
|
403
|
+
scope=None,
|
|
404
|
+
preset=None,
|
|
405
|
+
quick=False,
|
|
406
|
+
backup=True,
|
|
407
|
+
skip_env_scan=False,
|
|
408
|
+
interactive=True,
|
|
409
|
+
ai_defaults=False,
|
|
410
|
+
with_sandbox=False,
|
|
411
|
+
force_proxy=False,
|
|
412
|
+
skip_proxy_check=False,
|
|
413
|
+
)
|