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.
Files changed (288) hide show
  1. superqode/__init__.py +33 -0
  2. superqode/acp/__init__.py +23 -0
  3. superqode/acp/client.py +913 -0
  4. superqode/acp/permission_screen.py +457 -0
  5. superqode/acp/types.py +480 -0
  6. superqode/acp_discovery.py +856 -0
  7. superqode/agent/__init__.py +22 -0
  8. superqode/agent/edit_strategies.py +334 -0
  9. superqode/agent/loop.py +892 -0
  10. superqode/agent/qe_report_templates.py +39 -0
  11. superqode/agent/system_prompts.py +353 -0
  12. superqode/agent_output.py +721 -0
  13. superqode/agent_stream.py +953 -0
  14. superqode/agents/__init__.py +59 -0
  15. superqode/agents/acp_registry.py +305 -0
  16. superqode/agents/client.py +249 -0
  17. superqode/agents/data/augmentcode.com.toml +51 -0
  18. superqode/agents/data/cagent.dev.toml +51 -0
  19. superqode/agents/data/claude.com.toml +60 -0
  20. superqode/agents/data/codeassistant.dev.toml +51 -0
  21. superqode/agents/data/codex.openai.com.toml +57 -0
  22. superqode/agents/data/fastagent.ai.toml +66 -0
  23. superqode/agents/data/geminicli.com.toml +77 -0
  24. superqode/agents/data/goose.block.xyz.toml +54 -0
  25. superqode/agents/data/junie.jetbrains.com.toml +56 -0
  26. superqode/agents/data/kimi.moonshot.cn.toml +57 -0
  27. superqode/agents/data/llmlingagent.dev.toml +51 -0
  28. superqode/agents/data/molt.bot.toml +49 -0
  29. superqode/agents/data/opencode.ai.toml +60 -0
  30. superqode/agents/data/stakpak.dev.toml +51 -0
  31. superqode/agents/data/vtcode.dev.toml +51 -0
  32. superqode/agents/discovery.py +266 -0
  33. superqode/agents/messaging.py +160 -0
  34. superqode/agents/persona.py +166 -0
  35. superqode/agents/registry.py +421 -0
  36. superqode/agents/schema.py +72 -0
  37. superqode/agents/unified.py +367 -0
  38. superqode/app/__init__.py +111 -0
  39. superqode/app/constants.py +314 -0
  40. superqode/app/css.py +366 -0
  41. superqode/app/models.py +118 -0
  42. superqode/app/suggester.py +125 -0
  43. superqode/app/widgets.py +1591 -0
  44. superqode/app_enhanced.py +399 -0
  45. superqode/app_main.py +17187 -0
  46. superqode/approval.py +312 -0
  47. superqode/atomic.py +296 -0
  48. superqode/commands/__init__.py +1 -0
  49. superqode/commands/acp.py +965 -0
  50. superqode/commands/agents.py +180 -0
  51. superqode/commands/auth.py +278 -0
  52. superqode/commands/config.py +374 -0
  53. superqode/commands/init.py +826 -0
  54. superqode/commands/providers.py +819 -0
  55. superqode/commands/qe.py +1145 -0
  56. superqode/commands/roles.py +380 -0
  57. superqode/commands/serve.py +172 -0
  58. superqode/commands/suggestions.py +127 -0
  59. superqode/commands/superqe.py +460 -0
  60. superqode/config/__init__.py +51 -0
  61. superqode/config/loader.py +812 -0
  62. superqode/config/schema.py +498 -0
  63. superqode/core/__init__.py +111 -0
  64. superqode/core/roles.py +281 -0
  65. superqode/danger.py +386 -0
  66. superqode/data/superqode-template.yaml +1522 -0
  67. superqode/design_system.py +1080 -0
  68. superqode/dialogs/__init__.py +6 -0
  69. superqode/dialogs/base.py +39 -0
  70. superqode/dialogs/model.py +130 -0
  71. superqode/dialogs/provider.py +870 -0
  72. superqode/diff_view.py +919 -0
  73. superqode/enterprise.py +21 -0
  74. superqode/evaluation/__init__.py +25 -0
  75. superqode/evaluation/adapters.py +93 -0
  76. superqode/evaluation/behaviors.py +89 -0
  77. superqode/evaluation/engine.py +209 -0
  78. superqode/evaluation/scenarios.py +96 -0
  79. superqode/execution/__init__.py +36 -0
  80. superqode/execution/linter.py +538 -0
  81. superqode/execution/modes.py +347 -0
  82. superqode/execution/resolver.py +283 -0
  83. superqode/execution/runner.py +642 -0
  84. superqode/file_explorer.py +811 -0
  85. superqode/file_viewer.py +471 -0
  86. superqode/flash.py +183 -0
  87. superqode/guidance/__init__.py +58 -0
  88. superqode/guidance/config.py +203 -0
  89. superqode/guidance/prompts.py +71 -0
  90. superqode/harness/__init__.py +54 -0
  91. superqode/harness/accelerator.py +291 -0
  92. superqode/harness/config.py +319 -0
  93. superqode/harness/validator.py +147 -0
  94. superqode/history.py +279 -0
  95. superqode/integrations/superopt_runner.py +124 -0
  96. superqode/logging/__init__.py +49 -0
  97. superqode/logging/adapters.py +219 -0
  98. superqode/logging/formatter.py +923 -0
  99. superqode/logging/integration.py +341 -0
  100. superqode/logging/sinks.py +170 -0
  101. superqode/logging/unified_log.py +417 -0
  102. superqode/lsp/__init__.py +26 -0
  103. superqode/lsp/client.py +544 -0
  104. superqode/main.py +1069 -0
  105. superqode/mcp/__init__.py +89 -0
  106. superqode/mcp/auth_storage.py +380 -0
  107. superqode/mcp/client.py +1236 -0
  108. superqode/mcp/config.py +319 -0
  109. superqode/mcp/integration.py +337 -0
  110. superqode/mcp/oauth.py +436 -0
  111. superqode/mcp/oauth_callback.py +385 -0
  112. superqode/mcp/types.py +290 -0
  113. superqode/memory/__init__.py +31 -0
  114. superqode/memory/feedback.py +342 -0
  115. superqode/memory/store.py +522 -0
  116. superqode/notifications.py +369 -0
  117. superqode/optimization/__init__.py +5 -0
  118. superqode/optimization/config.py +33 -0
  119. superqode/permissions/__init__.py +25 -0
  120. superqode/permissions/rules.py +488 -0
  121. superqode/plan.py +323 -0
  122. superqode/providers/__init__.py +33 -0
  123. superqode/providers/gateway/__init__.py +165 -0
  124. superqode/providers/gateway/base.py +228 -0
  125. superqode/providers/gateway/litellm_gateway.py +1170 -0
  126. superqode/providers/gateway/openresponses_gateway.py +436 -0
  127. superqode/providers/health.py +297 -0
  128. superqode/providers/huggingface/__init__.py +74 -0
  129. superqode/providers/huggingface/downloader.py +472 -0
  130. superqode/providers/huggingface/endpoints.py +442 -0
  131. superqode/providers/huggingface/hub.py +531 -0
  132. superqode/providers/huggingface/inference.py +394 -0
  133. superqode/providers/huggingface/transformers_runner.py +516 -0
  134. superqode/providers/local/__init__.py +100 -0
  135. superqode/providers/local/base.py +438 -0
  136. superqode/providers/local/discovery.py +418 -0
  137. superqode/providers/local/lmstudio.py +256 -0
  138. superqode/providers/local/mlx.py +457 -0
  139. superqode/providers/local/ollama.py +486 -0
  140. superqode/providers/local/sglang.py +268 -0
  141. superqode/providers/local/tgi.py +260 -0
  142. superqode/providers/local/tool_support.py +477 -0
  143. superqode/providers/local/vllm.py +258 -0
  144. superqode/providers/manager.py +1338 -0
  145. superqode/providers/models.py +1016 -0
  146. superqode/providers/models_dev.py +578 -0
  147. superqode/providers/openresponses/__init__.py +87 -0
  148. superqode/providers/openresponses/converters/__init__.py +17 -0
  149. superqode/providers/openresponses/converters/messages.py +343 -0
  150. superqode/providers/openresponses/converters/tools.py +268 -0
  151. superqode/providers/openresponses/schema/__init__.py +56 -0
  152. superqode/providers/openresponses/schema/models.py +585 -0
  153. superqode/providers/openresponses/streaming/__init__.py +5 -0
  154. superqode/providers/openresponses/streaming/parser.py +338 -0
  155. superqode/providers/openresponses/tools/__init__.py +21 -0
  156. superqode/providers/openresponses/tools/apply_patch.py +352 -0
  157. superqode/providers/openresponses/tools/code_interpreter.py +290 -0
  158. superqode/providers/openresponses/tools/file_search.py +333 -0
  159. superqode/providers/openresponses/tools/mcp_adapter.py +252 -0
  160. superqode/providers/registry.py +716 -0
  161. superqode/providers/usage.py +332 -0
  162. superqode/pure_mode.py +384 -0
  163. superqode/qr/__init__.py +23 -0
  164. superqode/qr/dashboard.py +781 -0
  165. superqode/qr/generator.py +1018 -0
  166. superqode/qr/templates.py +135 -0
  167. superqode/safety/__init__.py +41 -0
  168. superqode/safety/sandbox.py +413 -0
  169. superqode/safety/warnings.py +256 -0
  170. superqode/server/__init__.py +33 -0
  171. superqode/server/lsp_server.py +775 -0
  172. superqode/server/web.py +250 -0
  173. superqode/session/__init__.py +25 -0
  174. superqode/session/persistence.py +580 -0
  175. superqode/session/sharing.py +477 -0
  176. superqode/session.py +475 -0
  177. superqode/sidebar.py +2991 -0
  178. superqode/stream_view.py +648 -0
  179. superqode/styles/__init__.py +3 -0
  180. superqode/superqe/__init__.py +184 -0
  181. superqode/superqe/acp_runner.py +1064 -0
  182. superqode/superqe/constitution/__init__.py +62 -0
  183. superqode/superqe/constitution/evaluator.py +308 -0
  184. superqode/superqe/constitution/loader.py +432 -0
  185. superqode/superqe/constitution/schema.py +250 -0
  186. superqode/superqe/events.py +591 -0
  187. superqode/superqe/frameworks/__init__.py +65 -0
  188. superqode/superqe/frameworks/base.py +234 -0
  189. superqode/superqe/frameworks/e2e.py +263 -0
  190. superqode/superqe/frameworks/executor.py +237 -0
  191. superqode/superqe/frameworks/javascript.py +409 -0
  192. superqode/superqe/frameworks/python.py +373 -0
  193. superqode/superqe/frameworks/registry.py +92 -0
  194. superqode/superqe/mcp_tools/__init__.py +47 -0
  195. superqode/superqe/mcp_tools/core_tools.py +418 -0
  196. superqode/superqe/mcp_tools/registry.py +230 -0
  197. superqode/superqe/mcp_tools/testing_tools.py +167 -0
  198. superqode/superqe/noise.py +89 -0
  199. superqode/superqe/orchestrator.py +778 -0
  200. superqode/superqe/roles.py +609 -0
  201. superqode/superqe/session.py +713 -0
  202. superqode/superqe/skills/__init__.py +57 -0
  203. superqode/superqe/skills/base.py +106 -0
  204. superqode/superqe/skills/core_skills.py +899 -0
  205. superqode/superqe/skills/registry.py +90 -0
  206. superqode/superqe/verifier.py +101 -0
  207. superqode/superqe_cli.py +76 -0
  208. superqode/tool_call.py +358 -0
  209. superqode/tools/__init__.py +93 -0
  210. superqode/tools/agent_tools.py +496 -0
  211. superqode/tools/base.py +324 -0
  212. superqode/tools/batch_tool.py +133 -0
  213. superqode/tools/diagnostics.py +311 -0
  214. superqode/tools/edit_tools.py +653 -0
  215. superqode/tools/enhanced_base.py +515 -0
  216. superqode/tools/file_tools.py +269 -0
  217. superqode/tools/file_tracking.py +45 -0
  218. superqode/tools/lsp_tools.py +610 -0
  219. superqode/tools/network_tools.py +350 -0
  220. superqode/tools/permissions.py +400 -0
  221. superqode/tools/question_tool.py +324 -0
  222. superqode/tools/search_tools.py +598 -0
  223. superqode/tools/shell_tools.py +259 -0
  224. superqode/tools/todo_tools.py +121 -0
  225. superqode/tools/validation.py +80 -0
  226. superqode/tools/web_tools.py +639 -0
  227. superqode/tui.py +1152 -0
  228. superqode/tui_integration.py +875 -0
  229. superqode/tui_widgets/__init__.py +27 -0
  230. superqode/tui_widgets/widgets/__init__.py +18 -0
  231. superqode/tui_widgets/widgets/progress.py +185 -0
  232. superqode/tui_widgets/widgets/tool_display.py +188 -0
  233. superqode/undo_manager.py +574 -0
  234. superqode/utils/__init__.py +5 -0
  235. superqode/utils/error_handling.py +323 -0
  236. superqode/utils/fuzzy.py +257 -0
  237. superqode/widgets/__init__.py +477 -0
  238. superqode/widgets/agent_collab.py +390 -0
  239. superqode/widgets/agent_store.py +936 -0
  240. superqode/widgets/agent_switcher.py +395 -0
  241. superqode/widgets/animation_manager.py +284 -0
  242. superqode/widgets/code_context.py +356 -0
  243. superqode/widgets/command_palette.py +412 -0
  244. superqode/widgets/connection_status.py +537 -0
  245. superqode/widgets/conversation_history.py +470 -0
  246. superqode/widgets/diff_indicator.py +155 -0
  247. superqode/widgets/enhanced_status_bar.py +385 -0
  248. superqode/widgets/enhanced_toast.py +476 -0
  249. superqode/widgets/file_browser.py +809 -0
  250. superqode/widgets/file_reference.py +585 -0
  251. superqode/widgets/issue_timeline.py +340 -0
  252. superqode/widgets/leader_key.py +264 -0
  253. superqode/widgets/mode_switcher.py +445 -0
  254. superqode/widgets/model_picker.py +234 -0
  255. superqode/widgets/permission_preview.py +1205 -0
  256. superqode/widgets/prompt.py +358 -0
  257. superqode/widgets/provider_connect.py +725 -0
  258. superqode/widgets/pty_shell.py +587 -0
  259. superqode/widgets/qe_dashboard.py +321 -0
  260. superqode/widgets/resizable_sidebar.py +377 -0
  261. superqode/widgets/response_changes.py +218 -0
  262. superqode/widgets/response_display.py +528 -0
  263. superqode/widgets/rich_tool_display.py +613 -0
  264. superqode/widgets/sidebar_panels.py +1180 -0
  265. superqode/widgets/slash_complete.py +356 -0
  266. superqode/widgets/split_view.py +612 -0
  267. superqode/widgets/status_bar.py +273 -0
  268. superqode/widgets/superqode_display.py +786 -0
  269. superqode/widgets/thinking_display.py +815 -0
  270. superqode/widgets/throbber.py +87 -0
  271. superqode/widgets/toast.py +206 -0
  272. superqode/widgets/unified_output.py +1073 -0
  273. superqode/workspace/__init__.py +75 -0
  274. superqode/workspace/artifacts.py +472 -0
  275. superqode/workspace/coordinator.py +353 -0
  276. superqode/workspace/diff_tracker.py +429 -0
  277. superqode/workspace/git_guard.py +373 -0
  278. superqode/workspace/git_snapshot.py +526 -0
  279. superqode/workspace/manager.py +750 -0
  280. superqode/workspace/snapshot.py +357 -0
  281. superqode/workspace/watcher.py +535 -0
  282. superqode/workspace/worktree.py +440 -0
  283. superqode-0.1.5.dist-info/METADATA +204 -0
  284. superqode-0.1.5.dist-info/RECORD +288 -0
  285. superqode-0.1.5.dist-info/WHEEL +5 -0
  286. superqode-0.1.5.dist-info/entry_points.txt +3 -0
  287. superqode-0.1.5.dist-info/licenses/LICENSE +648 -0
  288. superqode-0.1.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,281 @@
1
+ """
2
+ Unified Role Definitions for SuperQode.
3
+
4
+ Provides a single interface for all role types across the platform:
5
+ - dev: Development roles (fullstack, frontend, backend, etc.)
6
+ - qe: Quality Engineering roles (smoke, regression, security, etc.)
7
+ - devops: DevOps roles (deployment, infrastructure, monitoring)
8
+
9
+ Each role can operate in either BYOK or ACP mode.
10
+ """
11
+
12
+ from dataclasses import dataclass, field
13
+ from enum import Enum
14
+ from typing import Dict, List, Literal, Optional, Any
15
+
16
+ from ..__init__ import __version__
17
+
18
+
19
+ class RoleCategory(Enum):
20
+ """Role category (top-level grouping)."""
21
+
22
+ DEV = "dev"
23
+ QE = "qe"
24
+ DEVOPS = "devops"
25
+
26
+
27
+ class QERoleType(Enum):
28
+ """Type of QE role."""
29
+
30
+ EXECUTION = "execution" # Runs existing tests (smoke, sanity, regression)
31
+ DETECTION = "detection" # Proactive issue detection (security, api, e2e)
32
+
33
+
34
+ @dataclass
35
+ class Role:
36
+ """
37
+ Unified role definition.
38
+
39
+ Represents a role in the SuperQode system, whether it's a development,
40
+ QE, or DevOps role. Each role can operate in BYOK or ACP mode.
41
+ """
42
+
43
+ category: RoleCategory
44
+ name: str
45
+ description: str
46
+ job_description: str = ""
47
+
48
+ # Execution mode
49
+ mode: Literal["byok", "acp"] = "byok"
50
+
51
+ # BYOK settings
52
+ provider: Optional[str] = None
53
+ model: Optional[str] = None
54
+
55
+ # ACP settings
56
+ agent: Optional[str] = None
57
+
58
+ # QE-specific
59
+ qe_type: Optional[QERoleType] = None
60
+
61
+ # Common settings
62
+ enabled: bool = True
63
+ mcp_servers: List[str] = field(default_factory=list)
64
+
65
+ @property
66
+ def display_name(self) -> str:
67
+ """Get display name like 'dev.fullstack'."""
68
+ return f"{self.category.value}.{self.name}"
69
+
70
+ @property
71
+ def command(self) -> str:
72
+ """Get TUI command like ':<mode> <role>'."""
73
+ return f":{self.category.value} {self.name}"
74
+
75
+ @property
76
+ def is_byok(self) -> bool:
77
+ """Check if role uses BYOK mode."""
78
+ return self.mode == "byok"
79
+
80
+ @property
81
+ def is_acp(self) -> bool:
82
+ """Check if role uses ACP mode."""
83
+ return self.mode == "acp"
84
+
85
+ @property
86
+ def is_execution_role(self) -> bool:
87
+ """Check if this is an execution QE role."""
88
+ return self.qe_type == QERoleType.EXECUTION
89
+
90
+ @property
91
+ def is_detection_role(self) -> bool:
92
+ """Check if this is a detection QE role."""
93
+ return self.qe_type == QERoleType.DETECTION
94
+
95
+ def to_dict(self) -> Dict[str, Any]:
96
+ """Convert to dictionary representation."""
97
+ result = {
98
+ "category": self.category.value,
99
+ "name": self.name,
100
+ "display_name": self.display_name,
101
+ "description": self.description,
102
+ "job_description": self.job_description,
103
+ "mode": self.mode,
104
+ "enabled": self.enabled,
105
+ }
106
+
107
+ if self.mode == "byok":
108
+ result["provider"] = self.provider
109
+ result["model"] = self.model
110
+ else:
111
+ result["agent"] = self.agent
112
+
113
+ if self.qe_type:
114
+ result["qe_type"] = self.qe_type.value
115
+
116
+ if self.mcp_servers:
117
+ result["mcp_servers"] = self.mcp_servers
118
+
119
+ return result
120
+
121
+
122
+ # =============================================================================
123
+ # Default Role Definitions
124
+ # =============================================================================
125
+
126
+ DEFAULT_DEV_ROLES = {
127
+ "fullstack": Role(
128
+ category=RoleCategory.DEV,
129
+ name="fullstack",
130
+ description="Full-stack development",
131
+ job_description="Implement features, fix bugs, refactor code across the entire stack",
132
+ mode="acp",
133
+ agent="claude-code",
134
+ ),
135
+ "frontend": Role(
136
+ category=RoleCategory.DEV,
137
+ name="frontend",
138
+ description="Frontend/UI specialist",
139
+ job_description="Build and maintain user interfaces, ensure great UX",
140
+ mode="acp",
141
+ agent="claude-code",
142
+ ),
143
+ "backend": Role(
144
+ category=RoleCategory.DEV,
145
+ name="backend",
146
+ description="Backend/API specialist",
147
+ job_description="Design and implement APIs, services, and data layers",
148
+ mode="acp",
149
+ agent="claude-code",
150
+ ),
151
+ }
152
+
153
+ DEFAULT_QE_ROLES = {
154
+ "smoke": Role(
155
+ category=RoleCategory.QE,
156
+ name="smoke",
157
+ description="Fast critical path validation",
158
+ job_description="Run smoke tests to validate critical paths work",
159
+ mode="byok",
160
+ qe_type=QERoleType.EXECUTION,
161
+ ),
162
+ "sanity": Role(
163
+ category=RoleCategory.QE,
164
+ name="sanity",
165
+ description="Core functionality check",
166
+ job_description="Verify core functionality and recent changes",
167
+ mode="byok",
168
+ qe_type=QERoleType.EXECUTION,
169
+ ),
170
+ "regression": Role(
171
+ category=RoleCategory.QE,
172
+ name="regression",
173
+ description="Full test suite execution",
174
+ job_description="Run full regression suite with flake detection",
175
+ mode="byok",
176
+ qe_type=QERoleType.EXECUTION,
177
+ ),
178
+ "security": Role(
179
+ category=RoleCategory.QE,
180
+ name="security",
181
+ description="Security vulnerability scanning",
182
+ job_description="Proactively detect security vulnerabilities and suggest fixes",
183
+ mode="acp",
184
+ agent="claude-code",
185
+ qe_type=QERoleType.DETECTION,
186
+ ),
187
+ "api": Role(
188
+ category=RoleCategory.QE,
189
+ name="api",
190
+ description="API contract and behavior testing",
191
+ job_description="Validate API contracts, test edge cases, check error handling",
192
+ mode="acp",
193
+ agent="claude-code",
194
+ qe_type=QERoleType.DETECTION,
195
+ ),
196
+ "e2e": Role(
197
+ category=RoleCategory.QE,
198
+ name="e2e",
199
+ description="End-to-end workflow validation",
200
+ job_description="Test complete user workflows and integration points",
201
+ mode="acp",
202
+ agent="claude-code",
203
+ qe_type=QERoleType.DETECTION,
204
+ ),
205
+ "performance": Role(
206
+ category=RoleCategory.QE,
207
+ name="performance",
208
+ description="Performance bottleneck detection",
209
+ job_description="Identify performance issues and optimization opportunities",
210
+ mode="acp",
211
+ agent="claude-code",
212
+ qe_type=QERoleType.DETECTION,
213
+ ),
214
+ }
215
+
216
+ DEFAULT_DEVOPS_ROLES = {
217
+ "deployment": Role(
218
+ category=RoleCategory.DEVOPS,
219
+ name="deployment",
220
+ description="Deployment readiness validation",
221
+ job_description="Validate deployment configurations and readiness",
222
+ mode="acp",
223
+ agent="claude-code",
224
+ ),
225
+ "infrastructure": Role(
226
+ category=RoleCategory.DEVOPS,
227
+ name="infrastructure",
228
+ description="Infrastructure and config validation",
229
+ job_description="Review infrastructure code and configurations",
230
+ mode="acp",
231
+ agent="claude-code",
232
+ ),
233
+ "monitoring": Role(
234
+ category=RoleCategory.DEVOPS,
235
+ name="monitoring",
236
+ description="Observability and alerting setup",
237
+ job_description="Set up and validate monitoring, logging, and alerting",
238
+ mode="acp",
239
+ agent="claude-code",
240
+ ),
241
+ }
242
+
243
+
244
+ def get_default_roles() -> Dict[str, Dict[str, Role]]:
245
+ """Get all default roles organized by category."""
246
+ return {
247
+ "dev": DEFAULT_DEV_ROLES,
248
+ "qe": DEFAULT_QE_ROLES,
249
+ "devops": DEFAULT_DEVOPS_ROLES,
250
+ }
251
+
252
+
253
+ def get_role(category: str, name: str) -> Optional[Role]:
254
+ """Get a specific role by category and name."""
255
+ defaults = get_default_roles()
256
+ category_roles = defaults.get(category, {})
257
+ return category_roles.get(name)
258
+
259
+
260
+ def list_all_roles() -> List[Role]:
261
+ """List all available roles."""
262
+ roles = []
263
+ for category_roles in get_default_roles().values():
264
+ roles.extend(category_roles.values())
265
+ return roles
266
+
267
+
268
+ def list_roles_by_category(category: str) -> List[Role]:
269
+ """List roles in a specific category."""
270
+ defaults = get_default_roles()
271
+ return list(defaults.get(category, {}).values())
272
+
273
+
274
+ def list_qe_execution_roles() -> List[Role]:
275
+ """List QE roles that run existing tests."""
276
+ return [r for r in DEFAULT_QE_ROLES.values() if r.qe_type == QERoleType.EXECUTION]
277
+
278
+
279
+ def list_qe_detection_roles() -> List[Role]:
280
+ """List QE roles that detect issues proactively."""
281
+ return [r for r in DEFAULT_QE_ROLES.values() if r.qe_type == QERoleType.DETECTION]
superqode/danger.py ADDED
@@ -0,0 +1,386 @@
1
+ """
2
+ SuperQode Danger Detection - Command Safety Analysis
3
+
4
+ Analyzes shell commands to detect potentially dangerous operations.
5
+ Uses a unique visual style with gradient warnings.
6
+ """
7
+
8
+ from enum import IntEnum
9
+ from functools import lru_cache
10
+ from pathlib import Path
11
+ from typing import Iterable, NamedTuple, Sequence, Tuple
12
+
13
+ # Commands that are generally safe (read-only operations)
14
+ SAFE_COMMANDS = {
15
+ # Display & Output
16
+ "echo",
17
+ "cat",
18
+ "less",
19
+ "more",
20
+ "head",
21
+ "tail",
22
+ "tac",
23
+ "nl",
24
+ "bat",
25
+ # File & Directory Information
26
+ "ls",
27
+ "tree",
28
+ "pwd",
29
+ "file",
30
+ "stat",
31
+ "du",
32
+ "df",
33
+ "exa",
34
+ "lsd",
35
+ # Search & Find
36
+ "find",
37
+ "locate",
38
+ "which",
39
+ "whereis",
40
+ "type",
41
+ "grep",
42
+ "egrep",
43
+ "fgrep",
44
+ "rg",
45
+ "ag",
46
+ "fd",
47
+ "fzf",
48
+ # Text Processing (read-only)
49
+ "wc",
50
+ "sort",
51
+ "uniq",
52
+ "cut",
53
+ "paste",
54
+ "column",
55
+ "tr",
56
+ "diff",
57
+ "cmp",
58
+ "comm",
59
+ # System Information
60
+ "whoami",
61
+ "who",
62
+ "w",
63
+ "id",
64
+ "hostname",
65
+ "uname",
66
+ "uptime",
67
+ "date",
68
+ "cal",
69
+ "env",
70
+ "printenv",
71
+ # Process Information
72
+ "ps",
73
+ "top",
74
+ "htop",
75
+ "pgrep",
76
+ "jobs",
77
+ "pstree",
78
+ # Network (read-only)
79
+ "ping",
80
+ "traceroute",
81
+ "nslookup",
82
+ "dig",
83
+ "host",
84
+ "netstat",
85
+ "ss",
86
+ "ifconfig",
87
+ "ip",
88
+ # View compressed files
89
+ "zcat",
90
+ "zless",
91
+ # History & Help
92
+ "history",
93
+ "man",
94
+ "help",
95
+ "info",
96
+ "apropos",
97
+ "whatis",
98
+ # Checksums
99
+ "md5sum",
100
+ "sha256sum",
101
+ "sha1sum",
102
+ "cksum",
103
+ "sum",
104
+ "md5",
105
+ "shasum",
106
+ # Other Safe
107
+ "bc",
108
+ "expr",
109
+ "test",
110
+ "sleep",
111
+ "true",
112
+ "false",
113
+ "yes",
114
+ "seq",
115
+ "basename",
116
+ "dirname",
117
+ "realpath",
118
+ "readlink",
119
+ # Dev tools (read-only)
120
+ "git status",
121
+ "git log",
122
+ "git diff",
123
+ "git show",
124
+ "git branch",
125
+ "npm list",
126
+ "pip list",
127
+ "cargo tree",
128
+ }
129
+
130
+ # Commands that can modify the filesystem
131
+ UNSAFE_COMMANDS = {
132
+ # File/Directory Creation
133
+ "mkdir",
134
+ "touch",
135
+ "mktemp",
136
+ "mkfifo",
137
+ "mknod",
138
+ # File/Directory Deletion
139
+ "rm",
140
+ "rmdir",
141
+ "shred",
142
+ # File/Directory Moving/Copying
143
+ "mv",
144
+ "cp",
145
+ "rsync",
146
+ "scp",
147
+ "install",
148
+ # File Modification
149
+ "sed",
150
+ "awk",
151
+ "tee",
152
+ "nano",
153
+ "vim",
154
+ "vi",
155
+ "emacs",
156
+ "code",
157
+ # Permissions/Ownership
158
+ "chmod",
159
+ "chown",
160
+ "chgrp",
161
+ "chattr",
162
+ "setfacl",
163
+ # Linking
164
+ "ln",
165
+ "link",
166
+ "unlink",
167
+ # Archive/Compression
168
+ "tar",
169
+ "zip",
170
+ "unzip",
171
+ "gzip",
172
+ "gunzip",
173
+ "bzip2",
174
+ "bunzip2",
175
+ "xz",
176
+ "unxz",
177
+ "7z",
178
+ "rar",
179
+ "unrar",
180
+ # Download Tools
181
+ "wget",
182
+ "curl",
183
+ "fetch",
184
+ "aria2c",
185
+ # Low-level Disk
186
+ "dd",
187
+ "truncate",
188
+ "fallocate",
189
+ # File Splitting
190
+ "split",
191
+ "csplit",
192
+ # Sync
193
+ "sync",
194
+ # System Administration
195
+ "useradd",
196
+ "userdel",
197
+ "usermod",
198
+ "groupadd",
199
+ "groupdel",
200
+ "passwd",
201
+ "mount",
202
+ "umount",
203
+ "mkfs",
204
+ "fdisk",
205
+ "parted",
206
+ "swapon",
207
+ "swapoff",
208
+ # Package managers (can install/remove)
209
+ "npm install",
210
+ "pip install",
211
+ "cargo install",
212
+ "brew install",
213
+ "apt",
214
+ "yum",
215
+ "dnf",
216
+ "pacman",
217
+ # Other Dangerous
218
+ "patch",
219
+ "git checkout",
220
+ "git reset",
221
+ "git clean",
222
+ }
223
+
224
+
225
+ class DangerLevel(IntEnum):
226
+ """The danger level of a command."""
227
+
228
+ SAFE = 0 # Command is known to be generally safe
229
+ UNKNOWN = 1 # We don't know about this command
230
+ DANGEROUS = 2 # Command can modify filesystem
231
+ DESTRUCTIVE = 3 # Command modifies files outside project
232
+
233
+
234
+ class CommandInfo(NamedTuple):
235
+ """Information about a command's danger level."""
236
+
237
+ command: str
238
+ level: DangerLevel
239
+ target_path: Path | None
240
+ reason: str
241
+
242
+
243
+ # Visual styles for each danger level
244
+ DANGER_STYLES = {
245
+ DangerLevel.SAFE: {
246
+ "icon": "✅",
247
+ "color": "#22c55e",
248
+ "bg": "#22c55e20",
249
+ "label": "Safe",
250
+ "border": "green",
251
+ },
252
+ DangerLevel.UNKNOWN: {
253
+ "icon": "❓",
254
+ "color": "#f59e0b",
255
+ "bg": "#f59e0b20",
256
+ "label": "Unknown",
257
+ "border": "yellow",
258
+ },
259
+ DangerLevel.DANGEROUS: {
260
+ "icon": "⚠️",
261
+ "color": "#f97316",
262
+ "bg": "#f9731620",
263
+ "label": "Dangerous",
264
+ "border": "orange1",
265
+ },
266
+ DangerLevel.DESTRUCTIVE: {
267
+ "icon": "🚨",
268
+ "color": "#ef4444",
269
+ "bg": "#ef444420",
270
+ "label": "DESTRUCTIVE",
271
+ "border": "red",
272
+ },
273
+ }
274
+
275
+
276
+ @lru_cache(maxsize=512)
277
+ def analyze_command(
278
+ project_dir: str,
279
+ working_dir: str,
280
+ command: str,
281
+ ) -> Tuple[DangerLevel, str, Path | None]:
282
+ """
283
+ Analyze a shell command for potential dangers.
284
+
285
+ Args:
286
+ project_dir: The project root directory
287
+ working_dir: Current working directory
288
+ command: The shell command to analyze
289
+
290
+ Returns:
291
+ Tuple of (danger_level, reason, target_path)
292
+ """
293
+ if not command or not command.strip():
294
+ return DangerLevel.SAFE, "Empty command", None
295
+
296
+ command = command.strip()
297
+ parts = command.split()
298
+ if not parts:
299
+ return DangerLevel.SAFE, "Empty command", None
300
+
301
+ base_cmd = parts[0]
302
+ project_path = Path(project_dir).resolve()
303
+ current_path = Path(working_dir).resolve()
304
+
305
+ # Check for safe commands first
306
+ if base_cmd in SAFE_COMMANDS:
307
+ return DangerLevel.SAFE, f"'{base_cmd}' is a read-only command", None
308
+
309
+ # Check for known unsafe commands
310
+ is_unsafe = base_cmd in UNSAFE_COMMANDS
311
+
312
+ # Look for file paths in arguments
313
+ target_path = None
314
+ for arg in parts[1:]:
315
+ if arg.startswith("-"):
316
+ continue
317
+ try:
318
+ # Try to resolve the path
319
+ if arg.startswith("/"):
320
+ target_path = Path(arg).resolve()
321
+ elif arg.startswith("~"):
322
+ target_path = Path(arg).expanduser().resolve()
323
+ else:
324
+ target_path = (current_path / arg).resolve()
325
+ break
326
+ except (OSError, ValueError):
327
+ continue
328
+
329
+ # Determine danger level
330
+ if is_unsafe:
331
+ if target_path:
332
+ try:
333
+ # Check if path is outside project
334
+ target_path.relative_to(project_path)
335
+ return DangerLevel.DANGEROUS, f"'{base_cmd}' can modify files", target_path
336
+ except ValueError:
337
+ return (
338
+ DangerLevel.DESTRUCTIVE,
339
+ f"'{base_cmd}' targets files outside project!",
340
+ target_path,
341
+ )
342
+ return DangerLevel.DANGEROUS, f"'{base_cmd}' can modify the filesystem", None
343
+
344
+ # Unknown command
345
+ return DangerLevel.UNKNOWN, f"Unknown command '{base_cmd}'", target_path
346
+
347
+
348
+ def get_danger_display(level: DangerLevel) -> dict:
349
+ """Get display properties for a danger level."""
350
+ return DANGER_STYLES.get(level, DANGER_STYLES[DangerLevel.UNKNOWN])
351
+
352
+
353
+ def format_danger_message(
354
+ command: str,
355
+ level: DangerLevel,
356
+ reason: str,
357
+ target_path: Path | None = None,
358
+ ) -> str:
359
+ """Format a danger warning message."""
360
+ style = DANGER_STYLES[level]
361
+ icon = style["icon"]
362
+ label = style["label"]
363
+
364
+ msg = f"{icon} [{label}] {reason}"
365
+ if target_path:
366
+ msg += f"\n 📁 Target: {target_path}"
367
+ return msg
368
+
369
+
370
+ # Quick check functions
371
+ def is_safe(command: str, project_dir: str = ".", working_dir: str = ".") -> bool:
372
+ """Check if a command is safe to run."""
373
+ level, _, _ = analyze_command(project_dir, working_dir, command)
374
+ return level == DangerLevel.SAFE
375
+
376
+
377
+ def is_destructive(command: str, project_dir: str = ".", working_dir: str = ".") -> bool:
378
+ """Check if a command is destructive (modifies files outside project)."""
379
+ level, _, _ = analyze_command(project_dir, working_dir, command)
380
+ return level == DangerLevel.DESTRUCTIVE
381
+
382
+
383
+ def requires_approval(command: str, project_dir: str = ".", working_dir: str = ".") -> bool:
384
+ """Check if a command requires user approval."""
385
+ level, _, _ = analyze_command(project_dir, working_dir, command)
386
+ return level >= DangerLevel.DANGEROUS