stravinsky 0.2.67__py3-none-any.whl → 0.4.18__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.
Potentially problematic release.
This version of stravinsky might be problematic. Click here for more details.
- mcp_bridge/__init__.py +1 -1
- mcp_bridge/auth/token_store.py +113 -11
- mcp_bridge/config/MANIFEST_SCHEMA.md +305 -0
- mcp_bridge/config/README.md +276 -0
- mcp_bridge/config/hook_config.py +249 -0
- mcp_bridge/config/hooks_manifest.json +138 -0
- mcp_bridge/config/rate_limits.py +222 -0
- mcp_bridge/config/skills_manifest.json +128 -0
- mcp_bridge/hooks/__init__.py +8 -3
- mcp_bridge/hooks/manager.py +8 -0
- mcp_bridge/hooks/tool_messaging.py +113 -10
- mcp_bridge/notifications.py +151 -0
- mcp_bridge/server.py +202 -48
- mcp_bridge/server_tools.py +440 -0
- mcp_bridge/tools/__init__.py +22 -18
- mcp_bridge/tools/agent_manager.py +197 -28
- mcp_bridge/tools/code_search.py +16 -2
- mcp_bridge/tools/lsp/__init__.py +7 -0
- mcp_bridge/tools/lsp/manager.py +448 -0
- mcp_bridge/tools/lsp/tools.py +634 -151
- mcp_bridge/tools/model_invoke.py +186 -159
- mcp_bridge/tools/query_classifier.py +323 -0
- mcp_bridge/tools/semantic_search.py +3042 -0
- mcp_bridge/update_manager.py +589 -0
- mcp_bridge/update_manager_pypi.py +299 -0
- {stravinsky-0.2.67.dist-info → stravinsky-0.4.18.dist-info}/METADATA +209 -25
- {stravinsky-0.2.67.dist-info → stravinsky-0.4.18.dist-info}/RECORD +29 -17
- {stravinsky-0.2.67.dist-info → stravinsky-0.4.18.dist-info}/WHEEL +0 -0
- {stravinsky-0.2.67.dist-info → stravinsky-0.4.18.dist-info}/entry_points.txt +0 -0
|
@@ -36,6 +36,8 @@ AGENT_MODEL_ROUTING = {
|
|
|
36
36
|
"multimodal": None,
|
|
37
37
|
"frontend": None,
|
|
38
38
|
"delphi": None,
|
|
39
|
+
"research-lead": None, # Hierarchical orchestrator using gemini-3-flash
|
|
40
|
+
"implementation-lead": None, # Hierarchical orchestrator using haiku
|
|
39
41
|
# Planner uses Opus for superior reasoning about dependencies and parallelization
|
|
40
42
|
"planner": "opus",
|
|
41
43
|
# Default for unknown agent types (coding tasks) - use Sonnet 4.5
|
|
@@ -48,6 +50,8 @@ AGENT_COST_TIERS = {
|
|
|
48
50
|
"dewey": "CHEAP", # Uses gemini-3-flash
|
|
49
51
|
"document_writer": "CHEAP", # Uses gemini-3-flash
|
|
50
52
|
"multimodal": "CHEAP", # Uses gemini-3-flash
|
|
53
|
+
"research-lead": "CHEAP", # Uses gemini-3-flash
|
|
54
|
+
"implementation-lead": "CHEAP", # Uses haiku
|
|
51
55
|
"frontend": "MEDIUM", # Uses gemini-3-pro-high
|
|
52
56
|
"delphi": "EXPENSIVE", # Uses gpt-5.2 (OpenAI GPT)
|
|
53
57
|
"planner": "EXPENSIVE", # Uses Claude Opus 4.5
|
|
@@ -60,12 +64,102 @@ AGENT_DISPLAY_MODELS = {
|
|
|
60
64
|
"dewey": "gemini-3-flash",
|
|
61
65
|
"document_writer": "gemini-3-flash",
|
|
62
66
|
"multimodal": "gemini-3-flash",
|
|
67
|
+
"research-lead": "gemini-3-flash",
|
|
68
|
+
"implementation-lead": "haiku",
|
|
63
69
|
"frontend": "gemini-3-pro-high",
|
|
64
70
|
"delphi": "gpt-5.2",
|
|
65
71
|
"planner": "opus-4.5",
|
|
66
72
|
"_default": "sonnet-4.5",
|
|
67
73
|
}
|
|
68
74
|
|
|
75
|
+
# Cost tier emoji indicators for visual differentiation
|
|
76
|
+
# Colors indicate cost: 🟢 cheap/free, 🔵 medium, 🟣 expensive (GPT), 🟠 Claude
|
|
77
|
+
COST_TIER_EMOJI = {
|
|
78
|
+
"CHEAP": "🟢", # Free/cheap models (gemini-3-flash, haiku)
|
|
79
|
+
"MEDIUM": "🔵", # Medium cost (gemini-3-pro-high)
|
|
80
|
+
"EXPENSIVE": "🟣", # Expensive models (gpt-5.2, opus)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# Model family indicators
|
|
84
|
+
MODEL_FAMILY_EMOJI = {
|
|
85
|
+
"gemini-3-flash": "🟢",
|
|
86
|
+
"gemini-3-pro-high": "🔵",
|
|
87
|
+
"haiku": "🟢",
|
|
88
|
+
"sonnet-4.5": "🟠",
|
|
89
|
+
"opus-4.5": "🟣",
|
|
90
|
+
"gpt-5.2": "🟣",
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# ANSI color codes for terminal output
|
|
94
|
+
class Colors:
|
|
95
|
+
"""ANSI color codes for colorized terminal output."""
|
|
96
|
+
RESET = "\033[0m"
|
|
97
|
+
BOLD = "\033[1m"
|
|
98
|
+
DIM = "\033[2m"
|
|
99
|
+
|
|
100
|
+
# Foreground colors
|
|
101
|
+
BLACK = "\033[30m"
|
|
102
|
+
RED = "\033[31m"
|
|
103
|
+
GREEN = "\033[32m"
|
|
104
|
+
YELLOW = "\033[33m"
|
|
105
|
+
BLUE = "\033[34m"
|
|
106
|
+
MAGENTA = "\033[35m"
|
|
107
|
+
CYAN = "\033[36m"
|
|
108
|
+
WHITE = "\033[37m"
|
|
109
|
+
|
|
110
|
+
# Bright foreground colors
|
|
111
|
+
BRIGHT_BLACK = "\033[90m"
|
|
112
|
+
BRIGHT_RED = "\033[91m"
|
|
113
|
+
BRIGHT_GREEN = "\033[92m"
|
|
114
|
+
BRIGHT_YELLOW = "\033[93m"
|
|
115
|
+
BRIGHT_BLUE = "\033[94m"
|
|
116
|
+
BRIGHT_MAGENTA = "\033[95m"
|
|
117
|
+
BRIGHT_CYAN = "\033[96m"
|
|
118
|
+
BRIGHT_WHITE = "\033[97m"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_agent_emoji(agent_type: str) -> str:
|
|
122
|
+
"""Get the colored emoji indicator for an agent based on its cost tier."""
|
|
123
|
+
cost_tier = AGENT_COST_TIERS.get(agent_type, AGENT_COST_TIERS["_default"])
|
|
124
|
+
return COST_TIER_EMOJI.get(cost_tier, "⚪")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def get_model_emoji(model_name: str) -> str:
|
|
128
|
+
"""Get the colored emoji indicator for a model."""
|
|
129
|
+
return MODEL_FAMILY_EMOJI.get(model_name, "⚪")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def colorize_agent_spawn_message(
|
|
133
|
+
cost_emoji: str,
|
|
134
|
+
agent_type: str,
|
|
135
|
+
display_model: str,
|
|
136
|
+
description: str,
|
|
137
|
+
task_id: str,
|
|
138
|
+
) -> str:
|
|
139
|
+
"""
|
|
140
|
+
Create a colorized agent spawn message with ANSI color codes.
|
|
141
|
+
|
|
142
|
+
Format:
|
|
143
|
+
🟢 explore:gemini-3-flash('Find auth...') ⏳
|
|
144
|
+
task_id=agent_abc123
|
|
145
|
+
|
|
146
|
+
With colors:
|
|
147
|
+
🟢 {CYAN}explore{RESET}:{YELLOW}gemini-3-flash{RESET}('{BOLD}Find auth...{RESET}') ⏳
|
|
148
|
+
task_id={BRIGHT_BLACK}agent_abc123{RESET}
|
|
149
|
+
"""
|
|
150
|
+
short_desc = (description or "")[:50].strip()
|
|
151
|
+
|
|
152
|
+
# Build colorized message
|
|
153
|
+
colored_message = (
|
|
154
|
+
f"{cost_emoji} "
|
|
155
|
+
f"{Colors.CYAN}{agent_type}{Colors.RESET}:"
|
|
156
|
+
f"{Colors.YELLOW}{display_model}{Colors.RESET}"
|
|
157
|
+
f"('{Colors.BOLD}{short_desc}{Colors.RESET}') "
|
|
158
|
+
f"{Colors.BRIGHT_GREEN}⏳{Colors.RESET}\n"
|
|
159
|
+
f"task_id={Colors.BRIGHT_BLACK}{task_id}{Colors.RESET}"
|
|
160
|
+
)
|
|
161
|
+
return colored_message
|
|
162
|
+
|
|
69
163
|
|
|
70
164
|
@dataclass
|
|
71
165
|
class AgentTask:
|
|
@@ -484,45 +578,45 @@ class AgentManager:
|
|
|
484
578
|
description = task.get("description", "")
|
|
485
579
|
agent_type = task.get("agent_type", "unknown")
|
|
486
580
|
|
|
581
|
+
# Get cost-tier emoji for visual differentiation
|
|
582
|
+
cost_emoji = get_agent_emoji(agent_type)
|
|
583
|
+
display_model = AGENT_DISPLAY_MODELS.get(agent_type, AGENT_DISPLAY_MODELS["_default"])
|
|
584
|
+
|
|
487
585
|
if status == "completed":
|
|
488
586
|
result = task.get("result", "(no output)")
|
|
489
|
-
return f"""✅ Agent Task Completed
|
|
587
|
+
return f"""{cost_emoji} {Colors.BRIGHT_GREEN}✅ Agent Task Completed{Colors.RESET}
|
|
490
588
|
|
|
491
|
-
**Task ID**: {task_id}
|
|
492
|
-
**Agent**: {agent_type}
|
|
493
|
-
**Description**: {description}
|
|
589
|
+
**Task ID**: {Colors.BRIGHT_BLACK}{task_id}{Colors.RESET}
|
|
590
|
+
**Agent**: {Colors.CYAN}{agent_type}{Colors.RESET}:{Colors.YELLOW}{display_model}{Colors.RESET}('{Colors.BOLD}{description}{Colors.RESET}')
|
|
494
591
|
|
|
495
592
|
**Result**:
|
|
496
593
|
{result}"""
|
|
497
594
|
|
|
498
595
|
elif status == "failed":
|
|
499
596
|
error = task.get("error", "(no error details)")
|
|
500
|
-
return f"""❌ Agent Task Failed
|
|
597
|
+
return f"""{cost_emoji} {Colors.BRIGHT_RED}❌ Agent Task Failed{Colors.RESET}
|
|
501
598
|
|
|
502
|
-
**Task ID**: {task_id}
|
|
503
|
-
**Agent**: {agent_type}
|
|
504
|
-
**Description**: {description}
|
|
599
|
+
**Task ID**: {Colors.BRIGHT_BLACK}{task_id}{Colors.RESET}
|
|
600
|
+
**Agent**: {Colors.CYAN}{agent_type}{Colors.RESET}:{Colors.YELLOW}{display_model}{Colors.RESET}('{Colors.BOLD}{description}{Colors.RESET}')
|
|
505
601
|
|
|
506
602
|
**Error**:
|
|
507
603
|
{error}"""
|
|
508
604
|
|
|
509
605
|
elif status == "cancelled":
|
|
510
|
-
return f"""⚠️ Agent Task Cancelled
|
|
606
|
+
return f"""{cost_emoji} {Colors.BRIGHT_YELLOW}⚠️ Agent Task Cancelled{Colors.RESET}
|
|
511
607
|
|
|
512
|
-
**Task ID**: {task_id}
|
|
513
|
-
**Agent**: {agent_type}
|
|
514
|
-
**Description**: {description}"""
|
|
608
|
+
**Task ID**: {Colors.BRIGHT_BLACK}{task_id}{Colors.RESET}
|
|
609
|
+
**Agent**: {Colors.CYAN}{agent_type}{Colors.RESET}:{Colors.YELLOW}{display_model}{Colors.RESET}('{Colors.BOLD}{description}{Colors.RESET}')"""
|
|
515
610
|
|
|
516
611
|
else: # pending or running
|
|
517
612
|
pid = task.get("pid", "N/A")
|
|
518
613
|
started = task.get("started_at", "N/A")
|
|
519
|
-
return f"""⏳ Agent Task Running
|
|
614
|
+
return f"""{cost_emoji} {Colors.BRIGHT_YELLOW}⏳ Agent Task Running{Colors.RESET}
|
|
520
615
|
|
|
521
|
-
**Task ID**: {task_id}
|
|
522
|
-
**Agent**: {agent_type}
|
|
523
|
-
**
|
|
524
|
-
**
|
|
525
|
-
**Started**: {started}
|
|
616
|
+
**Task ID**: {Colors.BRIGHT_BLACK}{task_id}{Colors.RESET}
|
|
617
|
+
**Agent**: {Colors.CYAN}{agent_type}{Colors.RESET}:{Colors.YELLOW}{display_model}{Colors.RESET}('{Colors.BOLD}{description}{Colors.RESET}')
|
|
618
|
+
**PID**: {Colors.DIM}{pid}{Colors.RESET}
|
|
619
|
+
**Started**: {Colors.DIM}{started}{Colors.RESET}
|
|
526
620
|
|
|
527
621
|
Use `agent_output` with block=true to wait for completion."""
|
|
528
622
|
|
|
@@ -595,11 +689,14 @@ Use `agent_output` with block=true to wait for completion."""
|
|
|
595
689
|
"cancelled": "⚠️",
|
|
596
690
|
}.get(status, "❓")
|
|
597
691
|
|
|
598
|
-
|
|
692
|
+
# Get cost-tier emoji for visual differentiation
|
|
693
|
+
cost_emoji = get_agent_emoji(agent_type)
|
|
694
|
+
display_model = AGENT_DISPLAY_MODELS.get(agent_type, AGENT_DISPLAY_MODELS["_default"])
|
|
695
|
+
|
|
696
|
+
result = f"""{cost_emoji} {status_emoji} **Agent Progress**
|
|
599
697
|
|
|
600
698
|
**Task ID**: {task_id}
|
|
601
|
-
**Agent**: {agent_type}
|
|
602
|
-
**Description**: {description}
|
|
699
|
+
**Agent**: {agent_type}:{display_model}('{description}')
|
|
603
700
|
**Status**: {status}
|
|
604
701
|
"""
|
|
605
702
|
|
|
@@ -776,6 +873,61 @@ CONSTRAINTS:
|
|
|
776
873
|
- Every task must have a clear agent assignment
|
|
777
874
|
- Parallel phases must be truly independent
|
|
778
875
|
- Include ready-to-use agent_spawn commands""",
|
|
876
|
+
"research-lead": """You coordinate research tasks by spawning explore and dewey agents in parallel.
|
|
877
|
+
|
|
878
|
+
## Your Role
|
|
879
|
+
1. Receive research objective from Stravinsky
|
|
880
|
+
2. Decompose into parallel search tasks
|
|
881
|
+
3. Spawn explore/dewey agents for each task
|
|
882
|
+
4. Collect and SYNTHESIZE results
|
|
883
|
+
5. Return structured findings (not raw outputs)
|
|
884
|
+
|
|
885
|
+
## Output Format
|
|
886
|
+
Always return a Research Brief:
|
|
887
|
+
```json
|
|
888
|
+
{
|
|
889
|
+
"objective": "Original research goal",
|
|
890
|
+
"findings": [
|
|
891
|
+
{"source": "agent_id", "summary": "Key finding", "confidence": "high/medium/low"},
|
|
892
|
+
...
|
|
893
|
+
],
|
|
894
|
+
"synthesis": "Combined analysis of all findings",
|
|
895
|
+
"gaps": ["Information we couldn't find"],
|
|
896
|
+
"recommendations": ["Suggested next steps"]
|
|
897
|
+
}
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
MODEL ROUTING:
|
|
901
|
+
Use invoke_gemini with model="gemini-3-flash" for ALL synthesis work.
|
|
902
|
+
""",
|
|
903
|
+
"implementation-lead": """You coordinate implementation based on research findings.
|
|
904
|
+
|
|
905
|
+
## Your Role
|
|
906
|
+
1. Receive Research Brief from Stravinsky
|
|
907
|
+
2. Create implementation plan
|
|
908
|
+
3. Delegate to specialists:
|
|
909
|
+
- frontend: UI/visual work
|
|
910
|
+
- debugger: Fix failures
|
|
911
|
+
- code-reviewer: Quality checks
|
|
912
|
+
4. Verify with lsp_diagnostics
|
|
913
|
+
5. Return Implementation Report
|
|
914
|
+
|
|
915
|
+
## Output Format
|
|
916
|
+
```json
|
|
917
|
+
{
|
|
918
|
+
"objective": "What was implemented",
|
|
919
|
+
"files_changed": ["path/to/file.py"],
|
|
920
|
+
"tests_status": "pass/fail/skipped",
|
|
921
|
+
"diagnostics": "clean/warnings/errors",
|
|
922
|
+
"blockers": ["Issues preventing completion"]
|
|
923
|
+
}
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
## Escalation Rules
|
|
927
|
+
- After 2 failed attempts → spawn debugger
|
|
928
|
+
- After debugger fails → escalate to Stravinsky with context
|
|
929
|
+
- NEVER call delphi directly
|
|
930
|
+
""",
|
|
779
931
|
}
|
|
780
932
|
|
|
781
933
|
system_prompt = system_prompts.get(agent_type, None)
|
|
@@ -802,18 +954,25 @@ CONSTRAINTS:
|
|
|
802
954
|
timeout=timeout,
|
|
803
955
|
)
|
|
804
956
|
|
|
805
|
-
# Get display model for concise output
|
|
957
|
+
# Get display model and cost tier emoji for concise output
|
|
806
958
|
display_model = AGENT_DISPLAY_MODELS.get(agent_type, AGENT_DISPLAY_MODELS["_default"])
|
|
959
|
+
cost_emoji = get_agent_emoji(agent_type)
|
|
807
960
|
short_desc = (description or prompt[:50]).strip()
|
|
808
961
|
|
|
809
962
|
# If blocking mode (recommended for delphi), wait for completion
|
|
810
963
|
if blocking:
|
|
811
964
|
result = manager.get_output(task_id, block=True, timeout=timeout)
|
|
812
|
-
|
|
965
|
+
blocking_msg = colorize_agent_spawn_message(
|
|
966
|
+
cost_emoji, agent_type, display_model, short_desc, task_id
|
|
967
|
+
)
|
|
968
|
+
return f"{blocking_msg} {Colors.BOLD}[BLOCKING]{Colors.RESET}\n\n{result}"
|
|
813
969
|
|
|
814
|
-
#
|
|
815
|
-
|
|
816
|
-
|
|
970
|
+
# Enhanced format with ANSI colors: cost_emoji agent:model('description') status_emoji
|
|
971
|
+
# 🟢 explore:gemini-3-flash('Find auth...') ⏳
|
|
972
|
+
# With colors: agent type in cyan, model in yellow, description bold
|
|
973
|
+
return colorize_agent_spawn_message(
|
|
974
|
+
cost_emoji, agent_type, display_model, short_desc, task_id
|
|
975
|
+
)
|
|
817
976
|
|
|
818
977
|
|
|
819
978
|
async def agent_output(task_id: str, block: bool = False) -> str:
|
|
@@ -916,9 +1075,19 @@ async def agent_list() -> str:
|
|
|
916
1075
|
|
|
917
1076
|
agent_type = t.get("agent_type", "unknown")
|
|
918
1077
|
display_model = AGENT_DISPLAY_MODELS.get(agent_type, AGENT_DISPLAY_MODELS["_default"])
|
|
1078
|
+
cost_emoji = get_agent_emoji(agent_type)
|
|
919
1079
|
desc = t.get("description", t.get("prompt", "")[:40])
|
|
920
|
-
|
|
921
|
-
|
|
1080
|
+
task_id = t["id"]
|
|
1081
|
+
|
|
1082
|
+
# Concise format with colors: cost_emoji status agent:model('desc') id=xxx
|
|
1083
|
+
# Agent type in cyan, model in yellow, task_id in dim
|
|
1084
|
+
lines.append(
|
|
1085
|
+
f"{cost_emoji} {status_emoji} "
|
|
1086
|
+
f"{Colors.CYAN}{agent_type}{Colors.RESET}:"
|
|
1087
|
+
f"{Colors.YELLOW}{display_model}{Colors.RESET}"
|
|
1088
|
+
f"('{Colors.BOLD}{desc}{Colors.RESET}') "
|
|
1089
|
+
f"id={Colors.BRIGHT_BLACK}{task_id}{Colors.RESET}"
|
|
1090
|
+
)
|
|
922
1091
|
|
|
923
1092
|
return "\n".join(lines)
|
|
924
1093
|
|
mcp_bridge/tools/code_search.py
CHANGED
|
@@ -90,6 +90,10 @@ async def check_ai_comment_patterns(file_path: str) -> str:
|
|
|
90
90
|
Returns:
|
|
91
91
|
List of detected AI-style patterns with line numbers, or "No AI patterns detected"
|
|
92
92
|
"""
|
|
93
|
+
# USER-VISIBLE NOTIFICATION
|
|
94
|
+
import sys
|
|
95
|
+
print(f"🤖 AI-CHECK: {file_path}", file=sys.stderr)
|
|
96
|
+
|
|
93
97
|
path = Path(file_path)
|
|
94
98
|
if not path.exists():
|
|
95
99
|
return f"Error: File not found: {file_path}"
|
|
@@ -245,14 +249,18 @@ async def grep_search(pattern: str, directory: str = ".", file_pattern: str = ""
|
|
|
245
249
|
async def glob_files(pattern: str, directory: str = ".") -> str:
|
|
246
250
|
"""
|
|
247
251
|
Find files matching a glob pattern.
|
|
248
|
-
|
|
252
|
+
|
|
249
253
|
Args:
|
|
250
254
|
pattern: Glob pattern (e.g., "**/*.py", "src/**/*.ts")
|
|
251
255
|
directory: Base directory for search
|
|
252
|
-
|
|
256
|
+
|
|
253
257
|
Returns:
|
|
254
258
|
List of matching file paths.
|
|
255
259
|
"""
|
|
260
|
+
# USER-VISIBLE NOTIFICATION
|
|
261
|
+
import sys
|
|
262
|
+
print(f"📁 GLOB: pattern='{pattern}' dir={directory}", file=sys.stderr)
|
|
263
|
+
|
|
256
264
|
try:
|
|
257
265
|
cmd = ["fd", "--type", "f", "--glob", pattern, directory]
|
|
258
266
|
|
|
@@ -306,6 +314,12 @@ async def ast_grep_replace(
|
|
|
306
314
|
Returns:
|
|
307
315
|
Preview of changes or confirmation of applied changes.
|
|
308
316
|
"""
|
|
317
|
+
# USER-VISIBLE NOTIFICATION
|
|
318
|
+
import sys
|
|
319
|
+
mode = "dry-run" if dry_run else "APPLY"
|
|
320
|
+
lang_info = f" lang={language}" if language else ""
|
|
321
|
+
print(f"🔄 AST-REPLACE: '{pattern[:30]}' → '{replacement[:30]}'{lang_info} [{mode}]", file=sys.stderr)
|
|
322
|
+
|
|
309
323
|
try:
|
|
310
324
|
# Build command
|
|
311
325
|
cmd = ["sg", "run", "-p", pattern, "-r", replacement, directory]
|
mcp_bridge/tools/lsp/__init__.py
CHANGED
|
@@ -13,8 +13,11 @@ from .tools import (
|
|
|
13
13
|
lsp_prepare_rename,
|
|
14
14
|
lsp_rename,
|
|
15
15
|
lsp_code_actions,
|
|
16
|
+
lsp_code_action_resolve,
|
|
17
|
+
lsp_extract_refactor,
|
|
16
18
|
lsp_servers,
|
|
17
19
|
)
|
|
20
|
+
from .manager import LSPManager, get_lsp_manager
|
|
18
21
|
|
|
19
22
|
__all__ = [
|
|
20
23
|
"lsp_hover",
|
|
@@ -25,5 +28,9 @@ __all__ = [
|
|
|
25
28
|
"lsp_prepare_rename",
|
|
26
29
|
"lsp_rename",
|
|
27
30
|
"lsp_code_actions",
|
|
31
|
+
"lsp_code_action_resolve",
|
|
32
|
+
"lsp_extract_refactor",
|
|
28
33
|
"lsp_servers",
|
|
34
|
+
"LSPManager",
|
|
35
|
+
"get_lsp_manager",
|
|
29
36
|
]
|