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,826 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Init command - Initialize SuperQE configuration for a project.
|
|
3
|
+
|
|
4
|
+
Supports guided mode with:
|
|
5
|
+
- Framework detection (React, Django, FastAPI, etc.)
|
|
6
|
+
- Team size configuration
|
|
7
|
+
- Provider setup with API key detection
|
|
8
|
+
- Validation with quick scan
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import subprocess
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Dict, List, Optional, Tuple
|
|
18
|
+
|
|
19
|
+
import click
|
|
20
|
+
from rich.console import Console
|
|
21
|
+
from rich.panel import Panel
|
|
22
|
+
from rich.prompt import Confirm, Prompt
|
|
23
|
+
from rich.table import Table
|
|
24
|
+
|
|
25
|
+
console = Console()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class FrameworkInfo:
|
|
30
|
+
"""Detected framework information."""
|
|
31
|
+
|
|
32
|
+
name: str
|
|
33
|
+
category: str # "frontend", "backend", "fullstack", "cli"
|
|
34
|
+
language: str
|
|
35
|
+
recommended_roles: List[str]
|
|
36
|
+
test_patterns: List[str]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Framework detection rules
|
|
40
|
+
FRAMEWORK_DETECTORS = {
|
|
41
|
+
# Frontend frameworks
|
|
42
|
+
"next.js": {
|
|
43
|
+
"files": ["next.config.js", "next.config.mjs", "next.config.ts"],
|
|
44
|
+
"package_json_deps": ["next"],
|
|
45
|
+
"info": FrameworkInfo(
|
|
46
|
+
name="Next.js",
|
|
47
|
+
category="fullstack",
|
|
48
|
+
language="typescript",
|
|
49
|
+
recommended_roles=["e2e_tester", "api_tester", "unit_tester"],
|
|
50
|
+
test_patterns=["**/*.test.tsx", "**/*.spec.tsx", "**/__tests__/**"],
|
|
51
|
+
),
|
|
52
|
+
},
|
|
53
|
+
"react": {
|
|
54
|
+
"files": [],
|
|
55
|
+
"package_json_deps": ["react", "react-dom"],
|
|
56
|
+
"info": FrameworkInfo(
|
|
57
|
+
name="React",
|
|
58
|
+
category="frontend",
|
|
59
|
+
language="typescript",
|
|
60
|
+
recommended_roles=["e2e_tester", "unit_tester"],
|
|
61
|
+
test_patterns=["**/*.test.tsx", "**/*.test.jsx", "**/*.spec.tsx"],
|
|
62
|
+
),
|
|
63
|
+
},
|
|
64
|
+
"vue": {
|
|
65
|
+
"files": ["vue.config.js", "vite.config.ts"],
|
|
66
|
+
"package_json_deps": ["vue"],
|
|
67
|
+
"info": FrameworkInfo(
|
|
68
|
+
name="Vue.js",
|
|
69
|
+
category="frontend",
|
|
70
|
+
language="typescript",
|
|
71
|
+
recommended_roles=["e2e_tester", "unit_tester"],
|
|
72
|
+
test_patterns=["**/*.spec.ts", "**/*.test.ts"],
|
|
73
|
+
),
|
|
74
|
+
},
|
|
75
|
+
# Backend frameworks
|
|
76
|
+
"django": {
|
|
77
|
+
"files": ["manage.py"],
|
|
78
|
+
"pyproject_deps": ["django"],
|
|
79
|
+
"requirements_deps": ["django", "Django"],
|
|
80
|
+
"info": FrameworkInfo(
|
|
81
|
+
name="Django",
|
|
82
|
+
category="backend",
|
|
83
|
+
language="python",
|
|
84
|
+
recommended_roles=[
|
|
85
|
+
"api_tester",
|
|
86
|
+
"security_tester",
|
|
87
|
+
"unit_tester",
|
|
88
|
+
"performance_tester",
|
|
89
|
+
],
|
|
90
|
+
test_patterns=["**/test_*.py", "**/tests.py", "**/tests/*.py"],
|
|
91
|
+
),
|
|
92
|
+
},
|
|
93
|
+
"fastapi": {
|
|
94
|
+
"files": [],
|
|
95
|
+
"pyproject_deps": ["fastapi"],
|
|
96
|
+
"requirements_deps": ["fastapi"],
|
|
97
|
+
"info": FrameworkInfo(
|
|
98
|
+
name="FastAPI",
|
|
99
|
+
category="backend",
|
|
100
|
+
language="python",
|
|
101
|
+
recommended_roles=[
|
|
102
|
+
"api_tester",
|
|
103
|
+
"security_tester",
|
|
104
|
+
"unit_tester",
|
|
105
|
+
"performance_tester",
|
|
106
|
+
],
|
|
107
|
+
test_patterns=["**/test_*.py", "**/tests/*.py"],
|
|
108
|
+
),
|
|
109
|
+
},
|
|
110
|
+
"flask": {
|
|
111
|
+
"files": [],
|
|
112
|
+
"pyproject_deps": ["flask"],
|
|
113
|
+
"requirements_deps": ["flask", "Flask"],
|
|
114
|
+
"info": FrameworkInfo(
|
|
115
|
+
name="Flask",
|
|
116
|
+
category="backend",
|
|
117
|
+
language="python",
|
|
118
|
+
recommended_roles=["api_tester", "security_tester", "unit_tester"],
|
|
119
|
+
test_patterns=["**/test_*.py"],
|
|
120
|
+
),
|
|
121
|
+
},
|
|
122
|
+
"express": {
|
|
123
|
+
"files": [],
|
|
124
|
+
"package_json_deps": ["express"],
|
|
125
|
+
"info": FrameworkInfo(
|
|
126
|
+
name="Express.js",
|
|
127
|
+
category="backend",
|
|
128
|
+
language="typescript",
|
|
129
|
+
recommended_roles=["api_tester", "security_tester", "unit_tester"],
|
|
130
|
+
test_patterns=["**/*.test.js", "**/*.spec.js"],
|
|
131
|
+
),
|
|
132
|
+
},
|
|
133
|
+
# Go frameworks
|
|
134
|
+
"go-chi": {
|
|
135
|
+
"files": [],
|
|
136
|
+
"go_mod_deps": ["github.com/go-chi/chi"],
|
|
137
|
+
"info": FrameworkInfo(
|
|
138
|
+
name="Go Chi",
|
|
139
|
+
category="backend",
|
|
140
|
+
language="go",
|
|
141
|
+
recommended_roles=["api_tester", "performance_tester", "unit_tester"],
|
|
142
|
+
test_patterns=["**/*_test.go"],
|
|
143
|
+
),
|
|
144
|
+
},
|
|
145
|
+
"go-gin": {
|
|
146
|
+
"files": [],
|
|
147
|
+
"go_mod_deps": ["github.com/gin-gonic/gin"],
|
|
148
|
+
"info": FrameworkInfo(
|
|
149
|
+
name="Go Gin",
|
|
150
|
+
category="backend",
|
|
151
|
+
language="go",
|
|
152
|
+
recommended_roles=["api_tester", "performance_tester", "unit_tester"],
|
|
153
|
+
test_patterns=["**/*_test.go"],
|
|
154
|
+
),
|
|
155
|
+
},
|
|
156
|
+
# Rust
|
|
157
|
+
"rust-actix": {
|
|
158
|
+
"files": [],
|
|
159
|
+
"cargo_deps": ["actix-web"],
|
|
160
|
+
"info": FrameworkInfo(
|
|
161
|
+
name="Actix Web",
|
|
162
|
+
category="backend",
|
|
163
|
+
language="rust",
|
|
164
|
+
recommended_roles=["api_tester", "performance_tester", "unit_tester"],
|
|
165
|
+
test_patterns=["**/tests/*.rs"],
|
|
166
|
+
),
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# Provider detection (check environment variables)
|
|
172
|
+
PROVIDER_ENV_VARS = {
|
|
173
|
+
"anthropic": "ANTHROPIC_API_KEY",
|
|
174
|
+
"openai": "OPENAI_API_KEY",
|
|
175
|
+
"google": "GOOGLE_API_KEY",
|
|
176
|
+
"xai": "XAI_API_KEY",
|
|
177
|
+
"zhipuai": "ZHIPUAI_API_KEY",
|
|
178
|
+
"deepseek": "DEEPSEEK_API_KEY",
|
|
179
|
+
"groq": "GROQ_API_KEY",
|
|
180
|
+
"together": "TOGETHER_API_KEY",
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
DEFAULT_CONFIG = """# SuperQode Configuration (used by SuperQE)
|
|
184
|
+
# https://super-agentic.ai/superqode
|
|
185
|
+
|
|
186
|
+
superqode:
|
|
187
|
+
version: "1.0"
|
|
188
|
+
team_name: "{team_name}"
|
|
189
|
+
|
|
190
|
+
qe:
|
|
191
|
+
# Output settings
|
|
192
|
+
output:
|
|
193
|
+
directory: ".superqode"
|
|
194
|
+
reports_format: "markdown"
|
|
195
|
+
keep_history: true
|
|
196
|
+
|
|
197
|
+
# Execution modes
|
|
198
|
+
modes:
|
|
199
|
+
quick_scan:
|
|
200
|
+
timeout: 60
|
|
201
|
+
depth: shallow
|
|
202
|
+
generate_tests: false
|
|
203
|
+
destructive: false
|
|
204
|
+
|
|
205
|
+
deep_qe:
|
|
206
|
+
timeout: 1800
|
|
207
|
+
depth: full
|
|
208
|
+
generate_tests: true
|
|
209
|
+
destructive: true
|
|
210
|
+
|
|
211
|
+
# Execution roles (deterministic - run existing tests only)
|
|
212
|
+
execution_roles:
|
|
213
|
+
smoke:
|
|
214
|
+
test_pattern: "**/test_smoke*.py"
|
|
215
|
+
fail_fast: true
|
|
216
|
+
|
|
217
|
+
sanity:
|
|
218
|
+
test_pattern: "**/test_sanity*.py"
|
|
219
|
+
fail_fast: false
|
|
220
|
+
|
|
221
|
+
regression:
|
|
222
|
+
test_pattern: "**/test_*.py"
|
|
223
|
+
detect_flakes: true
|
|
224
|
+
|
|
225
|
+
# Noise controls
|
|
226
|
+
noise:
|
|
227
|
+
min_confidence: 0.7
|
|
228
|
+
deduplicate: true
|
|
229
|
+
suppress_known_risks: false
|
|
230
|
+
min_severity: "low" # low, medium, high, critical
|
|
231
|
+
|
|
232
|
+
# Harness validation
|
|
233
|
+
harness:
|
|
234
|
+
enabled: true
|
|
235
|
+
timeout_seconds: 30
|
|
236
|
+
python_tools: ["ruff", "mypy"]
|
|
237
|
+
javascript_tools: ["eslint"]
|
|
238
|
+
go_tools: ["go vet"]
|
|
239
|
+
rust_tools: ["cargo check"]
|
|
240
|
+
shell_tools: ["shellcheck"]
|
|
241
|
+
custom_steps:
|
|
242
|
+
- name: "project-harness"
|
|
243
|
+
command: "python scripts/harness_check.py"
|
|
244
|
+
timeout_seconds: 120
|
|
245
|
+
enabled: false
|
|
246
|
+
|
|
247
|
+
# SuperOpt optimization hook (command-based, optional)
|
|
248
|
+
qe:
|
|
249
|
+
optimize:
|
|
250
|
+
enabled: false
|
|
251
|
+
command: ""
|
|
252
|
+
|
|
253
|
+
# Provider configuration (for BYOK mode)
|
|
254
|
+
providers:
|
|
255
|
+
anthropic:
|
|
256
|
+
api_key_env: "ANTHROPIC_API_KEY"
|
|
257
|
+
openai:
|
|
258
|
+
api_key_env: "OPENAI_API_KEY"
|
|
259
|
+
google:
|
|
260
|
+
api_key_env: "GOOGLE_API_KEY"
|
|
261
|
+
"""
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _detect_frameworks(project_root: Path) -> List[FrameworkInfo]:
|
|
265
|
+
"""Detect frameworks used in the project."""
|
|
266
|
+
detected = []
|
|
267
|
+
|
|
268
|
+
# Read package.json if exists
|
|
269
|
+
package_json_deps = set()
|
|
270
|
+
package_json_path = project_root / "package.json"
|
|
271
|
+
if package_json_path.exists():
|
|
272
|
+
try:
|
|
273
|
+
import json
|
|
274
|
+
|
|
275
|
+
pkg = json.loads(package_json_path.read_text())
|
|
276
|
+
package_json_deps.update(pkg.get("dependencies", {}).keys())
|
|
277
|
+
package_json_deps.update(pkg.get("devDependencies", {}).keys())
|
|
278
|
+
except Exception:
|
|
279
|
+
pass
|
|
280
|
+
|
|
281
|
+
# Read pyproject.toml if exists
|
|
282
|
+
pyproject_deps = set()
|
|
283
|
+
pyproject_path = project_root / "pyproject.toml"
|
|
284
|
+
if pyproject_path.exists():
|
|
285
|
+
try:
|
|
286
|
+
content = pyproject_path.read_text()
|
|
287
|
+
# Simple parsing - look for dependencies section
|
|
288
|
+
for line in content.split("\n"):
|
|
289
|
+
line = line.strip()
|
|
290
|
+
if "=" in line and not line.startswith("#"):
|
|
291
|
+
dep = line.split("=")[0].strip().strip('"').lower()
|
|
292
|
+
pyproject_deps.add(dep)
|
|
293
|
+
except Exception:
|
|
294
|
+
pass
|
|
295
|
+
|
|
296
|
+
# Read requirements.txt if exists
|
|
297
|
+
requirements_deps = set()
|
|
298
|
+
for req_file in ["requirements.txt", "requirements-dev.txt", "requirements/base.txt"]:
|
|
299
|
+
req_path = project_root / req_file
|
|
300
|
+
if req_path.exists():
|
|
301
|
+
try:
|
|
302
|
+
for line in req_path.read_text().split("\n"):
|
|
303
|
+
line = line.strip()
|
|
304
|
+
if line and not line.startswith("#"):
|
|
305
|
+
dep = line.split("==")[0].split(">=")[0].split("[")[0].strip()
|
|
306
|
+
requirements_deps.add(dep.lower())
|
|
307
|
+
except Exception:
|
|
308
|
+
pass
|
|
309
|
+
|
|
310
|
+
# Read go.mod if exists
|
|
311
|
+
go_mod_deps = set()
|
|
312
|
+
go_mod_path = project_root / "go.mod"
|
|
313
|
+
if go_mod_path.exists():
|
|
314
|
+
try:
|
|
315
|
+
for line in go_mod_path.read_text().split("\n"):
|
|
316
|
+
if line.strip() and not line.startswith("module") and not line.startswith("go "):
|
|
317
|
+
dep = line.strip().split()[0]
|
|
318
|
+
go_mod_deps.add(dep)
|
|
319
|
+
except Exception:
|
|
320
|
+
pass
|
|
321
|
+
|
|
322
|
+
# Read Cargo.toml if exists
|
|
323
|
+
cargo_deps = set()
|
|
324
|
+
cargo_path = project_root / "Cargo.toml"
|
|
325
|
+
if cargo_path.exists():
|
|
326
|
+
try:
|
|
327
|
+
content = cargo_path.read_text()
|
|
328
|
+
in_deps = False
|
|
329
|
+
for line in content.split("\n"):
|
|
330
|
+
if "[dependencies]" in line:
|
|
331
|
+
in_deps = True
|
|
332
|
+
elif line.startswith("[") and in_deps:
|
|
333
|
+
in_deps = False
|
|
334
|
+
elif in_deps and "=" in line:
|
|
335
|
+
dep = line.split("=")[0].strip()
|
|
336
|
+
cargo_deps.add(dep)
|
|
337
|
+
except Exception:
|
|
338
|
+
pass
|
|
339
|
+
|
|
340
|
+
# Check each framework
|
|
341
|
+
for framework_id, detector in FRAMEWORK_DETECTORS.items():
|
|
342
|
+
found = False
|
|
343
|
+
|
|
344
|
+
# Check for specific files
|
|
345
|
+
for file_pattern in detector.get("files", []):
|
|
346
|
+
if (project_root / file_pattern).exists():
|
|
347
|
+
found = True
|
|
348
|
+
break
|
|
349
|
+
|
|
350
|
+
# Check package.json dependencies
|
|
351
|
+
if not found:
|
|
352
|
+
for dep in detector.get("package_json_deps", []):
|
|
353
|
+
if dep in package_json_deps:
|
|
354
|
+
found = True
|
|
355
|
+
break
|
|
356
|
+
|
|
357
|
+
# Check pyproject.toml dependencies
|
|
358
|
+
if not found:
|
|
359
|
+
for dep in detector.get("pyproject_deps", []):
|
|
360
|
+
if dep.lower() in pyproject_deps:
|
|
361
|
+
found = True
|
|
362
|
+
break
|
|
363
|
+
|
|
364
|
+
# Check requirements.txt dependencies
|
|
365
|
+
if not found:
|
|
366
|
+
for dep in detector.get("requirements_deps", []):
|
|
367
|
+
if dep.lower() in requirements_deps:
|
|
368
|
+
found = True
|
|
369
|
+
break
|
|
370
|
+
|
|
371
|
+
# Check go.mod dependencies
|
|
372
|
+
if not found:
|
|
373
|
+
for dep in detector.get("go_mod_deps", []):
|
|
374
|
+
if any(dep in d for d in go_mod_deps):
|
|
375
|
+
found = True
|
|
376
|
+
break
|
|
377
|
+
|
|
378
|
+
# Check Cargo.toml dependencies
|
|
379
|
+
if not found:
|
|
380
|
+
for dep in detector.get("cargo_deps", []):
|
|
381
|
+
if dep in cargo_deps:
|
|
382
|
+
found = True
|
|
383
|
+
break
|
|
384
|
+
|
|
385
|
+
if found:
|
|
386
|
+
detected.append(detector["info"])
|
|
387
|
+
|
|
388
|
+
return detected
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _detect_providers() -> List[Tuple[str, str]]:
|
|
392
|
+
"""Detect configured providers from environment variables."""
|
|
393
|
+
configured = []
|
|
394
|
+
for provider, env_var in PROVIDER_ENV_VARS.items():
|
|
395
|
+
if os.environ.get(env_var):
|
|
396
|
+
configured.append((provider, env_var))
|
|
397
|
+
return configured
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def _create_guided_config(
|
|
401
|
+
team_name: str,
|
|
402
|
+
team_size: str,
|
|
403
|
+
frameworks: List[FrameworkInfo],
|
|
404
|
+
provider: Optional[str],
|
|
405
|
+
) -> str:
|
|
406
|
+
"""Create configuration based on guided setup choices."""
|
|
407
|
+
# Collect recommended roles from frameworks
|
|
408
|
+
roles = set()
|
|
409
|
+
test_patterns = []
|
|
410
|
+
for fw in frameworks:
|
|
411
|
+
roles.update(fw.recommended_roles)
|
|
412
|
+
test_patterns.extend(fw.test_patterns)
|
|
413
|
+
|
|
414
|
+
# Add default roles if none detected
|
|
415
|
+
if not roles:
|
|
416
|
+
roles = {"unit_tester", "api_tester", "security_tester"}
|
|
417
|
+
|
|
418
|
+
# Adjust roles based on team size
|
|
419
|
+
if team_size == "solo":
|
|
420
|
+
# Minimal set for solo developers
|
|
421
|
+
roles = {"unit_tester", "security_tester"}
|
|
422
|
+
elif team_size == "small":
|
|
423
|
+
# Keep detected roles, add security
|
|
424
|
+
roles.add("security_tester")
|
|
425
|
+
# "full" keeps all detected roles
|
|
426
|
+
|
|
427
|
+
# Build roles section
|
|
428
|
+
roles_yaml = ""
|
|
429
|
+
role_configs = {
|
|
430
|
+
"unit_tester": 'description: "Unit testing with coverage analysis"',
|
|
431
|
+
"api_tester": 'description: "API endpoint testing and validation"',
|
|
432
|
+
"security_tester": 'description: "Security vulnerability scanning"',
|
|
433
|
+
"e2e_tester": 'description: "End-to-end user journey testing"',
|
|
434
|
+
"performance_tester": 'description: "Performance and load testing"',
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
for role in sorted(roles):
|
|
438
|
+
if role in role_configs:
|
|
439
|
+
roles_yaml += f"""
|
|
440
|
+
{role}:
|
|
441
|
+
{role_configs[role]}
|
|
442
|
+
enabled: true"""
|
|
443
|
+
|
|
444
|
+
# Build test patterns
|
|
445
|
+
patterns_yaml = ""
|
|
446
|
+
if test_patterns:
|
|
447
|
+
unique_patterns = list(set(test_patterns))[:5] # Limit to 5
|
|
448
|
+
patterns_yaml = "\n ".join(f'- "{p}"' for p in unique_patterns)
|
|
449
|
+
|
|
450
|
+
# Provider config
|
|
451
|
+
provider_section = ""
|
|
452
|
+
if provider:
|
|
453
|
+
provider_section = f"""
|
|
454
|
+
# Default provider
|
|
455
|
+
default:
|
|
456
|
+
provider: {provider}
|
|
457
|
+
"""
|
|
458
|
+
|
|
459
|
+
# Framework info comment
|
|
460
|
+
framework_comment = ""
|
|
461
|
+
if frameworks:
|
|
462
|
+
fw_names = ", ".join(fw.name for fw in frameworks)
|
|
463
|
+
framework_comment = f"# Detected frameworks: {fw_names}\n"
|
|
464
|
+
|
|
465
|
+
return f'''{framework_comment}# SuperQode Configuration (used by SuperQE)
|
|
466
|
+
# Generated by guided setup
|
|
467
|
+
|
|
468
|
+
superqode:
|
|
469
|
+
version: "2.0"
|
|
470
|
+
team_name: "{team_name}"
|
|
471
|
+
{provider_section}
|
|
472
|
+
team:
|
|
473
|
+
qe:
|
|
474
|
+
description: "Quality Engineering"
|
|
475
|
+
roles:{roles_yaml}
|
|
476
|
+
|
|
477
|
+
qe:
|
|
478
|
+
output:
|
|
479
|
+
directory: ".superqode"
|
|
480
|
+
reports_format: "markdown"
|
|
481
|
+
|
|
482
|
+
modes:
|
|
483
|
+
quick_scan:
|
|
484
|
+
timeout: 60
|
|
485
|
+
depth: shallow
|
|
486
|
+
|
|
487
|
+
deep_qe:
|
|
488
|
+
timeout: 1800
|
|
489
|
+
depth: full
|
|
490
|
+
generate_tests: true
|
|
491
|
+
|
|
492
|
+
noise:
|
|
493
|
+
min_confidence: 0.7
|
|
494
|
+
deduplicate: true
|
|
495
|
+
min_severity: "low"
|
|
496
|
+
|
|
497
|
+
harness:
|
|
498
|
+
enabled: true
|
|
499
|
+
timeout_seconds: 30
|
|
500
|
+
'''
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
@click.command("init")
|
|
504
|
+
@click.argument("path", type=click.Path(), default=".")
|
|
505
|
+
@click.option("--force", "-f", is_flag=True, help="Overwrite existing configuration")
|
|
506
|
+
@click.option("--minimal", "-m", is_flag=True, help="Create minimal configuration")
|
|
507
|
+
@click.option("--guided", "-g", is_flag=True, help="Run guided setup wizard")
|
|
508
|
+
def init(path: str, force: bool, minimal: bool, guided: bool):
|
|
509
|
+
"""Initialize SuperQE configuration for a project.
|
|
510
|
+
|
|
511
|
+
Creates a superqode.yaml configuration file and .superqode directory.
|
|
512
|
+
|
|
513
|
+
Examples:
|
|
514
|
+
|
|
515
|
+
superqe init # Initialize current directory
|
|
516
|
+
|
|
517
|
+
superqe init ./myproject # Initialize specific directory
|
|
518
|
+
|
|
519
|
+
superqe init --minimal # Create minimal config
|
|
520
|
+
|
|
521
|
+
superqe init --guided # Run guided setup wizard
|
|
522
|
+
"""
|
|
523
|
+
project_root = Path(path).resolve()
|
|
524
|
+
|
|
525
|
+
console.print()
|
|
526
|
+
console.print(Panel("[bold]SuperQE Initialization[/bold]", border_style="cyan"))
|
|
527
|
+
console.print()
|
|
528
|
+
|
|
529
|
+
# Check if project exists
|
|
530
|
+
if not project_root.exists():
|
|
531
|
+
console.print(f"[red]Error:[/red] Path does not exist: {project_root}")
|
|
532
|
+
return 1
|
|
533
|
+
|
|
534
|
+
config_file = project_root / "superqode.yaml"
|
|
535
|
+
superqode_dir = project_root / ".superqode"
|
|
536
|
+
|
|
537
|
+
# Check for existing config
|
|
538
|
+
if config_file.exists() and not force:
|
|
539
|
+
console.print(f"[yellow]Configuration already exists:[/yellow] {config_file}")
|
|
540
|
+
if not Confirm.ask("Overwrite existing configuration?"):
|
|
541
|
+
console.print("[dim]Initialization cancelled.[/dim]")
|
|
542
|
+
return 0
|
|
543
|
+
|
|
544
|
+
# Guided setup mode
|
|
545
|
+
if guided:
|
|
546
|
+
return _run_guided_setup(project_root, config_file, superqode_dir)
|
|
547
|
+
|
|
548
|
+
# Standard setup
|
|
549
|
+
# Detect project info
|
|
550
|
+
team_name = _detect_team_name(project_root)
|
|
551
|
+
|
|
552
|
+
# Ask for team name
|
|
553
|
+
team_name = Prompt.ask("Team name", default=team_name)
|
|
554
|
+
|
|
555
|
+
# Create configuration
|
|
556
|
+
if minimal:
|
|
557
|
+
config_content = _create_minimal_config(team_name)
|
|
558
|
+
else:
|
|
559
|
+
config_content = DEFAULT_CONFIG.format(team_name=team_name)
|
|
560
|
+
|
|
561
|
+
# Write config file
|
|
562
|
+
config_file.write_text(config_content)
|
|
563
|
+
console.print(f"[green]✓[/green] Created {config_file}")
|
|
564
|
+
console.print(
|
|
565
|
+
"[dim]⚡ Power QE roles: unit, integration, api, ui, accessibility, security, usability[/dim]"
|
|
566
|
+
)
|
|
567
|
+
console.print(
|
|
568
|
+
"[dim]💡 Tip: Update each role's job_description in superqode.yaml for best results[/dim]"
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
# Create .superqode directory structure
|
|
572
|
+
_create_superqode_directory(superqode_dir)
|
|
573
|
+
|
|
574
|
+
# Detect test patterns
|
|
575
|
+
_detect_and_suggest_patterns(project_root)
|
|
576
|
+
|
|
577
|
+
console.print()
|
|
578
|
+
console.print("[green]SuperQE initialized successfully![/green]")
|
|
579
|
+
console.print()
|
|
580
|
+
console.print("[dim]Next steps:[/dim]")
|
|
581
|
+
console.print(" 1. Review superqode.yaml and customize settings")
|
|
582
|
+
console.print(" 2. Run [cyan]superqe run . --mode quick[/cyan] for a quick scan")
|
|
583
|
+
console.print(" 3. Run [cyan]superqe run . --mode deep[/cyan] for full analysis")
|
|
584
|
+
console.print()
|
|
585
|
+
|
|
586
|
+
return 0
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
def _run_guided_setup(project_root: Path, config_file: Path, superqode_dir: Path) -> int:
|
|
590
|
+
"""Run the guided setup wizard."""
|
|
591
|
+
console.print("[bold cyan]Step 1/4: Project Detection[/bold cyan]")
|
|
592
|
+
console.print()
|
|
593
|
+
|
|
594
|
+
# Detect frameworks
|
|
595
|
+
frameworks = _detect_frameworks(project_root)
|
|
596
|
+
if frameworks:
|
|
597
|
+
console.print("[green]Detected frameworks:[/green]")
|
|
598
|
+
table = Table(show_header=False, box=None)
|
|
599
|
+
table.add_column("Framework", style="cyan")
|
|
600
|
+
table.add_column("Category")
|
|
601
|
+
table.add_column("Language")
|
|
602
|
+
for fw in frameworks:
|
|
603
|
+
table.add_row(fw.name, fw.category, fw.language)
|
|
604
|
+
console.print(table)
|
|
605
|
+
else:
|
|
606
|
+
console.print("[dim]No specific framework detected[/dim]")
|
|
607
|
+
|
|
608
|
+
# Detect test files
|
|
609
|
+
_detect_and_suggest_patterns(project_root)
|
|
610
|
+
console.print()
|
|
611
|
+
|
|
612
|
+
# Step 2: Team size
|
|
613
|
+
console.print("[bold cyan]Step 2/4: Team Size[/bold cyan]")
|
|
614
|
+
console.print()
|
|
615
|
+
console.print("Select your team size to optimize QE role configuration:")
|
|
616
|
+
console.print(" [cyan]1[/cyan]. Solo developer (minimal roles, fast feedback)")
|
|
617
|
+
console.print(" [cyan]2[/cyan]. Small team (2-10 people, balanced coverage)")
|
|
618
|
+
console.print(" [cyan]3[/cyan]. Full team (all roles enabled)")
|
|
619
|
+
console.print()
|
|
620
|
+
|
|
621
|
+
team_size_choice = Prompt.ask("Team size", choices=["1", "2", "3"], default="2")
|
|
622
|
+
team_size_map = {"1": "solo", "2": "small", "3": "full"}
|
|
623
|
+
team_size = team_size_map[team_size_choice]
|
|
624
|
+
console.print()
|
|
625
|
+
|
|
626
|
+
# Step 3: Provider configuration
|
|
627
|
+
console.print("[bold cyan]Step 3/4: Provider Configuration[/bold cyan]")
|
|
628
|
+
console.print()
|
|
629
|
+
|
|
630
|
+
configured_providers = _detect_providers()
|
|
631
|
+
selected_provider = None
|
|
632
|
+
|
|
633
|
+
if configured_providers:
|
|
634
|
+
console.print("[green]Detected API keys:[/green]")
|
|
635
|
+
for provider, env_var in configured_providers:
|
|
636
|
+
console.print(f" [cyan]{provider}[/cyan] ({env_var})")
|
|
637
|
+
console.print()
|
|
638
|
+
|
|
639
|
+
if len(configured_providers) == 1:
|
|
640
|
+
selected_provider = configured_providers[0][0]
|
|
641
|
+
console.print(f"[dim]Using {selected_provider} as default provider[/dim]")
|
|
642
|
+
else:
|
|
643
|
+
provider_names = [p[0] for p in configured_providers]
|
|
644
|
+
selected_provider = Prompt.ask(
|
|
645
|
+
"Select default provider", choices=provider_names, default=provider_names[0]
|
|
646
|
+
)
|
|
647
|
+
else:
|
|
648
|
+
console.print("[yellow]No API keys detected in environment.[/yellow]")
|
|
649
|
+
console.print("[dim]You can configure providers later in superqode.yaml[/dim]")
|
|
650
|
+
console.print()
|
|
651
|
+
console.print("Free tier options:")
|
|
652
|
+
console.print(" - ZhipuAI (ZHIPUAI_API_KEY)")
|
|
653
|
+
console.print(" - Groq (GROQ_API_KEY)")
|
|
654
|
+
console.print()
|
|
655
|
+
|
|
656
|
+
console.print()
|
|
657
|
+
|
|
658
|
+
# Step 4: Team name
|
|
659
|
+
console.print("[bold cyan]Step 4/4: Team Name[/bold cyan]")
|
|
660
|
+
console.print()
|
|
661
|
+
team_name = _detect_team_name(project_root)
|
|
662
|
+
team_name = Prompt.ask("Team name", default=team_name)
|
|
663
|
+
console.print()
|
|
664
|
+
|
|
665
|
+
# Generate configuration
|
|
666
|
+
config_content = _create_guided_config(
|
|
667
|
+
team_name=team_name,
|
|
668
|
+
team_size=team_size,
|
|
669
|
+
frameworks=frameworks,
|
|
670
|
+
provider=selected_provider,
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
# Write config file
|
|
674
|
+
config_file.write_text(config_content)
|
|
675
|
+
console.print(f"[green]✓[/green] Created {config_file}")
|
|
676
|
+
console.print(
|
|
677
|
+
"[dim]⚡ Power QE roles: unit, integration, api, ui, accessibility, security, usability[/dim]"
|
|
678
|
+
)
|
|
679
|
+
console.print(
|
|
680
|
+
"[dim]💡 Tip: Update each role's job_description in superqode.yaml for best results[/dim]"
|
|
681
|
+
)
|
|
682
|
+
|
|
683
|
+
# Create directory structure
|
|
684
|
+
_create_superqode_directory(superqode_dir)
|
|
685
|
+
|
|
686
|
+
# Success message
|
|
687
|
+
console.print()
|
|
688
|
+
console.print(
|
|
689
|
+
Panel("[bold green]SuperQE initialized successfully![/bold green]", border_style="green")
|
|
690
|
+
)
|
|
691
|
+
console.print()
|
|
692
|
+
|
|
693
|
+
# Show what was configured
|
|
694
|
+
if frameworks:
|
|
695
|
+
fw_names = ", ".join(fw.name for fw in frameworks)
|
|
696
|
+
console.print(f"[dim]Frameworks:[/dim] {fw_names}")
|
|
697
|
+
console.print(f"[dim]Team size:[/dim] {team_size}")
|
|
698
|
+
if selected_provider:
|
|
699
|
+
console.print(f"[dim]Provider:[/dim] {selected_provider}")
|
|
700
|
+
console.print()
|
|
701
|
+
|
|
702
|
+
# Offer to run quick scan
|
|
703
|
+
if Confirm.ask("Run a quick scan to validate setup?", default=True):
|
|
704
|
+
console.print()
|
|
705
|
+
console.print("[cyan]Running quick scan...[/cyan]")
|
|
706
|
+
console.print()
|
|
707
|
+
try:
|
|
708
|
+
result = subprocess.run(
|
|
709
|
+
["superqe", "run", str(project_root), "--mode", "quick"],
|
|
710
|
+
cwd=str(project_root),
|
|
711
|
+
)
|
|
712
|
+
if result.returncode == 0:
|
|
713
|
+
console.print()
|
|
714
|
+
console.print("[green]Setup validated successfully![/green]")
|
|
715
|
+
else:
|
|
716
|
+
console.print()
|
|
717
|
+
console.print(
|
|
718
|
+
"[yellow]Quick scan completed with findings. Check the report above.[/yellow]"
|
|
719
|
+
)
|
|
720
|
+
except Exception as e:
|
|
721
|
+
console.print(f"[dim]Could not run quick scan: {e}[/dim]")
|
|
722
|
+
else:
|
|
723
|
+
console.print()
|
|
724
|
+
console.print("[dim]Next steps:[/dim]")
|
|
725
|
+
console.print(" 1. Run [cyan]superqe run . --mode quick[/cyan] for a quick scan")
|
|
726
|
+
console.print(" 2. Run [cyan]superqe dashboard[/cyan] to view results")
|
|
727
|
+
console.print()
|
|
728
|
+
|
|
729
|
+
return 0
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
def _create_superqode_directory(superqode_dir: Path) -> None:
|
|
733
|
+
"""Create the .superqode directory structure."""
|
|
734
|
+
superqode_dir.mkdir(exist_ok=True)
|
|
735
|
+
(superqode_dir / "qe-artifacts").mkdir(exist_ok=True)
|
|
736
|
+
(superqode_dir / "qe-artifacts" / "patches").mkdir(exist_ok=True)
|
|
737
|
+
(superqode_dir / "qe-artifacts" / "generated-tests").mkdir(exist_ok=True)
|
|
738
|
+
(superqode_dir / "qe-artifacts" / "qr").mkdir(exist_ok=True)
|
|
739
|
+
(superqode_dir / "history").mkdir(exist_ok=True)
|
|
740
|
+
console.print(f"[green]✓[/green] Created {superqode_dir}/")
|
|
741
|
+
|
|
742
|
+
# Create .gitignore in .superqode
|
|
743
|
+
gitignore_file = superqode_dir / ".gitignore"
|
|
744
|
+
gitignore_content = """# SuperQode / SuperQE temporary files
|
|
745
|
+
temp/
|
|
746
|
+
*.log
|
|
747
|
+
workspace-state.json
|
|
748
|
+
|
|
749
|
+
# Keep artifacts
|
|
750
|
+
!qe-artifacts/
|
|
751
|
+
"""
|
|
752
|
+
gitignore_file.write_text(gitignore_content)
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
def _detect_team_name(project_root: Path) -> str:
|
|
756
|
+
"""Detect team name from project directory or git config."""
|
|
757
|
+
# Try to get from git config
|
|
758
|
+
try:
|
|
759
|
+
import subprocess
|
|
760
|
+
|
|
761
|
+
result = subprocess.run(
|
|
762
|
+
["git", "config", "user.name"],
|
|
763
|
+
cwd=str(project_root),
|
|
764
|
+
capture_output=True,
|
|
765
|
+
text=True,
|
|
766
|
+
)
|
|
767
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
768
|
+
return f"{result.stdout.strip()}'s Team"
|
|
769
|
+
except Exception:
|
|
770
|
+
pass
|
|
771
|
+
|
|
772
|
+
# Fall back to directory name
|
|
773
|
+
return f"{project_root.name} Team"
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
def _create_minimal_config(team_name: str) -> str:
|
|
777
|
+
"""Create a minimal configuration."""
|
|
778
|
+
return f'''# SuperQode Configuration (Minimal, used by SuperQE)
|
|
779
|
+
superqode:
|
|
780
|
+
version: "1.0"
|
|
781
|
+
team_name: "{team_name}"
|
|
782
|
+
|
|
783
|
+
qe:
|
|
784
|
+
modes:
|
|
785
|
+
quick_scan:
|
|
786
|
+
timeout: 60
|
|
787
|
+
deep_qe:
|
|
788
|
+
timeout: 1800
|
|
789
|
+
|
|
790
|
+
noise:
|
|
791
|
+
min_confidence: 0.7
|
|
792
|
+
deduplicate: true
|
|
793
|
+
'''
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
def _detect_and_suggest_patterns(project_root: Path) -> None:
|
|
797
|
+
"""Detect existing test patterns and suggest configuration."""
|
|
798
|
+
patterns_found = []
|
|
799
|
+
|
|
800
|
+
# Python tests
|
|
801
|
+
pytest_files = list(project_root.glob("**/test_*.py"))
|
|
802
|
+
if pytest_files:
|
|
803
|
+
patterns_found.append(f" - Python (pytest): {len(pytest_files)} test files")
|
|
804
|
+
|
|
805
|
+
# JavaScript tests
|
|
806
|
+
jest_files = list(project_root.glob("**/*.test.js")) + list(project_root.glob("**/*.spec.js"))
|
|
807
|
+
if jest_files:
|
|
808
|
+
patterns_found.append(f" - JavaScript (jest): {len(jest_files)} test files")
|
|
809
|
+
|
|
810
|
+
# TypeScript tests
|
|
811
|
+
ts_test_files = list(project_root.glob("**/*.test.ts")) + list(
|
|
812
|
+
project_root.glob("**/*.spec.ts")
|
|
813
|
+
)
|
|
814
|
+
if ts_test_files:
|
|
815
|
+
patterns_found.append(f" - TypeScript: {len(ts_test_files)} test files")
|
|
816
|
+
|
|
817
|
+
# Go tests
|
|
818
|
+
go_test_files = list(project_root.glob("**/*_test.go"))
|
|
819
|
+
if go_test_files:
|
|
820
|
+
patterns_found.append(f" - Go: {len(go_test_files)} test files")
|
|
821
|
+
|
|
822
|
+
if patterns_found:
|
|
823
|
+
console.print()
|
|
824
|
+
console.print("[dim]Detected test files:[/dim]")
|
|
825
|
+
for p in patterns_found:
|
|
826
|
+
console.print(p)
|