superqode 0.1.5__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.
- superqode/__init__.py +33 -0
- superqode/acp/__init__.py +23 -0
- superqode/acp/client.py +913 -0
- superqode/acp/permission_screen.py +457 -0
- superqode/acp/types.py +480 -0
- superqode/acp_discovery.py +856 -0
- superqode/agent/__init__.py +22 -0
- superqode/agent/edit_strategies.py +334 -0
- superqode/agent/loop.py +892 -0
- superqode/agent/qe_report_templates.py +39 -0
- superqode/agent/system_prompts.py +353 -0
- superqode/agent_output.py +721 -0
- superqode/agent_stream.py +953 -0
- superqode/agents/__init__.py +59 -0
- superqode/agents/acp_registry.py +305 -0
- superqode/agents/client.py +249 -0
- superqode/agents/data/augmentcode.com.toml +51 -0
- superqode/agents/data/cagent.dev.toml +51 -0
- superqode/agents/data/claude.com.toml +60 -0
- superqode/agents/data/codeassistant.dev.toml +51 -0
- superqode/agents/data/codex.openai.com.toml +57 -0
- superqode/agents/data/fastagent.ai.toml +66 -0
- superqode/agents/data/geminicli.com.toml +77 -0
- superqode/agents/data/goose.block.xyz.toml +54 -0
- superqode/agents/data/junie.jetbrains.com.toml +56 -0
- superqode/agents/data/kimi.moonshot.cn.toml +57 -0
- superqode/agents/data/llmlingagent.dev.toml +51 -0
- superqode/agents/data/molt.bot.toml +49 -0
- superqode/agents/data/opencode.ai.toml +60 -0
- superqode/agents/data/stakpak.dev.toml +51 -0
- superqode/agents/data/vtcode.dev.toml +51 -0
- superqode/agents/discovery.py +266 -0
- superqode/agents/messaging.py +160 -0
- superqode/agents/persona.py +166 -0
- superqode/agents/registry.py +421 -0
- superqode/agents/schema.py +72 -0
- superqode/agents/unified.py +367 -0
- superqode/app/__init__.py +111 -0
- superqode/app/constants.py +314 -0
- superqode/app/css.py +366 -0
- superqode/app/models.py +118 -0
- superqode/app/suggester.py +125 -0
- superqode/app/widgets.py +1591 -0
- superqode/app_enhanced.py +399 -0
- superqode/app_main.py +17187 -0
- superqode/approval.py +312 -0
- superqode/atomic.py +296 -0
- superqode/commands/__init__.py +1 -0
- superqode/commands/acp.py +965 -0
- superqode/commands/agents.py +180 -0
- superqode/commands/auth.py +278 -0
- superqode/commands/config.py +374 -0
- superqode/commands/init.py +826 -0
- superqode/commands/providers.py +819 -0
- superqode/commands/qe.py +1145 -0
- superqode/commands/roles.py +380 -0
- superqode/commands/serve.py +172 -0
- superqode/commands/suggestions.py +127 -0
- superqode/commands/superqe.py +460 -0
- superqode/config/__init__.py +51 -0
- superqode/config/loader.py +812 -0
- superqode/config/schema.py +498 -0
- superqode/core/__init__.py +111 -0
- superqode/core/roles.py +281 -0
- superqode/danger.py +386 -0
- superqode/data/superqode-template.yaml +1522 -0
- superqode/design_system.py +1080 -0
- superqode/dialogs/__init__.py +6 -0
- superqode/dialogs/base.py +39 -0
- superqode/dialogs/model.py +130 -0
- superqode/dialogs/provider.py +870 -0
- superqode/diff_view.py +919 -0
- superqode/enterprise.py +21 -0
- superqode/evaluation/__init__.py +25 -0
- superqode/evaluation/adapters.py +93 -0
- superqode/evaluation/behaviors.py +89 -0
- superqode/evaluation/engine.py +209 -0
- superqode/evaluation/scenarios.py +96 -0
- superqode/execution/__init__.py +36 -0
- superqode/execution/linter.py +538 -0
- superqode/execution/modes.py +347 -0
- superqode/execution/resolver.py +283 -0
- superqode/execution/runner.py +642 -0
- superqode/file_explorer.py +811 -0
- superqode/file_viewer.py +471 -0
- superqode/flash.py +183 -0
- superqode/guidance/__init__.py +58 -0
- superqode/guidance/config.py +203 -0
- superqode/guidance/prompts.py +71 -0
- superqode/harness/__init__.py +54 -0
- superqode/harness/accelerator.py +291 -0
- superqode/harness/config.py +319 -0
- superqode/harness/validator.py +147 -0
- superqode/history.py +279 -0
- superqode/integrations/superopt_runner.py +124 -0
- superqode/logging/__init__.py +49 -0
- superqode/logging/adapters.py +219 -0
- superqode/logging/formatter.py +923 -0
- superqode/logging/integration.py +341 -0
- superqode/logging/sinks.py +170 -0
- superqode/logging/unified_log.py +417 -0
- superqode/lsp/__init__.py +26 -0
- superqode/lsp/client.py +544 -0
- superqode/main.py +1069 -0
- superqode/mcp/__init__.py +89 -0
- superqode/mcp/auth_storage.py +380 -0
- superqode/mcp/client.py +1236 -0
- superqode/mcp/config.py +319 -0
- superqode/mcp/integration.py +337 -0
- superqode/mcp/oauth.py +436 -0
- superqode/mcp/oauth_callback.py +385 -0
- superqode/mcp/types.py +290 -0
- superqode/memory/__init__.py +31 -0
- superqode/memory/feedback.py +342 -0
- superqode/memory/store.py +522 -0
- superqode/notifications.py +369 -0
- superqode/optimization/__init__.py +5 -0
- superqode/optimization/config.py +33 -0
- superqode/permissions/__init__.py +25 -0
- superqode/permissions/rules.py +488 -0
- superqode/plan.py +323 -0
- superqode/providers/__init__.py +33 -0
- superqode/providers/gateway/__init__.py +165 -0
- superqode/providers/gateway/base.py +228 -0
- superqode/providers/gateway/litellm_gateway.py +1170 -0
- superqode/providers/gateway/openresponses_gateway.py +436 -0
- superqode/providers/health.py +297 -0
- superqode/providers/huggingface/__init__.py +74 -0
- superqode/providers/huggingface/downloader.py +472 -0
- superqode/providers/huggingface/endpoints.py +442 -0
- superqode/providers/huggingface/hub.py +531 -0
- superqode/providers/huggingface/inference.py +394 -0
- superqode/providers/huggingface/transformers_runner.py +516 -0
- superqode/providers/local/__init__.py +100 -0
- superqode/providers/local/base.py +438 -0
- superqode/providers/local/discovery.py +418 -0
- superqode/providers/local/lmstudio.py +256 -0
- superqode/providers/local/mlx.py +457 -0
- superqode/providers/local/ollama.py +486 -0
- superqode/providers/local/sglang.py +268 -0
- superqode/providers/local/tgi.py +260 -0
- superqode/providers/local/tool_support.py +477 -0
- superqode/providers/local/vllm.py +258 -0
- superqode/providers/manager.py +1338 -0
- superqode/providers/models.py +1016 -0
- superqode/providers/models_dev.py +578 -0
- superqode/providers/openresponses/__init__.py +87 -0
- superqode/providers/openresponses/converters/__init__.py +17 -0
- superqode/providers/openresponses/converters/messages.py +343 -0
- superqode/providers/openresponses/converters/tools.py +268 -0
- superqode/providers/openresponses/schema/__init__.py +56 -0
- superqode/providers/openresponses/schema/models.py +585 -0
- superqode/providers/openresponses/streaming/__init__.py +5 -0
- superqode/providers/openresponses/streaming/parser.py +338 -0
- superqode/providers/openresponses/tools/__init__.py +21 -0
- superqode/providers/openresponses/tools/apply_patch.py +352 -0
- superqode/providers/openresponses/tools/code_interpreter.py +290 -0
- superqode/providers/openresponses/tools/file_search.py +333 -0
- superqode/providers/openresponses/tools/mcp_adapter.py +252 -0
- superqode/providers/registry.py +716 -0
- superqode/providers/usage.py +332 -0
- superqode/pure_mode.py +384 -0
- superqode/qr/__init__.py +23 -0
- superqode/qr/dashboard.py +781 -0
- superqode/qr/generator.py +1018 -0
- superqode/qr/templates.py +135 -0
- superqode/safety/__init__.py +41 -0
- superqode/safety/sandbox.py +413 -0
- superqode/safety/warnings.py +256 -0
- superqode/server/__init__.py +33 -0
- superqode/server/lsp_server.py +775 -0
- superqode/server/web.py +250 -0
- superqode/session/__init__.py +25 -0
- superqode/session/persistence.py +580 -0
- superqode/session/sharing.py +477 -0
- superqode/session.py +475 -0
- superqode/sidebar.py +2991 -0
- superqode/stream_view.py +648 -0
- superqode/styles/__init__.py +3 -0
- superqode/superqe/__init__.py +184 -0
- superqode/superqe/acp_runner.py +1064 -0
- superqode/superqe/constitution/__init__.py +62 -0
- superqode/superqe/constitution/evaluator.py +308 -0
- superqode/superqe/constitution/loader.py +432 -0
- superqode/superqe/constitution/schema.py +250 -0
- superqode/superqe/events.py +591 -0
- superqode/superqe/frameworks/__init__.py +65 -0
- superqode/superqe/frameworks/base.py +234 -0
- superqode/superqe/frameworks/e2e.py +263 -0
- superqode/superqe/frameworks/executor.py +237 -0
- superqode/superqe/frameworks/javascript.py +409 -0
- superqode/superqe/frameworks/python.py +373 -0
- superqode/superqe/frameworks/registry.py +92 -0
- superqode/superqe/mcp_tools/__init__.py +47 -0
- superqode/superqe/mcp_tools/core_tools.py +418 -0
- superqode/superqe/mcp_tools/registry.py +230 -0
- superqode/superqe/mcp_tools/testing_tools.py +167 -0
- superqode/superqe/noise.py +89 -0
- superqode/superqe/orchestrator.py +778 -0
- superqode/superqe/roles.py +609 -0
- superqode/superqe/session.py +713 -0
- superqode/superqe/skills/__init__.py +57 -0
- superqode/superqe/skills/base.py +106 -0
- superqode/superqe/skills/core_skills.py +899 -0
- superqode/superqe/skills/registry.py +90 -0
- superqode/superqe/verifier.py +101 -0
- superqode/superqe_cli.py +76 -0
- superqode/tool_call.py +358 -0
- superqode/tools/__init__.py +93 -0
- superqode/tools/agent_tools.py +496 -0
- superqode/tools/base.py +324 -0
- superqode/tools/batch_tool.py +133 -0
- superqode/tools/diagnostics.py +311 -0
- superqode/tools/edit_tools.py +653 -0
- superqode/tools/enhanced_base.py +515 -0
- superqode/tools/file_tools.py +269 -0
- superqode/tools/file_tracking.py +45 -0
- superqode/tools/lsp_tools.py +610 -0
- superqode/tools/network_tools.py +350 -0
- superqode/tools/permissions.py +400 -0
- superqode/tools/question_tool.py +324 -0
- superqode/tools/search_tools.py +598 -0
- superqode/tools/shell_tools.py +259 -0
- superqode/tools/todo_tools.py +121 -0
- superqode/tools/validation.py +80 -0
- superqode/tools/web_tools.py +639 -0
- superqode/tui.py +1152 -0
- superqode/tui_integration.py +875 -0
- superqode/tui_widgets/__init__.py +27 -0
- superqode/tui_widgets/widgets/__init__.py +18 -0
- superqode/tui_widgets/widgets/progress.py +185 -0
- superqode/tui_widgets/widgets/tool_display.py +188 -0
- superqode/undo_manager.py +574 -0
- superqode/utils/__init__.py +5 -0
- superqode/utils/error_handling.py +323 -0
- superqode/utils/fuzzy.py +257 -0
- superqode/widgets/__init__.py +477 -0
- superqode/widgets/agent_collab.py +390 -0
- superqode/widgets/agent_store.py +936 -0
- superqode/widgets/agent_switcher.py +395 -0
- superqode/widgets/animation_manager.py +284 -0
- superqode/widgets/code_context.py +356 -0
- superqode/widgets/command_palette.py +412 -0
- superqode/widgets/connection_status.py +537 -0
- superqode/widgets/conversation_history.py +470 -0
- superqode/widgets/diff_indicator.py +155 -0
- superqode/widgets/enhanced_status_bar.py +385 -0
- superqode/widgets/enhanced_toast.py +476 -0
- superqode/widgets/file_browser.py +809 -0
- superqode/widgets/file_reference.py +585 -0
- superqode/widgets/issue_timeline.py +340 -0
- superqode/widgets/leader_key.py +264 -0
- superqode/widgets/mode_switcher.py +445 -0
- superqode/widgets/model_picker.py +234 -0
- superqode/widgets/permission_preview.py +1205 -0
- superqode/widgets/prompt.py +358 -0
- superqode/widgets/provider_connect.py +725 -0
- superqode/widgets/pty_shell.py +587 -0
- superqode/widgets/qe_dashboard.py +321 -0
- superqode/widgets/resizable_sidebar.py +377 -0
- superqode/widgets/response_changes.py +218 -0
- superqode/widgets/response_display.py +528 -0
- superqode/widgets/rich_tool_display.py +613 -0
- superqode/widgets/sidebar_panels.py +1180 -0
- superqode/widgets/slash_complete.py +356 -0
- superqode/widgets/split_view.py +612 -0
- superqode/widgets/status_bar.py +273 -0
- superqode/widgets/superqode_display.py +786 -0
- superqode/widgets/thinking_display.py +815 -0
- superqode/widgets/throbber.py +87 -0
- superqode/widgets/toast.py +206 -0
- superqode/widgets/unified_output.py +1073 -0
- superqode/workspace/__init__.py +75 -0
- superqode/workspace/artifacts.py +472 -0
- superqode/workspace/coordinator.py +353 -0
- superqode/workspace/diff_tracker.py +429 -0
- superqode/workspace/git_guard.py +373 -0
- superqode/workspace/git_snapshot.py +526 -0
- superqode/workspace/manager.py +750 -0
- superqode/workspace/snapshot.py +357 -0
- superqode/workspace/watcher.py +535 -0
- superqode/workspace/worktree.py +440 -0
- superqode-0.1.5.dist-info/METADATA +204 -0
- superqode-0.1.5.dist-info/RECORD +288 -0
- superqode-0.1.5.dist-info/WHEEL +5 -0
- superqode-0.1.5.dist-info/entry_points.txt +3 -0
- superqode-0.1.5.dist-info/licenses/LICENSE +648 -0
- superqode-0.1.5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Config command - Manage SuperQode configuration.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.panel import Panel
|
|
14
|
+
from rich.syntax import Syntax
|
|
15
|
+
from rich.table import Table
|
|
16
|
+
from rich.tree import Tree
|
|
17
|
+
|
|
18
|
+
console = Console()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@click.group()
|
|
22
|
+
def config():
|
|
23
|
+
"""Manage SuperQode configuration.
|
|
24
|
+
|
|
25
|
+
View, validate, and modify configuration settings.
|
|
26
|
+
"""
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@config.command("show")
|
|
31
|
+
@click.argument("path", type=click.Path(exists=True), default=".")
|
|
32
|
+
@click.option(
|
|
33
|
+
"--format",
|
|
34
|
+
"-f",
|
|
35
|
+
"fmt",
|
|
36
|
+
type=click.Choice(["yaml", "json", "tree"]),
|
|
37
|
+
default="yaml",
|
|
38
|
+
help="Output format",
|
|
39
|
+
)
|
|
40
|
+
@click.option("--section", "-s", help="Show specific section (e.g., 'team.modes.dev')")
|
|
41
|
+
def config_show(path: str, fmt: str, section: Optional[str]):
|
|
42
|
+
"""Show current configuration.
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
|
|
46
|
+
superqode config show # Show full config
|
|
47
|
+
|
|
48
|
+
superqode config show -f json # Output as JSON
|
|
49
|
+
|
|
50
|
+
superqode config show -s team.modes.dev # Show specific section
|
|
51
|
+
"""
|
|
52
|
+
from superqode.config import load_config
|
|
53
|
+
|
|
54
|
+
project_root = Path(path).resolve()
|
|
55
|
+
config_file = project_root / "superqode.yaml"
|
|
56
|
+
|
|
57
|
+
if not config_file.exists():
|
|
58
|
+
console.print("[yellow]No configuration found.[/yellow]")
|
|
59
|
+
console.print("[dim]Run 'superqode init' to create a configuration.[/dim]")
|
|
60
|
+
return 1
|
|
61
|
+
|
|
62
|
+
# Load and parse config
|
|
63
|
+
try:
|
|
64
|
+
cfg = load_config(project_root)
|
|
65
|
+
except Exception as e:
|
|
66
|
+
console.print(f"[red]Error loading configuration:[/red] {e}")
|
|
67
|
+
return 1
|
|
68
|
+
|
|
69
|
+
console.print()
|
|
70
|
+
console.print(Panel("[bold]SuperQode Configuration[/bold]", border_style="cyan"))
|
|
71
|
+
console.print()
|
|
72
|
+
|
|
73
|
+
if fmt == "yaml":
|
|
74
|
+
# Show raw YAML
|
|
75
|
+
content = config_file.read_text()
|
|
76
|
+
syntax = Syntax(content, "yaml", theme="monokai", line_numbers=True)
|
|
77
|
+
console.print(syntax)
|
|
78
|
+
|
|
79
|
+
elif fmt == "json":
|
|
80
|
+
# Convert to JSON
|
|
81
|
+
import dataclasses
|
|
82
|
+
|
|
83
|
+
def to_dict(obj):
|
|
84
|
+
if dataclasses.is_dataclass(obj):
|
|
85
|
+
return {k: to_dict(v) for k, v in dataclasses.asdict(obj).items()}
|
|
86
|
+
elif isinstance(obj, dict):
|
|
87
|
+
return {k: to_dict(v) for k, v in obj.items()}
|
|
88
|
+
elif isinstance(obj, list):
|
|
89
|
+
return [to_dict(v) for v in obj]
|
|
90
|
+
elif hasattr(obj, "value"): # Enum
|
|
91
|
+
return obj.value
|
|
92
|
+
else:
|
|
93
|
+
return obj
|
|
94
|
+
|
|
95
|
+
config_dict = to_dict(cfg)
|
|
96
|
+
console.print(json.dumps(config_dict, indent=2))
|
|
97
|
+
|
|
98
|
+
elif fmt == "tree":
|
|
99
|
+
# Show as tree
|
|
100
|
+
_show_config_tree(cfg)
|
|
101
|
+
|
|
102
|
+
return 0
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@config.command("validate")
|
|
106
|
+
@click.argument("path", type=click.Path(exists=True), default=".")
|
|
107
|
+
@click.option("--fix", is_flag=True, help="Attempt to fix common issues")
|
|
108
|
+
def config_validate(path: str, fix: bool):
|
|
109
|
+
"""Validate configuration file.
|
|
110
|
+
|
|
111
|
+
Checks for:
|
|
112
|
+
- Valid YAML syntax
|
|
113
|
+
- Required fields
|
|
114
|
+
- Valid values
|
|
115
|
+
- Provider configurations
|
|
116
|
+
- Harness tool availability
|
|
117
|
+
|
|
118
|
+
Examples:
|
|
119
|
+
|
|
120
|
+
superqode config validate # Validate current directory
|
|
121
|
+
|
|
122
|
+
superqode config validate --fix # Auto-fix common issues
|
|
123
|
+
"""
|
|
124
|
+
from superqode.config import load_config
|
|
125
|
+
|
|
126
|
+
project_root = Path(path).resolve()
|
|
127
|
+
config_file = project_root / "superqode.yaml"
|
|
128
|
+
|
|
129
|
+
console.print()
|
|
130
|
+
console.print(Panel("[bold]Configuration Validation[/bold]", border_style="cyan"))
|
|
131
|
+
console.print()
|
|
132
|
+
|
|
133
|
+
if not config_file.exists():
|
|
134
|
+
console.print("[red]✗[/red] No superqode.yaml found")
|
|
135
|
+
console.print("[dim]Run 'superqode init' to create a configuration.[/dim]")
|
|
136
|
+
return 1
|
|
137
|
+
|
|
138
|
+
issues = []
|
|
139
|
+
warnings = []
|
|
140
|
+
|
|
141
|
+
# Check YAML syntax
|
|
142
|
+
try:
|
|
143
|
+
import yaml
|
|
144
|
+
|
|
145
|
+
with open(config_file) as f:
|
|
146
|
+
raw_config = yaml.safe_load(f)
|
|
147
|
+
console.print("[green]✓[/green] YAML syntax is valid")
|
|
148
|
+
except yaml.YAMLError as e:
|
|
149
|
+
console.print(f"[red]✗[/red] YAML syntax error: {e}")
|
|
150
|
+
return 1
|
|
151
|
+
|
|
152
|
+
# Check required sections
|
|
153
|
+
if "superqode" not in raw_config:
|
|
154
|
+
issues.append("Missing 'superqode' section")
|
|
155
|
+
else:
|
|
156
|
+
if "version" not in raw_config.get("superqode", {}):
|
|
157
|
+
warnings.append("Missing 'superqode.version' field")
|
|
158
|
+
console.print("[green]✓[/green] 'superqode' section present")
|
|
159
|
+
|
|
160
|
+
# Check MCP servers config (if present)
|
|
161
|
+
mcp_config = raw_config.get("mcp_servers", {})
|
|
162
|
+
if mcp_config:
|
|
163
|
+
console.print("[green]✓[/green] MCP servers configured")
|
|
164
|
+
for name, server_config in mcp_config.items():
|
|
165
|
+
if server_config.get("enabled", False):
|
|
166
|
+
console.print(f" [green]✓[/green] {name}: enabled")
|
|
167
|
+
else:
|
|
168
|
+
console.print(f" [dim]○[/dim] {name}: disabled")
|
|
169
|
+
|
|
170
|
+
# Check providers
|
|
171
|
+
providers = raw_config.get("providers", {})
|
|
172
|
+
if providers:
|
|
173
|
+
console.print("[green]✓[/green] Providers configured")
|
|
174
|
+
for name, pconfig in providers.items():
|
|
175
|
+
api_key_env = pconfig.get("api_key_env")
|
|
176
|
+
if api_key_env:
|
|
177
|
+
import os
|
|
178
|
+
|
|
179
|
+
if os.environ.get(api_key_env):
|
|
180
|
+
console.print(f" [green]✓[/green] {name}: {api_key_env} is set")
|
|
181
|
+
else:
|
|
182
|
+
warnings.append(f"Provider '{name}': {api_key_env} not set in environment")
|
|
183
|
+
|
|
184
|
+
# Load full config to check for errors
|
|
185
|
+
try:
|
|
186
|
+
cfg = load_config(project_root)
|
|
187
|
+
console.print("[green]✓[/green] Configuration loads successfully")
|
|
188
|
+
except Exception as e:
|
|
189
|
+
issues.append(f"Configuration load error: {e}")
|
|
190
|
+
|
|
191
|
+
# Report results
|
|
192
|
+
console.print()
|
|
193
|
+
if issues:
|
|
194
|
+
console.print("[bold red]Issues found:[/bold red]")
|
|
195
|
+
for issue in issues:
|
|
196
|
+
console.print(f" [red]✗[/red] {issue}")
|
|
197
|
+
console.print()
|
|
198
|
+
|
|
199
|
+
if warnings:
|
|
200
|
+
console.print("[bold yellow]Warnings:[/bold yellow]")
|
|
201
|
+
for warning in warnings:
|
|
202
|
+
console.print(f" [yellow]![/yellow] {warning}")
|
|
203
|
+
console.print()
|
|
204
|
+
|
|
205
|
+
if not issues and not warnings:
|
|
206
|
+
console.print("[green]✓ Configuration is valid![/green]")
|
|
207
|
+
return 0
|
|
208
|
+
elif not issues:
|
|
209
|
+
console.print("[green]✓ Configuration is valid (with warnings)[/green]")
|
|
210
|
+
return 0
|
|
211
|
+
else:
|
|
212
|
+
console.print("[red]✗ Configuration has issues[/red]")
|
|
213
|
+
return 1
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@config.command("set")
|
|
217
|
+
@click.argument("key")
|
|
218
|
+
@click.argument("value")
|
|
219
|
+
@click.argument("path", type=click.Path(exists=True), default=".")
|
|
220
|
+
def config_set(key: str, value: str, path: str):
|
|
221
|
+
"""Set a configuration value.
|
|
222
|
+
|
|
223
|
+
Examples:
|
|
224
|
+
|
|
225
|
+
superqode config set superqode.team_name "My Team"
|
|
226
|
+
|
|
227
|
+
superqode config set team.modes.dev.roles.fullstack.enabled false
|
|
228
|
+
"""
|
|
229
|
+
import yaml
|
|
230
|
+
|
|
231
|
+
project_root = Path(path).resolve()
|
|
232
|
+
config_file = project_root / "superqode.yaml"
|
|
233
|
+
|
|
234
|
+
if not config_file.exists():
|
|
235
|
+
console.print("[red]No configuration found.[/red]")
|
|
236
|
+
console.print("[dim]Run 'superqode init' first.[/dim]")
|
|
237
|
+
return 1
|
|
238
|
+
|
|
239
|
+
# Load existing config
|
|
240
|
+
with open(config_file) as f:
|
|
241
|
+
config = yaml.safe_load(f) or {}
|
|
242
|
+
|
|
243
|
+
# Parse the key path
|
|
244
|
+
keys = key.split(".")
|
|
245
|
+
current = config
|
|
246
|
+
|
|
247
|
+
# Navigate to parent
|
|
248
|
+
for k in keys[:-1]:
|
|
249
|
+
if k not in current:
|
|
250
|
+
current[k] = {}
|
|
251
|
+
current = current[k]
|
|
252
|
+
|
|
253
|
+
# Set value (try to parse as number/bool)
|
|
254
|
+
final_key = keys[-1]
|
|
255
|
+
try:
|
|
256
|
+
# Try int
|
|
257
|
+
parsed_value = int(value)
|
|
258
|
+
except ValueError:
|
|
259
|
+
try:
|
|
260
|
+
# Try float
|
|
261
|
+
parsed_value = float(value)
|
|
262
|
+
except ValueError:
|
|
263
|
+
# Try bool
|
|
264
|
+
if value.lower() in ("true", "yes", "on"):
|
|
265
|
+
parsed_value = True
|
|
266
|
+
elif value.lower() in ("false", "no", "off"):
|
|
267
|
+
parsed_value = False
|
|
268
|
+
else:
|
|
269
|
+
parsed_value = value
|
|
270
|
+
|
|
271
|
+
old_value = current.get(final_key)
|
|
272
|
+
current[final_key] = parsed_value
|
|
273
|
+
|
|
274
|
+
# Write back
|
|
275
|
+
with open(config_file, "w") as f:
|
|
276
|
+
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
|
|
277
|
+
|
|
278
|
+
console.print(f"[green]✓[/green] Set {key}: {old_value} → {parsed_value}")
|
|
279
|
+
return 0
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
@config.command("get")
|
|
283
|
+
@click.argument("key")
|
|
284
|
+
@click.argument("path", type=click.Path(exists=True), default=".")
|
|
285
|
+
def config_get(key: str, path: str):
|
|
286
|
+
"""Get a configuration value.
|
|
287
|
+
|
|
288
|
+
Examples:
|
|
289
|
+
|
|
290
|
+
superqode config get superqode.team_name
|
|
291
|
+
|
|
292
|
+
superqode config get team.modes.dev.roles.fullstack.enabled
|
|
293
|
+
"""
|
|
294
|
+
import yaml
|
|
295
|
+
|
|
296
|
+
project_root = Path(path).resolve()
|
|
297
|
+
config_file = project_root / "superqode.yaml"
|
|
298
|
+
|
|
299
|
+
if not config_file.exists():
|
|
300
|
+
console.print("[red]No configuration found.[/red]")
|
|
301
|
+
return 1
|
|
302
|
+
|
|
303
|
+
with open(config_file) as f:
|
|
304
|
+
config = yaml.safe_load(f) or {}
|
|
305
|
+
|
|
306
|
+
# Navigate to value
|
|
307
|
+
keys = key.split(".")
|
|
308
|
+
current = config
|
|
309
|
+
|
|
310
|
+
for k in keys:
|
|
311
|
+
if isinstance(current, dict) and k in current:
|
|
312
|
+
current = current[k]
|
|
313
|
+
else:
|
|
314
|
+
console.print(f"[yellow]Key not found:[/yellow] {key}")
|
|
315
|
+
return 1
|
|
316
|
+
|
|
317
|
+
# Output value
|
|
318
|
+
if isinstance(current, (dict, list)):
|
|
319
|
+
console.print(json.dumps(current, indent=2))
|
|
320
|
+
else:
|
|
321
|
+
console.print(current)
|
|
322
|
+
|
|
323
|
+
return 0
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _show_config_tree(cfg) -> None:
|
|
327
|
+
"""Display configuration as a tree."""
|
|
328
|
+
import dataclasses
|
|
329
|
+
|
|
330
|
+
tree = Tree("[bold cyan]superqode.yaml[/bold cyan]")
|
|
331
|
+
|
|
332
|
+
def add_to_tree(node, obj, name=""):
|
|
333
|
+
if dataclasses.is_dataclass(obj):
|
|
334
|
+
branch = node.add(f"[bold]{name}[/bold]") if name else node
|
|
335
|
+
for field in dataclasses.fields(obj):
|
|
336
|
+
add_to_tree(branch, getattr(obj, field.name), field.name)
|
|
337
|
+
elif isinstance(obj, dict):
|
|
338
|
+
branch = node.add(f"[bold]{name}[/bold]") if name else node
|
|
339
|
+
for k, v in obj.items():
|
|
340
|
+
add_to_tree(branch, v, k)
|
|
341
|
+
elif isinstance(obj, list):
|
|
342
|
+
branch = node.add(f"[bold]{name}[/bold] [dim]({len(obj)} items)[/dim]")
|
|
343
|
+
for i, v in enumerate(obj[:5]): # Limit to 5 items
|
|
344
|
+
add_to_tree(branch, v, f"[{i}]")
|
|
345
|
+
if len(obj) > 5:
|
|
346
|
+
branch.add("[dim]...[/dim]")
|
|
347
|
+
else:
|
|
348
|
+
value = str(obj)
|
|
349
|
+
if len(value) > 50:
|
|
350
|
+
value = value[:47] + "..."
|
|
351
|
+
node.add(f"{name}: [green]{value}[/green]")
|
|
352
|
+
|
|
353
|
+
add_to_tree(tree, cfg)
|
|
354
|
+
console.print(tree)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def _check_harness_tools(harness: dict, warnings: list) -> None:
|
|
358
|
+
"""Check if harness tools are available."""
|
|
359
|
+
import shutil
|
|
360
|
+
|
|
361
|
+
tool_checks = {
|
|
362
|
+
"python_tools": ["ruff", "mypy", "pyright"],
|
|
363
|
+
"javascript_tools": ["eslint", "tsc"],
|
|
364
|
+
"go_tools": ["golangci-lint"],
|
|
365
|
+
"rust_tools": ["cargo"],
|
|
366
|
+
"shell_tools": ["shellcheck"],
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
for category, tools in tool_checks.items():
|
|
370
|
+
configured_tools = harness.get(category, [])
|
|
371
|
+
for tool in configured_tools:
|
|
372
|
+
tool_name = tool.split()[0] # Handle "go vet" -> "go"
|
|
373
|
+
if not shutil.which(tool_name):
|
|
374
|
+
warnings.append(f"Harness tool not found: {tool_name}")
|