stravinsky 0.4.18__py3-none-any.whl → 0.4.66__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/__init__.py +16 -6
- mcp_bridge/auth/cli.py +202 -11
- mcp_bridge/auth/oauth.py +1 -2
- mcp_bridge/auth/openai_oauth.py +4 -7
- mcp_bridge/auth/token_store.py +0 -1
- mcp_bridge/cli/__init__.py +1 -1
- mcp_bridge/cli/install_hooks.py +503 -107
- mcp_bridge/cli/session_report.py +0 -3
- mcp_bridge/config/__init__.py +2 -2
- mcp_bridge/config/hook_config.py +3 -5
- mcp_bridge/config/rate_limits.py +108 -13
- mcp_bridge/hooks/HOOKS_SETTINGS.json +17 -4
- mcp_bridge/hooks/__init__.py +14 -4
- mcp_bridge/hooks/agent_reminder.py +4 -4
- mcp_bridge/hooks/auto_slash_command.py +5 -5
- mcp_bridge/hooks/budget_optimizer.py +2 -2
- mcp_bridge/hooks/claude_limits_hook.py +114 -0
- mcp_bridge/hooks/comment_checker.py +3 -4
- mcp_bridge/hooks/compaction.py +2 -2
- mcp_bridge/hooks/context.py +2 -1
- mcp_bridge/hooks/context_monitor.py +2 -2
- mcp_bridge/hooks/delegation_policy.py +85 -0
- mcp_bridge/hooks/directory_context.py +3 -3
- mcp_bridge/hooks/edit_recovery.py +3 -2
- mcp_bridge/hooks/edit_recovery_policy.py +49 -0
- mcp_bridge/hooks/empty_message_sanitizer.py +2 -2
- mcp_bridge/hooks/events.py +160 -0
- mcp_bridge/hooks/git_noninteractive.py +4 -4
- mcp_bridge/hooks/keyword_detector.py +8 -10
- mcp_bridge/hooks/manager.py +35 -22
- mcp_bridge/hooks/notification_hook.py +13 -6
- mcp_bridge/hooks/parallel_enforcement_policy.py +67 -0
- mcp_bridge/hooks/parallel_enforcer.py +5 -5
- mcp_bridge/hooks/parallel_execution.py +22 -10
- mcp_bridge/hooks/post_tool/parallel_validation.py +103 -0
- mcp_bridge/hooks/pre_compact.py +8 -9
- mcp_bridge/hooks/pre_tool/agent_spawn_validator.py +115 -0
- mcp_bridge/hooks/preemptive_compaction.py +2 -3
- mcp_bridge/hooks/routing_notifications.py +80 -0
- mcp_bridge/hooks/rules_injector.py +11 -19
- mcp_bridge/hooks/session_idle.py +4 -4
- mcp_bridge/hooks/session_notifier.py +4 -4
- mcp_bridge/hooks/session_recovery.py +4 -5
- mcp_bridge/hooks/stravinsky_mode.py +1 -1
- mcp_bridge/hooks/subagent_stop.py +1 -3
- mcp_bridge/hooks/task_validator.py +2 -2
- mcp_bridge/hooks/tmux_manager.py +7 -8
- mcp_bridge/hooks/todo_delegation.py +4 -1
- mcp_bridge/hooks/todo_enforcer.py +180 -10
- mcp_bridge/hooks/truncation_policy.py +37 -0
- mcp_bridge/hooks/truncator.py +1 -2
- mcp_bridge/metrics/cost_tracker.py +115 -0
- mcp_bridge/native_search.py +93 -0
- mcp_bridge/native_watcher.py +118 -0
- mcp_bridge/notifications.py +3 -4
- mcp_bridge/orchestrator/enums.py +11 -0
- mcp_bridge/orchestrator/router.py +165 -0
- mcp_bridge/orchestrator/state.py +32 -0
- mcp_bridge/orchestrator/visualization.py +14 -0
- mcp_bridge/orchestrator/wisdom.py +34 -0
- mcp_bridge/prompts/__init__.py +1 -8
- mcp_bridge/prompts/dewey.py +1 -1
- mcp_bridge/prompts/planner.py +2 -4
- mcp_bridge/prompts/stravinsky.py +53 -31
- mcp_bridge/proxy/__init__.py +0 -0
- mcp_bridge/proxy/client.py +70 -0
- mcp_bridge/proxy/model_server.py +157 -0
- mcp_bridge/routing/__init__.py +43 -0
- mcp_bridge/routing/config.py +250 -0
- mcp_bridge/routing/model_tiers.py +135 -0
- mcp_bridge/routing/provider_state.py +261 -0
- mcp_bridge/routing/task_classifier.py +190 -0
- mcp_bridge/server.py +363 -34
- mcp_bridge/server_tools.py +298 -6
- mcp_bridge/tools/__init__.py +19 -8
- mcp_bridge/tools/agent_manager.py +549 -799
- mcp_bridge/tools/background_tasks.py +13 -17
- mcp_bridge/tools/code_search.py +54 -51
- mcp_bridge/tools/continuous_loop.py +0 -1
- mcp_bridge/tools/dashboard.py +19 -0
- mcp_bridge/tools/find_code.py +296 -0
- mcp_bridge/tools/init.py +1 -0
- mcp_bridge/tools/list_directory.py +42 -0
- mcp_bridge/tools/lsp/__init__.py +8 -8
- mcp_bridge/tools/lsp/manager.py +51 -28
- mcp_bridge/tools/lsp/tools.py +98 -65
- mcp_bridge/tools/model_invoke.py +1047 -152
- mcp_bridge/tools/mux_client.py +75 -0
- mcp_bridge/tools/project_context.py +1 -2
- mcp_bridge/tools/query_classifier.py +132 -49
- mcp_bridge/tools/read_file.py +84 -0
- mcp_bridge/tools/replace.py +45 -0
- mcp_bridge/tools/run_shell_command.py +38 -0
- mcp_bridge/tools/search_enhancements.py +347 -0
- mcp_bridge/tools/semantic_search.py +677 -92
- mcp_bridge/tools/session_manager.py +0 -2
- mcp_bridge/tools/skill_loader.py +0 -1
- mcp_bridge/tools/task_runner.py +5 -7
- mcp_bridge/tools/templates.py +3 -3
- mcp_bridge/tools/tool_search.py +331 -0
- mcp_bridge/tools/write_file.py +29 -0
- mcp_bridge/update_manager.py +33 -37
- mcp_bridge/update_manager_pypi.py +6 -8
- mcp_bridge/utils/cache.py +82 -0
- mcp_bridge/utils/process.py +71 -0
- mcp_bridge/utils/session_state.py +51 -0
- mcp_bridge/utils/truncation.py +76 -0
- {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/METADATA +84 -35
- stravinsky-0.4.66.dist-info/RECORD +198 -0
- {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/entry_points.txt +1 -0
- stravinsky_claude_assets/HOOKS_INTEGRATION.md +316 -0
- stravinsky_claude_assets/agents/HOOKS.md +437 -0
- stravinsky_claude_assets/agents/code-reviewer.md +210 -0
- stravinsky_claude_assets/agents/comment_checker.md +580 -0
- stravinsky_claude_assets/agents/debugger.md +254 -0
- stravinsky_claude_assets/agents/delphi.md +495 -0
- stravinsky_claude_assets/agents/dewey.md +248 -0
- stravinsky_claude_assets/agents/explore.md +1198 -0
- stravinsky_claude_assets/agents/frontend.md +472 -0
- stravinsky_claude_assets/agents/implementation-lead.md +164 -0
- stravinsky_claude_assets/agents/momus.md +464 -0
- stravinsky_claude_assets/agents/research-lead.md +141 -0
- stravinsky_claude_assets/agents/stravinsky.md +730 -0
- stravinsky_claude_assets/commands/delphi.md +9 -0
- stravinsky_claude_assets/commands/dewey.md +54 -0
- stravinsky_claude_assets/commands/git-master.md +112 -0
- stravinsky_claude_assets/commands/index.md +49 -0
- stravinsky_claude_assets/commands/publish.md +86 -0
- stravinsky_claude_assets/commands/review.md +73 -0
- stravinsky_claude_assets/commands/str/agent_cancel.md +70 -0
- stravinsky_claude_assets/commands/str/agent_list.md +56 -0
- stravinsky_claude_assets/commands/str/agent_output.md +92 -0
- stravinsky_claude_assets/commands/str/agent_progress.md +74 -0
- stravinsky_claude_assets/commands/str/agent_retry.md +94 -0
- stravinsky_claude_assets/commands/str/cancel.md +51 -0
- stravinsky_claude_assets/commands/str/clean.md +97 -0
- stravinsky_claude_assets/commands/str/continue.md +38 -0
- stravinsky_claude_assets/commands/str/index.md +199 -0
- stravinsky_claude_assets/commands/str/list_watchers.md +96 -0
- stravinsky_claude_assets/commands/str/search.md +205 -0
- stravinsky_claude_assets/commands/str/start_filewatch.md +136 -0
- stravinsky_claude_assets/commands/str/stats.md +71 -0
- stravinsky_claude_assets/commands/str/stop_filewatch.md +89 -0
- stravinsky_claude_assets/commands/str/unwatch.md +42 -0
- stravinsky_claude_assets/commands/str/watch.md +45 -0
- stravinsky_claude_assets/commands/strav.md +53 -0
- stravinsky_claude_assets/commands/stravinsky.md +292 -0
- stravinsky_claude_assets/commands/verify.md +60 -0
- stravinsky_claude_assets/commands/version.md +5 -0
- stravinsky_claude_assets/hooks/README.md +248 -0
- stravinsky_claude_assets/hooks/comment_checker.py +193 -0
- stravinsky_claude_assets/hooks/context.py +38 -0
- stravinsky_claude_assets/hooks/context_monitor.py +153 -0
- stravinsky_claude_assets/hooks/dependency_tracker.py +73 -0
- stravinsky_claude_assets/hooks/edit_recovery.py +46 -0
- stravinsky_claude_assets/hooks/execution_state_tracker.py +68 -0
- stravinsky_claude_assets/hooks/notification_hook.py +103 -0
- stravinsky_claude_assets/hooks/notification_hook_v2.py +96 -0
- stravinsky_claude_assets/hooks/parallel_execution.py +241 -0
- stravinsky_claude_assets/hooks/parallel_reinforcement.py +106 -0
- stravinsky_claude_assets/hooks/parallel_reinforcement_v2.py +112 -0
- stravinsky_claude_assets/hooks/pre_compact.py +123 -0
- stravinsky_claude_assets/hooks/ralph_loop.py +173 -0
- stravinsky_claude_assets/hooks/session_recovery.py +263 -0
- stravinsky_claude_assets/hooks/stop_hook.py +89 -0
- stravinsky_claude_assets/hooks/stravinsky_metrics.py +164 -0
- stravinsky_claude_assets/hooks/stravinsky_mode.py +146 -0
- stravinsky_claude_assets/hooks/subagent_stop.py +98 -0
- stravinsky_claude_assets/hooks/todo_continuation.py +111 -0
- stravinsky_claude_assets/hooks/todo_delegation.py +96 -0
- stravinsky_claude_assets/hooks/tool_messaging.py +281 -0
- stravinsky_claude_assets/hooks/truncator.py +23 -0
- stravinsky_claude_assets/rules/deployment_safety.md +51 -0
- stravinsky_claude_assets/rules/integration_wiring.md +89 -0
- stravinsky_claude_assets/rules/pypi_deployment.md +220 -0
- stravinsky_claude_assets/rules/stravinsky_orchestrator.md +32 -0
- stravinsky_claude_assets/settings.json +152 -0
- stravinsky_claude_assets/skills/chrome-devtools/SKILL.md +81 -0
- stravinsky_claude_assets/skills/sqlite/SKILL.md +77 -0
- stravinsky_claude_assets/skills/supabase/SKILL.md +74 -0
- stravinsky_claude_assets/task_dependencies.json +34 -0
- stravinsky-0.4.18.dist-info/RECORD +0 -88
- {stravinsky-0.4.18.dist-info → stravinsky-0.4.66.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
PostToolUse hook for user-friendly tool messaging.
|
|
4
|
+
|
|
5
|
+
Outputs concise messages about which agent/tool was used and what it did.
|
|
6
|
+
Format examples:
|
|
7
|
+
- ast-grep('Searching for authentication patterns')
|
|
8
|
+
- delphi:openai/gpt-5.2-medium('Analyzing architecture trade-offs')
|
|
9
|
+
- explore:gemini-3-flash('Finding all API endpoints')
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
# Add utils directory to path for imports
|
|
17
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "utils"))
|
|
18
|
+
from colors import get_agent_color, colorize, Color, supports_color
|
|
19
|
+
from console_format import format_tool_use, format_agent_spawn, MessageType
|
|
20
|
+
|
|
21
|
+
# Agent model mappings
|
|
22
|
+
AGENT_MODELS = {
|
|
23
|
+
"explore": "gemini-3-flash",
|
|
24
|
+
"dewey": "gemini-3-flash",
|
|
25
|
+
"code-reviewer": "sonnet",
|
|
26
|
+
"debugger": "sonnet",
|
|
27
|
+
"frontend": "gemini-3-pro-high",
|
|
28
|
+
"delphi": "gpt-5.2-medium",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# MCP Server emoji mappings
|
|
32
|
+
SERVER_EMOJIS = {
|
|
33
|
+
"github": "🟡",
|
|
34
|
+
"ast-grep": "🟤",
|
|
35
|
+
"grep-app": "🟣",
|
|
36
|
+
"MCP_DOCKER": "🔵",
|
|
37
|
+
"stravinsky": "🔧",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Tool display names (legacy mapping for simple tools)
|
|
41
|
+
TOOL_NAMES = {
|
|
42
|
+
"mcp__stravinsky__ast_grep_search": "ast-grep",
|
|
43
|
+
"mcp__stravinsky__grep_search": "grep",
|
|
44
|
+
"mcp__stravinsky__glob_files": "glob",
|
|
45
|
+
"mcp__stravinsky__lsp_diagnostics": "lsp-diagnostics",
|
|
46
|
+
"mcp__stravinsky__lsp_hover": "lsp-hover",
|
|
47
|
+
"mcp__stravinsky__lsp_goto_definition": "lsp-goto-def",
|
|
48
|
+
"mcp__stravinsky__lsp_find_references": "lsp-find-refs",
|
|
49
|
+
"mcp__stravinsky__lsp_document_symbols": "lsp-symbols",
|
|
50
|
+
"mcp__stravinsky__lsp_workspace_symbols": "lsp-workspace-symbols",
|
|
51
|
+
"mcp__stravinsky__invoke_gemini": "gemini",
|
|
52
|
+
"mcp__stravinsky__invoke_openai": "openai",
|
|
53
|
+
"mcp__grep-app__searchCode": "grep.app",
|
|
54
|
+
"mcp__grep-app__github_file": "github-file",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def parse_mcp_tool_name(tool_name: str) -> tuple[str, str, str]:
|
|
59
|
+
"""
|
|
60
|
+
Parse MCP tool name into (server, tool_type, emoji).
|
|
61
|
+
|
|
62
|
+
Examples:
|
|
63
|
+
mcp__github__get_file_contents -> ("github", "get_file_contents", "🟡")
|
|
64
|
+
mcp__stravinsky__grep_search -> ("stravinsky", "grep", "🔧")
|
|
65
|
+
mcp__ast-grep__find_code -> ("ast-grep", "find_code", "🟤")
|
|
66
|
+
"""
|
|
67
|
+
if not tool_name.startswith("mcp__"):
|
|
68
|
+
return ("unknown", tool_name, "🔧")
|
|
69
|
+
|
|
70
|
+
# Remove mcp__ prefix and split by __
|
|
71
|
+
parts = tool_name[5:].split("__", 1)
|
|
72
|
+
if len(parts) != 2:
|
|
73
|
+
return ("unknown", tool_name, "🔧")
|
|
74
|
+
|
|
75
|
+
server = parts[0]
|
|
76
|
+
tool_type = parts[1]
|
|
77
|
+
|
|
78
|
+
# Get emoji for server
|
|
79
|
+
emoji = SERVER_EMOJIS.get(server, "🔧")
|
|
80
|
+
|
|
81
|
+
# Get simplified tool name if available
|
|
82
|
+
simple_name = TOOL_NAMES.get(tool_name, tool_type)
|
|
83
|
+
|
|
84
|
+
return (server, simple_name, emoji)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def extract_description(tool_name: str, params: dict) -> str:
|
|
88
|
+
"""Extract a concise description of what the tool did."""
|
|
89
|
+
|
|
90
|
+
# GitHub tools
|
|
91
|
+
if "github" in tool_name.lower():
|
|
92
|
+
if "get_file_contents" in tool_name:
|
|
93
|
+
path = params.get("path", "")
|
|
94
|
+
repo = params.get("repo", "")
|
|
95
|
+
owner = params.get("owner", "")
|
|
96
|
+
return f"Fetching {path} from {owner}/{repo}"
|
|
97
|
+
elif "create_or_update_file" in tool_name:
|
|
98
|
+
path = params.get("path", "")
|
|
99
|
+
return f"Updating {path}"
|
|
100
|
+
elif "search_repositories" in tool_name:
|
|
101
|
+
query = params.get("query", "")
|
|
102
|
+
return f"Searching repos for '{query[:40]}'"
|
|
103
|
+
elif "search_code" in tool_name:
|
|
104
|
+
q = params.get("q", "")
|
|
105
|
+
return f"Searching code for '{q[:40]}'"
|
|
106
|
+
elif "create_pull_request" in tool_name:
|
|
107
|
+
title = params.get("title", "")
|
|
108
|
+
return f"Creating PR: {title[:40]}"
|
|
109
|
+
elif "get_pull_request" in tool_name or "list_pull_requests" in tool_name:
|
|
110
|
+
return "Fetching PR details"
|
|
111
|
+
return "GitHub operation"
|
|
112
|
+
|
|
113
|
+
# MCP_DOCKER tools
|
|
114
|
+
if "MCP_DOCKER" in tool_name:
|
|
115
|
+
if "web_search_exa" in tool_name:
|
|
116
|
+
query = params.get("query", "")
|
|
117
|
+
return f"Web search: '{query[:40]}'"
|
|
118
|
+
elif "create_entities" in tool_name:
|
|
119
|
+
entities = params.get("entities", [])
|
|
120
|
+
count = len(entities)
|
|
121
|
+
return f"Creating {count} knowledge graph entities"
|
|
122
|
+
elif "search_nodes" in tool_name:
|
|
123
|
+
query = params.get("query", "")
|
|
124
|
+
return f"Searching knowledge graph for '{query[:40]}'"
|
|
125
|
+
return "Knowledge graph operation"
|
|
126
|
+
|
|
127
|
+
# ast-grep tools
|
|
128
|
+
if "ast-grep" in tool_name or "ast_grep" in tool_name:
|
|
129
|
+
if "find_code" in tool_name or "search" in tool_name:
|
|
130
|
+
pattern = params.get("pattern", "")
|
|
131
|
+
return f"AST search for '{pattern[:40]}'"
|
|
132
|
+
elif "test_match" in tool_name:
|
|
133
|
+
return "Testing AST pattern"
|
|
134
|
+
elif "dump_syntax" in tool_name:
|
|
135
|
+
return "Dumping syntax tree"
|
|
136
|
+
return "AST operation"
|
|
137
|
+
|
|
138
|
+
# grep-app tools
|
|
139
|
+
if "grep-app" in tool_name or "grep_app" in tool_name:
|
|
140
|
+
if "searchCode" in tool_name:
|
|
141
|
+
query = params.get("query", "")
|
|
142
|
+
return f"Searching GitHub for '{query[:40]}'"
|
|
143
|
+
elif "github_file" in tool_name:
|
|
144
|
+
path = params.get("path", "")
|
|
145
|
+
repo = params.get("repo", "")
|
|
146
|
+
return f"Fetching {path} from {repo}"
|
|
147
|
+
return "grep.app search"
|
|
148
|
+
|
|
149
|
+
# AST-grep (stravinsky)
|
|
150
|
+
if "ast_grep" in tool_name:
|
|
151
|
+
pattern = params.get("pattern", "")
|
|
152
|
+
directory = params.get("directory", ".")
|
|
153
|
+
return f"Searching AST in {directory} for '{pattern[:40]}...'"
|
|
154
|
+
|
|
155
|
+
# Grep/search
|
|
156
|
+
if "grep_search" in tool_name or "searchCode" in tool_name:
|
|
157
|
+
pattern = params.get("pattern", params.get("query", ""))
|
|
158
|
+
return f"Searching for '{pattern[:40]}...'"
|
|
159
|
+
|
|
160
|
+
# Glob
|
|
161
|
+
if "glob_files" in tool_name:
|
|
162
|
+
pattern = params.get("pattern", "")
|
|
163
|
+
return f"Finding files matching '{pattern}'"
|
|
164
|
+
|
|
165
|
+
# LSP diagnostics
|
|
166
|
+
if "lsp_diagnostics" in tool_name:
|
|
167
|
+
file_path = params.get("file_path", "")
|
|
168
|
+
filename = os.path.basename(file_path) if file_path else "file"
|
|
169
|
+
return f"Checking {filename} for errors"
|
|
170
|
+
|
|
171
|
+
# LSP hover
|
|
172
|
+
if "lsp_hover" in tool_name:
|
|
173
|
+
file_path = params.get("file_path", "")
|
|
174
|
+
line = params.get("line", "")
|
|
175
|
+
filename = os.path.basename(file_path) if file_path else "file"
|
|
176
|
+
return f"Type info for {filename}:{line}"
|
|
177
|
+
|
|
178
|
+
# LSP goto definition
|
|
179
|
+
if "lsp_goto" in tool_name:
|
|
180
|
+
file_path = params.get("file_path", "")
|
|
181
|
+
filename = os.path.basename(file_path) if file_path else "symbol"
|
|
182
|
+
return f"Finding definition in {filename}"
|
|
183
|
+
|
|
184
|
+
# LSP find references
|
|
185
|
+
if "lsp_find_references" in tool_name:
|
|
186
|
+
file_path = params.get("file_path", "")
|
|
187
|
+
filename = os.path.basename(file_path) if file_path else "symbol"
|
|
188
|
+
return f"Finding all references to symbol in {filename}"
|
|
189
|
+
|
|
190
|
+
# LSP symbols
|
|
191
|
+
if "lsp_symbols" in tool_name or "lsp_document_symbols" in tool_name:
|
|
192
|
+
file_path = params.get("file_path", "")
|
|
193
|
+
filename = os.path.basename(file_path) if file_path else "file"
|
|
194
|
+
return f"Getting symbols from {filename}"
|
|
195
|
+
|
|
196
|
+
if "lsp_workspace_symbols" in tool_name:
|
|
197
|
+
query = params.get("query", "")
|
|
198
|
+
return f"Searching workspace for symbol '{query}'"
|
|
199
|
+
|
|
200
|
+
# Gemini invocation
|
|
201
|
+
if "invoke_gemini" in tool_name:
|
|
202
|
+
prompt = params.get("prompt", "")
|
|
203
|
+
# Extract first meaningful line
|
|
204
|
+
first_line = prompt.split("\n")[0][:50] if prompt else "Processing"
|
|
205
|
+
return first_line
|
|
206
|
+
|
|
207
|
+
# OpenAI invocation
|
|
208
|
+
if "invoke_openai" in tool_name:
|
|
209
|
+
prompt = params.get("prompt", "")
|
|
210
|
+
first_line = prompt.split("\n")[0][:50] if prompt else "Strategic analysis"
|
|
211
|
+
return first_line
|
|
212
|
+
|
|
213
|
+
# GitHub file fetch
|
|
214
|
+
if "github_file" in tool_name:
|
|
215
|
+
path = params.get("path", "")
|
|
216
|
+
repo = params.get("repo", "")
|
|
217
|
+
return f"Fetching {path} from {repo}"
|
|
218
|
+
|
|
219
|
+
# Agent spawn (MCP tool)
|
|
220
|
+
if "agent_spawn" in tool_name:
|
|
221
|
+
agent_type = params.get("agent_type", "unknown")
|
|
222
|
+
description = params.get("description", "")
|
|
223
|
+
model = AGENT_MODELS.get(agent_type, "gemini-3-flash")
|
|
224
|
+
return f"{agent_type}({model})"
|
|
225
|
+
|
|
226
|
+
# Task delegation
|
|
227
|
+
if tool_name == "Task":
|
|
228
|
+
subagent_type = params.get("subagent_type", "unknown")
|
|
229
|
+
description = params.get("description", "")
|
|
230
|
+
model = AGENT_MODELS.get(subagent_type, "unknown")
|
|
231
|
+
return f"{subagent_type}:{model}('{description}')"
|
|
232
|
+
|
|
233
|
+
return "Processing"
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def main():
|
|
237
|
+
try:
|
|
238
|
+
# Read hook input from stdin
|
|
239
|
+
hook_input = json.loads(sys.stdin.read())
|
|
240
|
+
|
|
241
|
+
tool_name = hook_input.get("toolName", hook_input.get("tool_name", ""))
|
|
242
|
+
params = hook_input.get("params", hook_input.get("tool_input", {}))
|
|
243
|
+
|
|
244
|
+
# Only output messages for MCP tools and Task delegations
|
|
245
|
+
if not (tool_name.startswith("mcp__") or tool_name == "Task"):
|
|
246
|
+
sys.exit(0)
|
|
247
|
+
|
|
248
|
+
# Special handling for Task delegations
|
|
249
|
+
if tool_name == "Task":
|
|
250
|
+
subagent_type = params.get("subagent_type", "unknown")
|
|
251
|
+
description = params.get("description", "")
|
|
252
|
+
model = AGENT_MODELS.get(subagent_type, "unknown")
|
|
253
|
+
|
|
254
|
+
# Use rich formatting for agent spawns
|
|
255
|
+
message = format_agent_spawn(
|
|
256
|
+
agent_type=subagent_type, model=model, description=description
|
|
257
|
+
)
|
|
258
|
+
print(message, file=sys.stderr)
|
|
259
|
+
else:
|
|
260
|
+
# Parse MCP tool name to get server, tool_type, and emoji
|
|
261
|
+
server, tool_type, emoji = parse_mcp_tool_name(tool_name)
|
|
262
|
+
|
|
263
|
+
# Get description of what the tool did
|
|
264
|
+
description = extract_description(tool_name, params)
|
|
265
|
+
|
|
266
|
+
# Use rich formatting for tool usage
|
|
267
|
+
message = format_tool_use(
|
|
268
|
+
tool_name=tool_type, server=server, description=description, emoji=emoji
|
|
269
|
+
)
|
|
270
|
+
print(message, file=sys.stderr)
|
|
271
|
+
|
|
272
|
+
sys.exit(0)
|
|
273
|
+
|
|
274
|
+
except Exception as e:
|
|
275
|
+
# On error, fail silently (don't disrupt workflow)
|
|
276
|
+
print(f"Tool messaging hook error: {e}", file=sys.stderr)
|
|
277
|
+
sys.exit(0)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
if __name__ == "__main__":
|
|
281
|
+
main()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
MAX_CHARS = 30000
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
try:
|
|
9
|
+
data = json.load(sys.stdin)
|
|
10
|
+
tool_response = data.get("tool_response", "")
|
|
11
|
+
except Exception:
|
|
12
|
+
return
|
|
13
|
+
|
|
14
|
+
if len(tool_response) > MAX_CHARS:
|
|
15
|
+
header = f"[TRUNCATED - {len(tool_response)} chars reduced to {MAX_CHARS}]\n"
|
|
16
|
+
footer = "\n...[TRUNCATED]"
|
|
17
|
+
truncated = tool_response[:MAX_CHARS]
|
|
18
|
+
print(header + truncated + footer)
|
|
19
|
+
else:
|
|
20
|
+
print(tool_response)
|
|
21
|
+
|
|
22
|
+
if __name__ == "__main__":
|
|
23
|
+
main()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Deployment Safety Rules
|
|
2
|
+
|
|
3
|
+
## CRITICAL: Pre-Deployment Checklist
|
|
4
|
+
|
|
5
|
+
**NEVER deploy code to PyPI without passing ALL checks:**
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Run this BEFORE every deployment
|
|
9
|
+
./pre_deploy_check.sh
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Mandatory Checks (BLOCKING)
|
|
13
|
+
|
|
14
|
+
1. **Import Test** - `python3 -c "import mcp_bridge.server"` must succeed
|
|
15
|
+
2. **Version Consistency** - pyproject.toml and __init__.py versions must match
|
|
16
|
+
3. **Command Works** - `stravinsky --version` must succeed
|
|
17
|
+
4. **All Tools Import** - Every tool module must import without errors
|
|
18
|
+
5. **Tests Pass** - If tests exist, `pytest` must pass
|
|
19
|
+
6. **Linting Clean** - `ruff check` must have zero errors
|
|
20
|
+
7. **Git Clean** - No uncommitted changes
|
|
21
|
+
|
|
22
|
+
## Deployment Process
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Step 1: Run safety checks
|
|
26
|
+
./pre_deploy_check.sh || {
|
|
27
|
+
echo "❌ FAILED: Fix errors before deploying"
|
|
28
|
+
exit 1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Step 2: Deploy (only if checks pass)
|
|
32
|
+
./deploy.sh
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Why This Matters
|
|
36
|
+
|
|
37
|
+
**Recent failures prevented by these checks:**
|
|
38
|
+
- **v0.4.30 (2026-01-09)**: `NameError: name 'logger' is not defined` - would be caught by import test
|
|
39
|
+
- Future: Type errors, missing imports, broken commands all caught before PyPI
|
|
40
|
+
|
|
41
|
+
## Consequences of Skipping Checks
|
|
42
|
+
|
|
43
|
+
- Broken installations for all users globally
|
|
44
|
+
- Version number burned (can't re-upload to PyPI)
|
|
45
|
+
- Force version bump to fix
|
|
46
|
+
- User trust eroded
|
|
47
|
+
- Support burden increased
|
|
48
|
+
|
|
49
|
+
## Rule
|
|
50
|
+
|
|
51
|
+
**You MUST run `./pre_deploy_check.sh` before EVERY deployment. NO EXCEPTIONS.**
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Integration Wiring Rules
|
|
2
|
+
|
|
3
|
+
## Lesson Learned: Tool-Agent Integration (2026-01-11)
|
|
4
|
+
|
|
5
|
+
**Problem**: Sub-agents fail silently when tools are "wired in" but not actually usable.
|
|
6
|
+
|
|
7
|
+
**Root Cause**: Adding a tool to an agent's tool list doesn't guarantee the agent can USE it.
|
|
8
|
+
|
|
9
|
+
## Integration Checklist (MANDATORY)
|
|
10
|
+
|
|
11
|
+
When integrating Tool X into Agent Y:
|
|
12
|
+
|
|
13
|
+
### 1. Verify Invocation Method
|
|
14
|
+
|
|
15
|
+
| Agent Type | Invocation Method | Tool Access |
|
|
16
|
+
|------------|-------------------|-------------|
|
|
17
|
+
| `invoke_gemini` | Simple completion | NO tool calling |
|
|
18
|
+
| `invoke_gemini_agentic` | Agentic loop | YES - full tool access |
|
|
19
|
+
| `invoke_openai` | Direct call | Depends on model |
|
|
20
|
+
|
|
21
|
+
**CRITICAL**: If agent needs to call tools, it MUST use the `_agentic` variant.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
# WRONG: Agent can't use tools
|
|
25
|
+
invoke_gemini(prompt="Find auth code", model="gemini-3-flash")
|
|
26
|
+
|
|
27
|
+
# RIGHT: Agent can call semantic_search, grep, etc.
|
|
28
|
+
invoke_gemini_agentic(
|
|
29
|
+
prompt="Find auth code using semantic_search",
|
|
30
|
+
model="gemini-3-flash",
|
|
31
|
+
max_iterations=5
|
|
32
|
+
)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Verify Prerequisites
|
|
36
|
+
|
|
37
|
+
Some tools have prerequisites that must be met BEFORE use:
|
|
38
|
+
|
|
39
|
+
| Tool | Prerequisite | Check |
|
|
40
|
+
|------|--------------|-------|
|
|
41
|
+
| `semantic_search` | Index must exist | Run `semantic_index()` first |
|
|
42
|
+
| `lsp_*` | LSP server must be running | Check `lsp_servers()` |
|
|
43
|
+
| `invoke_*` | Auth must be configured | Run `stravinsky-auth status` |
|
|
44
|
+
|
|
45
|
+
**Add explicit checks**: Tools should fail EARLY with clear error messages if prerequisites are not met.
|
|
46
|
+
|
|
47
|
+
### 3. Verify Parent Agent Guidance
|
|
48
|
+
|
|
49
|
+
Parent agents (orchestrators) must guide sub-agents to USE the tool:
|
|
50
|
+
|
|
51
|
+
| Level | Responsibility |
|
|
52
|
+
|-------|----------------|
|
|
53
|
+
| **Orchestrator** (stravinsky) | Tell sub-agents WHEN to use which tools |
|
|
54
|
+
| **Coordinator** (research-lead) | Tell explore/dewey HOW to use tools for query types |
|
|
55
|
+
| **Worker** (explore) | Actually CALL the tools |
|
|
56
|
+
|
|
57
|
+
**If a tool is available but never used**, check the guidance chain.
|
|
58
|
+
|
|
59
|
+
### 4. Verification Pattern
|
|
60
|
+
|
|
61
|
+
After wiring a tool, verify the FULL chain:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Step 1: Tool is in agent's tool list ✓
|
|
65
|
+
Step 2: Agent uses correct invocation ✓
|
|
66
|
+
Step 3: Prerequisites are met/checked ✓
|
|
67
|
+
Step 4: Parent agents guide usage ✓
|
|
68
|
+
Step 5: End-to-end test works ✓
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Example: semantic_search Integration (Fixed 2026-01-11)
|
|
72
|
+
|
|
73
|
+
**Original Problem**: explore agent had semantic_search in tool list but never used it.
|
|
74
|
+
|
|
75
|
+
**Root Causes Found**:
|
|
76
|
+
1. explore.md called `invoke_gemini` (no tool access) instead of `invoke_gemini_agentic`
|
|
77
|
+
2. semantic_search returned empty results when no index existed (silent failure)
|
|
78
|
+
3. research-lead.md didn't tell explore agents WHEN to use semantic_search
|
|
79
|
+
|
|
80
|
+
**Fixes Applied**:
|
|
81
|
+
1. Changed explore.md to use `invoke_gemini_agentic` with `max_iterations: 5`
|
|
82
|
+
2. Added index existence check in semantic_search.py with clear error message
|
|
83
|
+
3. Added "Pattern 3: Semantic/Conceptual Search" to research-lead.md
|
|
84
|
+
|
|
85
|
+
## Rule
|
|
86
|
+
|
|
87
|
+
**When adding a tool to an agent, verify the FULL integration chain.**
|
|
88
|
+
|
|
89
|
+
Silent failures waste hours of debugging. Fail early, fail loudly.
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# PyPI Deployment Rules
|
|
2
|
+
|
|
3
|
+
## ⚠️ CRITICAL REMINDER: ALWAYS CLEAN BEFORE BUILDING
|
|
4
|
+
|
|
5
|
+
**The #1 deployment error:** Forgetting to clean dist/ before building
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# ALWAYS RUN THIS FUWT (use Python if hooks block rm):
|
|
9
|
+
python3 -c "import shutil; from pathlib import Path; [shutil.rmtree(p) for p in [Path('dist'), Path('build')] if p.exists()]; print('✅ Cleaned')"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Why:** PyPI rejects if dist/ contains old version files (e.g., 0.4.9.tar.gz when publishing 0.4.10)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Version Management
|
|
17
|
+
|
|
18
|
+
1. **ALWAYS check PyPI first before bumping version:**
|
|
19
|
+
```bash
|
|
20
|
+
pip index versions stravinsky 2>&1 | head -20
|
|
21
|
+
```
|
|
22
|
+
If the version you're about to use already exists on PyPI, bump higher!
|
|
23
|
+
|
|
24
|
+
2. **Version must be consistent** across:
|
|
25
|
+
- `pyproject.toml` (line ~5): `version = "X.Y.Z"`
|
|
26
|
+
- `mcp_bridge/__init__.py`: `__version__ = "X.Y.Z"`
|
|
27
|
+
|
|
28
|
+
3. **Version bumping strategy**:
|
|
29
|
+
- Patch (X.Y.Z+1): Bug fixes, documentation updates
|
|
30
|
+
- Minor (X.Y+1.0): New features, agent improvements, MCP tool additions
|
|
31
|
+
- Major (X+1.0.0): Breaking changes to API or architecture
|
|
32
|
+
|
|
33
|
+
4. **⚠️ CRITICAL**: PyPI does NOT allow re-uploading the same version. If `uv publish` fails with "File already exists", you MUST bump the version number and try again.
|
|
34
|
+
|
|
35
|
+
## CRITICAL RULES
|
|
36
|
+
|
|
37
|
+
1. **Pin Python upper bounds when core dependencies require it**
|
|
38
|
+
- ✅ CORRECT: `requires-python = ">=3.11,<3.14"` (when chromadb/onnxruntime don't support 3.14+)
|
|
39
|
+
- ❌ WRONG: `requires-python = ">=3.11"` (allows installation on unsupported Python versions)
|
|
40
|
+
- Reason: Better to block installation than have broken runtime imports
|
|
41
|
+
- Current constraint: `<3.14` due to chromadb → onnxruntime lacking Python 3.14 wheels
|
|
42
|
+
|
|
43
|
+
2. **ALWAYS install globally with @latest for auto-updates**
|
|
44
|
+
- ✅ CORRECT: `claude mcp add --global stravinsky -- uvx stravinsky@latest`
|
|
45
|
+
- ❌ WRONG: `claude mcp add stravinsky -- uvx stravinsky` (no @latest)
|
|
46
|
+
- ❌ WRONG: Local `.mcp.json` entries (use global only)
|
|
47
|
+
|
|
48
|
+
## Pre-Deployment Checklist
|
|
49
|
+
|
|
50
|
+
Before deploying to PyPI, ensure:
|
|
51
|
+
|
|
52
|
+
1. ✅ All changes committed to git
|
|
53
|
+
2. ✅ Version numbers match in `pyproject.toml` and `mcp_bridge/__init__.py`
|
|
54
|
+
3. ✅ No uncommitted temp files (`.stravinsky/agents/*.out`, `logs/`)
|
|
55
|
+
4. ✅ New files properly tracked in git (check `.claude/agents/`, `docs/`)
|
|
56
|
+
5. ✅ `uv.lock` is up-to-date
|
|
57
|
+
6. ✅ **Python version constraint matches dependency requirements** (`<3.14` for chromadb)
|
|
58
|
+
|
|
59
|
+
## Deployment Process
|
|
60
|
+
|
|
61
|
+
### Step 1: Clean Build Artifacts (MANDATORY - DO NOT SKIP)
|
|
62
|
+
|
|
63
|
+
**⚠️ CRITICAL: ALWAYS clean dist/ before building, even if version was bumped!**
|
|
64
|
+
|
|
65
|
+
**Why this matters:**
|
|
66
|
+
- PyPI rejects uploads if a file with the same name already exists (even if version differs)
|
|
67
|
+
- Old build artifacts in dist/ from previous versions will cause 400 Bad Request errors
|
|
68
|
+
- `uv publish` uploads ALL files in dist/, not just the latest build
|
|
69
|
+
|
|
70
|
+
**WRONG:** ❌ Skip cleaning → build → publish (publishes old + new versions → ERROR)
|
|
71
|
+
**CORRECT:** ✅ Clean → build → publish (only publishes new version)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# ⚠️ MANDATORY: Clean ALL build artifacts first
|
|
75
|
+
# If blocked by hooks, use Python alternative:
|
|
76
|
+
python3 -c "import shutil; from pathlib import Path; [shutil.rmtree(p) for p in [Path('dist'), Path('build')] if p.exists()]; print('✅ Cleaned dist/ and build/')"
|
|
77
|
+
|
|
78
|
+
# OR if hooks allow:
|
|
79
|
+
# rm -rf dist/ build/ *.egg-info
|
|
80
|
+
|
|
81
|
+
# Verify git status
|
|
82
|
+
git status
|
|
83
|
+
|
|
84
|
+
# Ensure version consistency (MUST match exactly)
|
|
85
|
+
VERSION_TOML=$(grep -E "^version = " pyproject.toml | head -1 | cut -d'"' -f2)
|
|
86
|
+
VERSION_INIT=$(grep -E "^__version__ = " mcp_bridge/__init__.py | cut -d'"' -f2)
|
|
87
|
+
|
|
88
|
+
if [ "$VERSION_TOML" != "$VERSION_INIT" ]; then
|
|
89
|
+
echo "❌ Version mismatch: pyproject.toml=$VERSION_TOML, __init__.py=$VERSION_INIT"
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
echo "✅ Version consistent: $VERSION_TOML"
|
|
94
|
+
|
|
95
|
+
# Verify dist/ is empty (CRITICAL CHECK)
|
|
96
|
+
if [ -d "dist" ] && [ "$(ls -A dist)" ]; then
|
|
97
|
+
echo "❌ ERROR: dist/ is not empty! Old artifacts will cause publish to fail."
|
|
98
|
+
echo " Files in dist/:"
|
|
99
|
+
ls -lh dist/
|
|
100
|
+
exit 1
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
echo "✅ dist/ is clean"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Step 2: Build (ONLY after cleaning)
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Build with uv (creates dist/stravinsky-X.Y.Z.tar.gz and .whl)
|
|
110
|
+
uv build
|
|
111
|
+
|
|
112
|
+
# Verify correct version was built
|
|
113
|
+
ls -lh dist/
|
|
114
|
+
# Should ONLY show files with your new version number
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Step 3: Publish to PyPI
|
|
118
|
+
|
|
119
|
+
**CRITICAL: ALWAYS load .env file first!**
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Load .env file (PYPI_API_TOKEN is stored here)
|
|
123
|
+
source .env
|
|
124
|
+
|
|
125
|
+
# Verify token is loaded
|
|
126
|
+
if [ -z "$PYPI_API_TOKEN" ]; then
|
|
127
|
+
echo "❌ PYPI_API_TOKEN not found in .env"
|
|
128
|
+
exit 1
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# Publish using PyPI API token from .env
|
|
132
|
+
uv publish --token "$PYPI_API_TOKEN"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Step 4: Git Tag and Push
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Create git tag
|
|
139
|
+
VERSION=$(grep -E "^version = " pyproject.toml | head -1 | cut -d'"' -f2)
|
|
140
|
+
git tag -a "v$VERSION" -m "chore: release v$VERSION"
|
|
141
|
+
|
|
142
|
+
# Push with tags
|
|
143
|
+
git push origin main --tags
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Step 5: Force uvx Cache Clear (MANDATORY)
|
|
147
|
+
|
|
148
|
+
**⚠️ CRITICAL: ALWAYS clear uvx cache after deployment!**
|
|
149
|
+
|
|
150
|
+
**Why this matters:**
|
|
151
|
+
- `@latest` doesn't force PyPI checks if uvx has a cached version
|
|
152
|
+
- Without clearing, users stay on old versions FOREVER
|
|
153
|
+
- This is THE most common cause of "version deployed but not updating" issues
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Clear uvx cache to force fresh PyPI fetch on next Claude restart
|
|
157
|
+
python3 -c "import shutil; from pathlib import Path; cache = Path.home() / '.cache' / 'uv'; shutil.rmtree(cache, ignore_errors=True); print('✅ Cleared uvx cache - restart Claude Code to fetch v$(grep -E "^version = " pyproject.toml | head -1 | cut -d'"' -f2)')"
|
|
158
|
+
|
|
159
|
+
# Verify deployment is on PyPI
|
|
160
|
+
pip index versions stravinsky 2>&1 | head -5
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Post-cache-clear:**
|
|
164
|
+
1. Restart Claude Code (or wait for next restart)
|
|
165
|
+
2. uvx will fetch the latest version from PyPI
|
|
166
|
+
3. Verify with: run any stravinsky MCP tool and check version in output
|
|
167
|
+
|
|
168
|
+
## Commit Message Convention
|
|
169
|
+
|
|
170
|
+
Use conventional commit format:
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
<type>: <description>
|
|
174
|
+
|
|
175
|
+
[optional body]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Types:**
|
|
179
|
+
- `feat`: New feature
|
|
180
|
+
- `fix`: Bug fix
|
|
181
|
+
- `docs`: Documentation changes
|
|
182
|
+
- `chore`: Build/release tasks
|
|
183
|
+
- `refactor`: Code restructuring
|
|
184
|
+
- `test`: Test additions/changes
|
|
185
|
+
|
|
186
|
+
**Example:**
|
|
187
|
+
```
|
|
188
|
+
feat: expand explore.md Multi-Model Usage from 12 to 319 lines
|
|
189
|
+
|
|
190
|
+
- Added 5 detailed examples with agent_context
|
|
191
|
+
- Documented gemini-3-flash usage patterns
|
|
192
|
+
- Added Model Selection Strategy section
|
|
193
|
+
- Documented haiku fallback behavior
|
|
194
|
+
- Added Gemini Best Practices (5 subsections)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Emergency Rollback
|
|
198
|
+
|
|
199
|
+
If deployment fails:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Revert to previous version
|
|
203
|
+
git revert HEAD
|
|
204
|
+
git push origin main
|
|
205
|
+
|
|
206
|
+
# Delete failed tag
|
|
207
|
+
git tag -d v$VERSION
|
|
208
|
+
git push origin :refs/tags/v$VERSION
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Post-Deployment Verification
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Verify PyPI package
|
|
215
|
+
pip install --upgrade stravinsky==$VERSION
|
|
216
|
+
|
|
217
|
+
# Check version
|
|
218
|
+
stravinsky --version
|
|
219
|
+
python -c "import mcp_bridge; print(mcp_bridge.__version__)"
|
|
220
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Stravinsky Orchestrator Triggers
|
|
2
|
+
|
|
3
|
+
This rule ensures that the Stravinsky orchestrator persona and ULTRAWORK mode are correctly initiated when relevant keywords are used.
|
|
4
|
+
|
|
5
|
+
## Triggers
|
|
6
|
+
|
|
7
|
+
- Keywords: `stravinsky`, `ultrawork`, `ulw`, `uw`
|
|
8
|
+
- Slash Commands: `/strav`, `/stravinsky`
|
|
9
|
+
|
|
10
|
+
## Instructions
|
|
11
|
+
|
|
12
|
+
If the user initiates a task with any of the triggers above:
|
|
13
|
+
|
|
14
|
+
1. **Assume the Stravinsky Persona**: You are a task orchestrator and parallel execution specialist.
|
|
15
|
+
2. **Activate Parallel Mode**: You MUST use the `Task` tool for all specialized sub-tasks.
|
|
16
|
+
3. **No Sequential Work**: If a task has 3+ independent steps, you MUST spawn subagents in parallel.
|
|
17
|
+
4. **Verification**: Never trust a subagent result without verifying it (e.g., via `lsp_diagnostics` or tests).
|
|
18
|
+
|
|
19
|
+
### ULTRAWORK Mode (ulw, uw)
|
|
20
|
+
|
|
21
|
+
If the `ULTRAWORK` (or `ulw`, `uw`) keyword is detected:
|
|
22
|
+
- Say "ULTRAWORK MODE ENABLED!" as your first response.
|
|
23
|
+
- Maximum parallelization is required (spawn all independent tasks immediately).
|
|
24
|
+
- Use a 32k thinking budget for planning.
|
|
25
|
+
- Deliver a full implementation, not a demo or skeleton.
|
|
26
|
+
|
|
27
|
+
## Tool Enforcement
|
|
28
|
+
|
|
29
|
+
When Stravinsky mode is active:
|
|
30
|
+
- **BLOCKED**: Direct file reading/searching tools (`Read`, `Search`, `Grep`, `Bash`).
|
|
31
|
+
- **REQUIRED**: Use the `Task` tool to delegate to `explore`, `dewey`, `code-reviewer`, etc.
|
|
32
|
+
- **EXCEPTION**: You may use `TodoRead`/`TodoWrite` for planning.
|