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
superqode/app/models.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SuperQode App Models - Agent data structures and helpers.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import concurrent.futures
|
|
9
|
+
import shutil
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from enum import Enum
|
|
12
|
+
|
|
13
|
+
from .constants import AGENT_COLORS, AGENT_ICONS, THEME
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AgentStatus(Enum):
|
|
17
|
+
"""Status of an agent installation."""
|
|
18
|
+
|
|
19
|
+
INSTALLED = "installed"
|
|
20
|
+
AVAILABLE = "available"
|
|
21
|
+
RECOMMENDED = "recommended"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class AgentInfo:
|
|
26
|
+
"""Information about a coding agent."""
|
|
27
|
+
|
|
28
|
+
identity: str
|
|
29
|
+
name: str
|
|
30
|
+
short_name: str
|
|
31
|
+
description: str
|
|
32
|
+
author: str
|
|
33
|
+
status: AgentStatus
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def color(self) -> str:
|
|
37
|
+
return AGENT_COLORS.get(self.short_name, THEME["purple"])
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def icon(self) -> str:
|
|
41
|
+
return AGENT_ICONS.get(self.short_name, "🤖")
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def is_ready(self) -> bool:
|
|
45
|
+
return self.status == AgentStatus.INSTALLED
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def status_icon(self) -> str:
|
|
49
|
+
if self.is_ready:
|
|
50
|
+
return "✅"
|
|
51
|
+
elif self.status == AgentStatus.RECOMMENDED:
|
|
52
|
+
return "⭐"
|
|
53
|
+
return "○"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def check_installed(name: str) -> bool:
|
|
57
|
+
"""Check if an agent is installed on the system."""
|
|
58
|
+
# Map agent short names to their CLI commands
|
|
59
|
+
cmd_map = {
|
|
60
|
+
# 14 Official ACP Agents
|
|
61
|
+
"gemini": "gemini",
|
|
62
|
+
"claude": "claude",
|
|
63
|
+
"claude-code": "claude",
|
|
64
|
+
"codex": "codex",
|
|
65
|
+
"junie": "junie",
|
|
66
|
+
"goose": "goose",
|
|
67
|
+
"kimi": "kimi",
|
|
68
|
+
"opencode": "opencode",
|
|
69
|
+
"stakpak": "stakpak",
|
|
70
|
+
"vtcode": "vtcode",
|
|
71
|
+
"auggie": "auggie",
|
|
72
|
+
"code-assistant": "code-assistant",
|
|
73
|
+
"cagent": "cagent",
|
|
74
|
+
"fast-agent": "fast-agent",
|
|
75
|
+
"llmling-agent": "llmling-agent",
|
|
76
|
+
}
|
|
77
|
+
return shutil.which(cmd_map.get(name, name)) is not None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def load_agents_sync() -> list[AgentInfo]:
|
|
81
|
+
"""Load agents list synchronously."""
|
|
82
|
+
agents = []
|
|
83
|
+
try:
|
|
84
|
+
from superqode.agents.discovery import read_agents
|
|
85
|
+
|
|
86
|
+
def _read():
|
|
87
|
+
loop = asyncio.new_event_loop()
|
|
88
|
+
asyncio.set_event_loop(loop)
|
|
89
|
+
try:
|
|
90
|
+
return loop.run_until_complete(read_agents())
|
|
91
|
+
finally:
|
|
92
|
+
loop.close()
|
|
93
|
+
|
|
94
|
+
with concurrent.futures.ThreadPoolExecutor() as ex:
|
|
95
|
+
agent_map = ex.submit(_read).result(timeout=10)
|
|
96
|
+
|
|
97
|
+
for identity, data in agent_map.items():
|
|
98
|
+
short = data.get("short_name", "").lower()
|
|
99
|
+
installed = check_installed(short)
|
|
100
|
+
recommended = data.get("recommended", False)
|
|
101
|
+
|
|
102
|
+
agents.append(
|
|
103
|
+
AgentInfo(
|
|
104
|
+
identity=identity,
|
|
105
|
+
name=data.get("name", "Unknown"),
|
|
106
|
+
short_name=short,
|
|
107
|
+
description=data.get("description", "")[:80],
|
|
108
|
+
author=data.get("author_name", ""),
|
|
109
|
+
status=AgentStatus.INSTALLED
|
|
110
|
+
if installed
|
|
111
|
+
else (AgentStatus.RECOMMENDED if recommended else AgentStatus.AVAILABLE),
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
except Exception:
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
agents.sort(key=lambda a: (0 if a.is_ready else 1, a.name))
|
|
118
|
+
return agents
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SuperQode Command Suggester - Autocompletion for commands.
|
|
3
|
+
|
|
4
|
+
Optimized for zero-latency typing - returns immediately without blocking.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List, Tuple, Optional
|
|
8
|
+
from textual.suggester import Suggester
|
|
9
|
+
|
|
10
|
+
from .constants import COMMANDS
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_role_suggestions(mode: str, partial_role: str) -> List[Tuple[str, bool, str]]:
|
|
14
|
+
"""Get role suggestions for a mode matching partial_role.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
mode: Mode name ('qe', 'dev', 'devops')
|
|
18
|
+
partial_role: Partial role name to match (empty string returns all roles)
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
List of (role_name, enabled, description) tuples, sorted by enabled first, then alphabetically
|
|
22
|
+
"""
|
|
23
|
+
try:
|
|
24
|
+
from superqode.config import load_config
|
|
25
|
+
|
|
26
|
+
config = load_config()
|
|
27
|
+
mode_config = config.team.modes.get(mode)
|
|
28
|
+
if not mode_config or not mode_config.roles:
|
|
29
|
+
return []
|
|
30
|
+
|
|
31
|
+
partial_lower = partial_role.lower()
|
|
32
|
+
suggestions = []
|
|
33
|
+
|
|
34
|
+
for role_name, role_config in mode_config.roles.items():
|
|
35
|
+
# Use prefix match for more predictable autocomplete behavior
|
|
36
|
+
# Empty partial_role matches all roles
|
|
37
|
+
if not partial_lower or role_name.lower().startswith(partial_lower):
|
|
38
|
+
enabled = role_config.enabled
|
|
39
|
+
desc = role_config.description or ""
|
|
40
|
+
suggestions.append((role_name, enabled, desc))
|
|
41
|
+
|
|
42
|
+
# Sort: enabled first, then alphabetically
|
|
43
|
+
suggestions.sort(key=lambda x: (not x[1], x[0]))
|
|
44
|
+
return suggestions
|
|
45
|
+
except Exception:
|
|
46
|
+
return []
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class CommandSuggester(Suggester):
|
|
50
|
+
"""Autocomplete for : commands.
|
|
51
|
+
|
|
52
|
+
Performance optimizations:
|
|
53
|
+
- Pre-computed command lists
|
|
54
|
+
- Fast early-exit checks
|
|
55
|
+
- Non-blocking async implementation
|
|
56
|
+
- Minimal processing per keystroke
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(self):
|
|
60
|
+
super().__init__()
|
|
61
|
+
# Pre-compute lowercase commands for faster matching
|
|
62
|
+
self._commands_lower = tuple(cmd.lower() for cmd in COMMANDS)
|
|
63
|
+
self._commands = tuple(COMMANDS)
|
|
64
|
+
# Pre-filter commands starting with ':' for even faster lookup
|
|
65
|
+
self._colon_commands = tuple(cmd for cmd in COMMANDS if cmd.startswith(":"))
|
|
66
|
+
self._colon_commands_lower = tuple(cmd.lower() for cmd in self._colon_commands)
|
|
67
|
+
|
|
68
|
+
async def get_suggestion(self, value: str) -> str | None:
|
|
69
|
+
"""Get suggestion for command autocomplete.
|
|
70
|
+
|
|
71
|
+
Returns immediately to avoid any blocking or delay.
|
|
72
|
+
Designed for zero-latency typing experience.
|
|
73
|
+
|
|
74
|
+
Supports:
|
|
75
|
+
- Basic commands: :help, :clear, etc.
|
|
76
|
+
- Mode commands with roles: :qe <role>, :dev <role>, :devops <role>
|
|
77
|
+
"""
|
|
78
|
+
# Ultra-fast path: not a command (most common case)
|
|
79
|
+
if not value:
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
# Fast path: doesn't start with ':'
|
|
83
|
+
if not value.startswith(":"):
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
# Fast path: too short (just ':')
|
|
87
|
+
if len(value) < 2:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
value_lower = value.lower()
|
|
91
|
+
|
|
92
|
+
# Check for mode commands with role patterns: :qe <role>, :dev <role>, :devops <role>
|
|
93
|
+
mode_patterns = [("qe", ":qe"), ("dev", ":dev"), ("devops", ":devops")]
|
|
94
|
+
for mode_name, mode_prefix in mode_patterns:
|
|
95
|
+
if value_lower == mode_prefix or value_lower.startswith(mode_prefix + " "):
|
|
96
|
+
# Determine the prefix with space
|
|
97
|
+
prefix_with_space = mode_prefix + " "
|
|
98
|
+
# Extract partial role name (everything after the mode prefix and space)
|
|
99
|
+
if len(value) > len(prefix_with_space):
|
|
100
|
+
partial_role = value[len(prefix_with_space) :]
|
|
101
|
+
else:
|
|
102
|
+
# User typed just ":qe" or ":qe " - return first enabled role
|
|
103
|
+
partial_role = ""
|
|
104
|
+
|
|
105
|
+
# Get role suggestions
|
|
106
|
+
try:
|
|
107
|
+
suggestions = get_role_suggestions(mode_name, partial_role)
|
|
108
|
+
if suggestions:
|
|
109
|
+
role_name, enabled, _ = suggestions[0]
|
|
110
|
+
status = "" if enabled else " [DISABLED]"
|
|
111
|
+
# Keep the space in prefix - don't strip it!
|
|
112
|
+
return f"{prefix_with_space}{role_name}{status}"
|
|
113
|
+
except Exception:
|
|
114
|
+
# If role suggestions fail, fall through to normal command matching
|
|
115
|
+
pass
|
|
116
|
+
# No suggestions found - let normal command matching continue
|
|
117
|
+
break
|
|
118
|
+
|
|
119
|
+
# Fast matching - use pre-filtered colon commands
|
|
120
|
+
# Find first command that starts with the value
|
|
121
|
+
for i, cmd_lower in enumerate(self._colon_commands_lower):
|
|
122
|
+
if cmd_lower.startswith(value_lower) and cmd_lower != value_lower:
|
|
123
|
+
return self._colon_commands[i]
|
|
124
|
+
|
|
125
|
+
return None
|