stravinsky 0.2.40__py3-none-any.whl → 0.2.67__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_refresh.py +130 -0
- mcp_bridge/cli/__init__.py +6 -0
- mcp_bridge/cli/install_hooks.py +1265 -0
- mcp_bridge/cli/session_report.py +585 -0
- mcp_bridge/hooks/HOOKS_SETTINGS.json +175 -0
- mcp_bridge/hooks/README.md +215 -0
- mcp_bridge/hooks/__init__.py +117 -46
- mcp_bridge/hooks/edit_recovery.py +42 -37
- mcp_bridge/hooks/git_noninteractive.py +89 -0
- mcp_bridge/hooks/keyword_detector.py +30 -0
- mcp_bridge/hooks/manager.py +50 -0
- mcp_bridge/hooks/notification_hook.py +103 -0
- mcp_bridge/hooks/parallel_enforcer.py +127 -0
- mcp_bridge/hooks/parallel_execution.py +111 -0
- mcp_bridge/hooks/pre_compact.py +123 -0
- mcp_bridge/hooks/preemptive_compaction.py +81 -7
- mcp_bridge/hooks/rules_injector.py +507 -0
- mcp_bridge/hooks/session_idle.py +116 -0
- mcp_bridge/hooks/session_notifier.py +125 -0
- mcp_bridge/{native_hooks → hooks}/stravinsky_mode.py +51 -16
- mcp_bridge/hooks/subagent_stop.py +98 -0
- mcp_bridge/hooks/task_validator.py +73 -0
- mcp_bridge/hooks/tmux_manager.py +141 -0
- mcp_bridge/hooks/todo_continuation.py +90 -0
- mcp_bridge/hooks/todo_delegation.py +88 -0
- mcp_bridge/hooks/tool_messaging.py +164 -0
- mcp_bridge/hooks/truncator.py +21 -17
- mcp_bridge/prompts/__init__.py +3 -1
- mcp_bridge/prompts/dewey.py +30 -20
- mcp_bridge/prompts/explore.py +46 -8
- mcp_bridge/prompts/multimodal.py +24 -3
- mcp_bridge/prompts/planner.py +222 -0
- mcp_bridge/prompts/stravinsky.py +107 -28
- mcp_bridge/server.py +76 -10
- mcp_bridge/server_tools.py +164 -32
- mcp_bridge/tools/agent_manager.py +203 -96
- mcp_bridge/tools/background_tasks.py +2 -1
- mcp_bridge/tools/code_search.py +81 -9
- mcp_bridge/tools/lsp/tools.py +6 -2
- mcp_bridge/tools/model_invoke.py +270 -47
- mcp_bridge/tools/templates.py +32 -18
- stravinsky-0.2.67.dist-info/METADATA +284 -0
- stravinsky-0.2.67.dist-info/RECORD +76 -0
- stravinsky-0.2.67.dist-info/entry_points.txt +5 -0
- mcp_bridge/native_hooks/edit_recovery.py +0 -46
- mcp_bridge/native_hooks/truncator.py +0 -23
- stravinsky-0.2.40.dist-info/METADATA +0 -204
- stravinsky-0.2.40.dist-info/RECORD +0 -57
- stravinsky-0.2.40.dist-info/entry_points.txt +0 -3
- /mcp_bridge/{native_hooks → hooks}/context.py +0 -0
- {stravinsky-0.2.40.dist-info → stravinsky-0.2.67.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
UserPromptSubmit hook: Todo Continuation Enforcer
|
|
4
|
+
|
|
5
|
+
Checks if there are incomplete todos (in_progress or pending) and injects
|
|
6
|
+
a reminder to continue working on them before starting new work.
|
|
7
|
+
|
|
8
|
+
Aligned with oh-my-opencode's [SYSTEM REMINDER - TODO CONTINUATION] pattern.
|
|
9
|
+
"""
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_todo_state() -> dict:
|
|
17
|
+
"""Try to get current todo state from Claude Code session or local cache."""
|
|
18
|
+
# Claude Code stores todo state - we can check via session files
|
|
19
|
+
# For now, we'll use a simple file-based approach
|
|
20
|
+
cwd = Path(os.environ.get("CLAUDE_CWD", "."))
|
|
21
|
+
todo_cache = cwd / ".claude" / "todo_state.json"
|
|
22
|
+
|
|
23
|
+
if todo_cache.exists():
|
|
24
|
+
try:
|
|
25
|
+
return json.loads(todo_cache.read_text())
|
|
26
|
+
except Exception:
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
return {"todos": []}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def main():
|
|
33
|
+
try:
|
|
34
|
+
data = json.load(sys.stdin)
|
|
35
|
+
prompt = data.get("prompt", "")
|
|
36
|
+
except Exception:
|
|
37
|
+
return 0
|
|
38
|
+
|
|
39
|
+
# Get current todo state
|
|
40
|
+
state = get_todo_state()
|
|
41
|
+
todos = state.get("todos", [])
|
|
42
|
+
|
|
43
|
+
if not todos:
|
|
44
|
+
# No todos tracked, pass through
|
|
45
|
+
print(prompt)
|
|
46
|
+
return 0
|
|
47
|
+
|
|
48
|
+
# Count incomplete todos
|
|
49
|
+
in_progress = [t for t in todos if t.get("status") == "in_progress"]
|
|
50
|
+
pending = [t for t in todos if t.get("status") == "pending"]
|
|
51
|
+
|
|
52
|
+
if not in_progress and not pending:
|
|
53
|
+
# All todos complete, pass through
|
|
54
|
+
print(prompt)
|
|
55
|
+
return 0
|
|
56
|
+
|
|
57
|
+
# Build reminder
|
|
58
|
+
reminder_parts = ["[SYSTEM REMINDER - TODO CONTINUATION]", ""]
|
|
59
|
+
|
|
60
|
+
if in_progress:
|
|
61
|
+
reminder_parts.append(f"IN PROGRESS ({len(in_progress)} items):")
|
|
62
|
+
for t in in_progress:
|
|
63
|
+
reminder_parts.append(f" - {t.get('content', 'Unknown task')}")
|
|
64
|
+
reminder_parts.append("")
|
|
65
|
+
|
|
66
|
+
if pending:
|
|
67
|
+
reminder_parts.append(f"PENDING ({len(pending)} items):")
|
|
68
|
+
for t in pending[:5]: # Show max 5 pending
|
|
69
|
+
reminder_parts.append(f" - {t.get('content', 'Unknown task')}")
|
|
70
|
+
if len(pending) > 5:
|
|
71
|
+
reminder_parts.append(f" ... and {len(pending) - 5} more")
|
|
72
|
+
reminder_parts.append("")
|
|
73
|
+
|
|
74
|
+
reminder_parts.extend([
|
|
75
|
+
"IMPORTANT: You have incomplete work. Before starting anything new:",
|
|
76
|
+
"1. Continue working on IN_PROGRESS todos first",
|
|
77
|
+
"2. If blocked, explain why and move to next PENDING item",
|
|
78
|
+
"3. Only start NEW work if all todos are complete or explicitly abandoned",
|
|
79
|
+
"",
|
|
80
|
+
"---",
|
|
81
|
+
"",
|
|
82
|
+
])
|
|
83
|
+
|
|
84
|
+
reminder = "\n".join(reminder_parts)
|
|
85
|
+
print(reminder + prompt)
|
|
86
|
+
return 0
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
if __name__ == "__main__":
|
|
90
|
+
sys.exit(main())
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
PostToolUse hook for TodoWrite: CRITICAL parallel execution enforcer.
|
|
4
|
+
|
|
5
|
+
This hook fires AFTER TodoWrite completes. If there are 2+ pending items,
|
|
6
|
+
it outputs a STRONG reminder that Task agents must be spawned immediately.
|
|
7
|
+
|
|
8
|
+
Exit code 2 is used to signal a HARD BLOCK - Claude should see this as
|
|
9
|
+
a failure condition requiring immediate correction.
|
|
10
|
+
|
|
11
|
+
Works in tandem with:
|
|
12
|
+
- parallel_execution.py (UserPromptSubmit): Pre-emptive instruction injection
|
|
13
|
+
- stravinsky_mode.py (PreToolUse): Hard blocking of Read/Grep/Bash tools
|
|
14
|
+
"""
|
|
15
|
+
import json
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
# Check if stravinsky mode is active (hard blocking enabled)
|
|
20
|
+
STRAVINSKY_MODE_FILE = Path.home() / ".stravinsky_mode"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def is_stravinsky_mode():
|
|
24
|
+
"""Check if hard blocking mode is active."""
|
|
25
|
+
return STRAVINSKY_MODE_FILE.exists()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def main():
|
|
29
|
+
# Read hook input from stdin
|
|
30
|
+
try:
|
|
31
|
+
hook_input = json.load(sys.stdin)
|
|
32
|
+
except (json.JSONDecodeError, EOFError):
|
|
33
|
+
return 0
|
|
34
|
+
|
|
35
|
+
tool_name = hook_input.get("tool_name", "")
|
|
36
|
+
|
|
37
|
+
if tool_name != "TodoWrite":
|
|
38
|
+
return 0
|
|
39
|
+
|
|
40
|
+
# Get the todos that were just written
|
|
41
|
+
tool_input = hook_input.get("tool_input", {})
|
|
42
|
+
todos = tool_input.get("todos", [])
|
|
43
|
+
|
|
44
|
+
# Count pending todos
|
|
45
|
+
pending_count = sum(1 for t in todos if t.get("status") == "pending")
|
|
46
|
+
|
|
47
|
+
if pending_count < 2:
|
|
48
|
+
return 0
|
|
49
|
+
|
|
50
|
+
# Check if stravinsky mode is active
|
|
51
|
+
stravinsky_active = is_stravinsky_mode()
|
|
52
|
+
|
|
53
|
+
# CRITICAL: Output urgent reminder for parallel Task spawning
|
|
54
|
+
mode_warning = ""
|
|
55
|
+
if stravinsky_active:
|
|
56
|
+
mode_warning = """
|
|
57
|
+
⚠️ STRAVINSKY MODE ACTIVE - Direct tools (Read, Grep, Bash) are BLOCKED.
|
|
58
|
+
You MUST use Task(subagent_type="explore", ...) for ALL file operations.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
error_message = f"""
|
|
62
|
+
🚨 PARALLEL DELEGATION REQUIRED 🚨
|
|
63
|
+
|
|
64
|
+
TodoWrite created {pending_count} pending items.
|
|
65
|
+
{mode_warning}
|
|
66
|
+
You MUST spawn Task agents for ALL independent TODOs in THIS SAME RESPONSE.
|
|
67
|
+
|
|
68
|
+
Required pattern (IMMEDIATELY after this message):
|
|
69
|
+
Task(subagent_type="explore", prompt="TODO 1...", description="TODO 1", run_in_background=true)
|
|
70
|
+
Task(subagent_type="explore", prompt="TODO 2...", description="TODO 2", run_in_background=true)
|
|
71
|
+
...
|
|
72
|
+
|
|
73
|
+
DO NOT:
|
|
74
|
+
- End your response without spawning Tasks
|
|
75
|
+
- Mark TODOs in_progress before spawning Tasks
|
|
76
|
+
- Use Read/Grep/Bash directly (BLOCKED in stravinsky mode)
|
|
77
|
+
|
|
78
|
+
Your NEXT action MUST be multiple Task() calls, one for each independent TODO.
|
|
79
|
+
"""
|
|
80
|
+
print(error_message, file=sys.stderr)
|
|
81
|
+
|
|
82
|
+
# Exit code 2 = HARD BLOCK in stravinsky mode
|
|
83
|
+
# Exit code 1 = WARNING otherwise
|
|
84
|
+
return 2 if stravinsky_active else 1
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
if __name__ == "__main__":
|
|
88
|
+
sys.exit(main())
|
|
@@ -0,0 +1,164 @@
|
|
|
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
|
+
# Agent model mappings
|
|
17
|
+
AGENT_MODELS = {
|
|
18
|
+
"explore": "gemini-3-flash",
|
|
19
|
+
"dewey": "gemini-3-flash",
|
|
20
|
+
"code-reviewer": "sonnet",
|
|
21
|
+
"debugger": "sonnet",
|
|
22
|
+
"frontend": "gemini-3-pro-high",
|
|
23
|
+
"delphi": "gpt-5.2-medium",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Tool display names
|
|
27
|
+
TOOL_NAMES = {
|
|
28
|
+
"mcp__stravinsky__ast_grep_search": "ast-grep",
|
|
29
|
+
"mcp__stravinsky__grep_search": "grep",
|
|
30
|
+
"mcp__stravinsky__glob_files": "glob",
|
|
31
|
+
"mcp__stravinsky__lsp_diagnostics": "lsp-diagnostics",
|
|
32
|
+
"mcp__stravinsky__lsp_hover": "lsp-hover",
|
|
33
|
+
"mcp__stravinsky__lsp_goto_definition": "lsp-goto-def",
|
|
34
|
+
"mcp__stravinsky__lsp_find_references": "lsp-find-refs",
|
|
35
|
+
"mcp__stravinsky__lsp_document_symbols": "lsp-symbols",
|
|
36
|
+
"mcp__stravinsky__lsp_workspace_symbols": "lsp-workspace-symbols",
|
|
37
|
+
"mcp__stravinsky__invoke_gemini": "gemini",
|
|
38
|
+
"mcp__stravinsky__invoke_openai": "openai",
|
|
39
|
+
"mcp__grep-app__searchCode": "grep.app",
|
|
40
|
+
"mcp__grep-app__github_file": "github-file",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def extract_description(tool_name: str, params: dict) -> str:
|
|
45
|
+
"""Extract a concise description of what the tool did."""
|
|
46
|
+
|
|
47
|
+
# AST-grep
|
|
48
|
+
if "ast_grep" in tool_name:
|
|
49
|
+
pattern = params.get("pattern", "")
|
|
50
|
+
directory = params.get("directory", ".")
|
|
51
|
+
return f"Searching AST in {directory} for '{pattern[:40]}...'"
|
|
52
|
+
|
|
53
|
+
# Grep/search
|
|
54
|
+
if "grep_search" in tool_name or "searchCode" in tool_name:
|
|
55
|
+
pattern = params.get("pattern", params.get("query", ""))
|
|
56
|
+
return f"Searching for '{pattern[:40]}...'"
|
|
57
|
+
|
|
58
|
+
# Glob
|
|
59
|
+
if "glob_files" in tool_name:
|
|
60
|
+
pattern = params.get("pattern", "")
|
|
61
|
+
return f"Finding files matching '{pattern}'"
|
|
62
|
+
|
|
63
|
+
# LSP diagnostics
|
|
64
|
+
if "lsp_diagnostics" in tool_name:
|
|
65
|
+
file_path = params.get("file_path", "")
|
|
66
|
+
filename = os.path.basename(file_path) if file_path else "file"
|
|
67
|
+
return f"Checking {filename} for errors"
|
|
68
|
+
|
|
69
|
+
# LSP hover
|
|
70
|
+
if "lsp_hover" in tool_name:
|
|
71
|
+
file_path = params.get("file_path", "")
|
|
72
|
+
line = params.get("line", "")
|
|
73
|
+
filename = os.path.basename(file_path) if file_path else "file"
|
|
74
|
+
return f"Type info for {filename}:{line}"
|
|
75
|
+
|
|
76
|
+
# LSP goto definition
|
|
77
|
+
if "lsp_goto" in tool_name:
|
|
78
|
+
file_path = params.get("file_path", "")
|
|
79
|
+
filename = os.path.basename(file_path) if file_path else "symbol"
|
|
80
|
+
return f"Finding definition in {filename}"
|
|
81
|
+
|
|
82
|
+
# LSP find references
|
|
83
|
+
if "lsp_find_references" in tool_name:
|
|
84
|
+
file_path = params.get("file_path", "")
|
|
85
|
+
filename = os.path.basename(file_path) if file_path else "symbol"
|
|
86
|
+
return f"Finding all references to symbol in {filename}"
|
|
87
|
+
|
|
88
|
+
# LSP symbols
|
|
89
|
+
if "lsp_symbols" in tool_name or "lsp_document_symbols" in tool_name:
|
|
90
|
+
file_path = params.get("file_path", "")
|
|
91
|
+
filename = os.path.basename(file_path) if file_path else "file"
|
|
92
|
+
return f"Getting symbols from {filename}"
|
|
93
|
+
|
|
94
|
+
if "lsp_workspace_symbols" in tool_name:
|
|
95
|
+
query = params.get("query", "")
|
|
96
|
+
return f"Searching workspace for symbol '{query}'"
|
|
97
|
+
|
|
98
|
+
# Gemini invocation
|
|
99
|
+
if "invoke_gemini" in tool_name:
|
|
100
|
+
prompt = params.get("prompt", "")
|
|
101
|
+
# Extract first meaningful line
|
|
102
|
+
first_line = prompt.split('\n')[0][:50] if prompt else "Processing"
|
|
103
|
+
return first_line
|
|
104
|
+
|
|
105
|
+
# OpenAI invocation
|
|
106
|
+
if "invoke_openai" in tool_name:
|
|
107
|
+
prompt = params.get("prompt", "")
|
|
108
|
+
first_line = prompt.split('\n')[0][:50] if prompt else "Strategic analysis"
|
|
109
|
+
return first_line
|
|
110
|
+
|
|
111
|
+
# GitHub file fetch
|
|
112
|
+
if "github_file" in tool_name:
|
|
113
|
+
path = params.get("path", "")
|
|
114
|
+
repo = params.get("repo", "")
|
|
115
|
+
return f"Fetching {path} from {repo}"
|
|
116
|
+
|
|
117
|
+
# Task delegation
|
|
118
|
+
if tool_name == "Task":
|
|
119
|
+
subagent_type = params.get("subagent_type", "unknown")
|
|
120
|
+
description = params.get("description", "")
|
|
121
|
+
model = AGENT_MODELS.get(subagent_type, "unknown")
|
|
122
|
+
return f"{subagent_type}:{model}('{description}')"
|
|
123
|
+
|
|
124
|
+
return "Processing"
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def main():
|
|
128
|
+
try:
|
|
129
|
+
# Read hook input from stdin
|
|
130
|
+
hook_input = json.loads(sys.stdin.read())
|
|
131
|
+
|
|
132
|
+
tool_name = hook_input.get("toolName", hook_input.get("tool_name", ""))
|
|
133
|
+
params = hook_input.get("params", hook_input.get("tool_input", {}))
|
|
134
|
+
|
|
135
|
+
# Only output messages for MCP tools and Task delegations
|
|
136
|
+
if not (tool_name.startswith("mcp__") or tool_name == "Task"):
|
|
137
|
+
sys.exit(0)
|
|
138
|
+
|
|
139
|
+
# Get tool display name
|
|
140
|
+
display_name = TOOL_NAMES.get(tool_name, tool_name)
|
|
141
|
+
|
|
142
|
+
# Special handling for Task delegations
|
|
143
|
+
if tool_name == "Task":
|
|
144
|
+
subagent_type = params.get("subagent_type", "unknown")
|
|
145
|
+
description = params.get("description", "")
|
|
146
|
+
model = AGENT_MODELS.get(subagent_type, "unknown")
|
|
147
|
+
|
|
148
|
+
# Show full agent delegation message
|
|
149
|
+
print(f"🎯 {subagent_type}:{model}('{description}')", file=sys.stderr)
|
|
150
|
+
else:
|
|
151
|
+
# Regular tool usage
|
|
152
|
+
description = extract_description(tool_name, params)
|
|
153
|
+
print(f"🔧 {display_name}('{description}')", file=sys.stderr)
|
|
154
|
+
|
|
155
|
+
sys.exit(0)
|
|
156
|
+
|
|
157
|
+
except Exception as e:
|
|
158
|
+
# On error, fail silently (don't disrupt workflow)
|
|
159
|
+
print(f"Tool messaging hook error: {e}", file=sys.stderr)
|
|
160
|
+
sys.exit(0)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
if __name__ == "__main__":
|
|
164
|
+
main()
|
mcp_bridge/hooks/truncator.py
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
"""
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
MAX_CHARS = 30000
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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()
|
mcp_bridge/prompts/__init__.py
CHANGED
|
@@ -6,13 +6,15 @@ from . import explore
|
|
|
6
6
|
from . import frontend
|
|
7
7
|
from . import document_writer
|
|
8
8
|
from . import multimodal
|
|
9
|
+
from . import planner
|
|
9
10
|
|
|
10
11
|
__all__ = [
|
|
11
12
|
"stravinsky",
|
|
12
|
-
"delphi",
|
|
13
|
+
"delphi",
|
|
13
14
|
"dewey",
|
|
14
15
|
"explore",
|
|
15
16
|
"frontend",
|
|
16
17
|
"document_writer",
|
|
17
18
|
"multimodal",
|
|
19
|
+
"planner",
|
|
18
20
|
]
|
mcp_bridge/prompts/dewey.py
CHANGED
|
@@ -50,8 +50,8 @@ Classify EVERY request into one of these categories before taking action:
|
|
|
50
50
|
|
|
51
51
|
| Type | Trigger Examples | Tools |
|
|
52
52
|
|------|------------------|-------|
|
|
53
|
-
| **TYPE A: CONCEPTUAL** | "How do I use X?", "Best practice for Y?" |
|
|
54
|
-
| **TYPE B: IMPLEMENTATION** | "How does X implement Y?", "Show me source of Z" | gh clone + read + blame |
|
|
53
|
+
| **TYPE A: CONCEPTUAL** | "How do I use X?", "Best practice for Y?" | exa websearch + grep-app GitHub search (parallel) |
|
|
54
|
+
| **TYPE B: IMPLEMENTATION** | "How does X implement Y?", "Show me source of Z" | gh clone + ast-grep + read + blame |
|
|
55
55
|
| **TYPE C: CONTEXT** | "Why was this changed?", "History of X?" | gh issues/prs + git log/blame |
|
|
56
56
|
| **TYPE D: COMPREHENSIVE** | Complex/ambiguous requests | ALL tools in parallel |
|
|
57
57
|
|
|
@@ -64,12 +64,15 @@ Classify EVERY request into one of these categories before taking action:
|
|
|
64
64
|
|
|
65
65
|
**Execute in parallel (3+ calls)**:
|
|
66
66
|
```
|
|
67
|
-
Tool 1:
|
|
68
|
-
|
|
69
|
-
Tool
|
|
67
|
+
Tool 1: mcp__MCP_DOCKER__web_search_exa(query="library-name topic 2026", num_results=5)
|
|
68
|
+
-> Current articles, blog posts, best practices (ALWAYS use Exa instead of native WebSearch)
|
|
69
|
+
Tool 2: mcp__grep-app__searchCode(query="library-name implementation pattern")
|
|
70
|
+
-> Real GitHub code examples with permalinks
|
|
71
|
+
Tool 3: gh search repos "library-name" --sort stars --limit 5
|
|
72
|
+
-> Popular repositories for reference
|
|
70
73
|
```
|
|
71
74
|
|
|
72
|
-
**Output**:
|
|
75
|
+
**Output**: Synthesize with evidence links (Exa URLs + GitHub permalinks).
|
|
73
76
|
|
|
74
77
|
---
|
|
75
78
|
|
|
@@ -85,8 +88,8 @@ Step 2: Get commit SHA for permalinks
|
|
|
85
88
|
cd ${TMPDIR:-/tmp}/repo-name && git rev-parse HEAD
|
|
86
89
|
|
|
87
90
|
Step 3: Find the implementation
|
|
88
|
-
-
|
|
89
|
-
-
|
|
91
|
+
- mcp__ast-grep__find_code(pattern="function $NAME", language="typescript") for structural search
|
|
92
|
+
- grep_search for function/class names
|
|
90
93
|
- Read the specific file
|
|
91
94
|
- git blame for context if needed
|
|
92
95
|
|
|
@@ -97,9 +100,9 @@ Step 4: Construct permalink
|
|
|
97
100
|
**Parallel acceleration (4+ calls)**:
|
|
98
101
|
```
|
|
99
102
|
Tool 1: gh repo clone owner/repo ${TMPDIR:-/tmp}/repo -- --depth 1
|
|
100
|
-
Tool 2:
|
|
103
|
+
Tool 2: mcp__grep-app__searchCode(query="repo:owner/repo function_name")
|
|
101
104
|
Tool 3: gh api repos/owner/repo/commits/HEAD --jq '.sha'
|
|
102
|
-
Tool 4:
|
|
105
|
+
Tool 4: mcp__MCP_DOCKER__web_search_exa(query="library-name function_name documentation 2026")
|
|
103
106
|
```
|
|
104
107
|
|
|
105
108
|
---
|
|
@@ -131,13 +134,15 @@ gh api repos/owner/repo/pulls/<number>/files
|
|
|
131
134
|
|
|
132
135
|
**Execute ALL in parallel (6+ calls)**:
|
|
133
136
|
```
|
|
134
|
-
//
|
|
135
|
-
Tool 1:
|
|
136
|
-
Tool 2: Web search ("topic recent updates 2025")
|
|
137
|
+
// Web Search (ALWAYS use Exa)
|
|
138
|
+
Tool 1: mcp__MCP_DOCKER__web_search_exa(query="topic recent updates 2026", num_results=10)
|
|
137
139
|
|
|
138
|
-
// Code Search
|
|
139
|
-
Tool
|
|
140
|
-
Tool
|
|
140
|
+
// GitHub Code Search
|
|
141
|
+
Tool 2: mcp__grep-app__searchCode(query="topic implementation pattern")
|
|
142
|
+
Tool 3: mcp__grep-app__searchCode(query="topic usage example")
|
|
143
|
+
|
|
144
|
+
// AST Pattern Search
|
|
145
|
+
Tool 4: mcp__ast-grep__find_code(pattern="$PATTERN", language="typescript")
|
|
141
146
|
|
|
142
147
|
// Source Analysis
|
|
143
148
|
Tool 5: gh repo clone owner/repo ${TMPDIR:-/tmp}/repo -- --depth 1
|
|
@@ -182,15 +187,20 @@ https://github.com/tanstack/query/blob/abc123def/packages/react-query/src/useQue
|
|
|
182
187
|
|
|
183
188
|
---
|
|
184
189
|
|
|
185
|
-
## TOOL REFERENCE (Stravinsky Tools)
|
|
190
|
+
## TOOL REFERENCE (Stravinsky + MCP DOCKER Tools)
|
|
186
191
|
|
|
187
192
|
### Primary Tools by Purpose
|
|
188
193
|
|
|
189
194
|
| Purpose | Tool | Usage |
|
|
190
195
|
|---------|------|-------|
|
|
191
|
-
| **
|
|
192
|
-
| **
|
|
193
|
-
| **File
|
|
196
|
+
| **Web Search** | `mcp__MCP_DOCKER__web_search_exa` | **ALWAYS use instead of native WebSearch** - Real-time web search for current articles, docs, tutorials |
|
|
197
|
+
| **GitHub Code Search** | `mcp__grep-app__searchCode` | Search across public GitHub repositories - returns permalinks |
|
|
198
|
+
| **GitHub File Fetch** | `mcp__grep-app__github_file` | Fetch specific file from GitHub repo |
|
|
199
|
+
| **AST Pattern Search** | `mcp__ast-grep__find_code` | Structural code search across 25+ languages with AST awareness |
|
|
200
|
+
| **AST Replace** | `mcp__ast-grep__replace` | AST-aware code refactoring and replacement |
|
|
201
|
+
| **Local Code Search** | `grep_search` | Pattern-based search in local/cloned repos (uses ripgrep) |
|
|
202
|
+
| **Local AST Search** | `ast_grep_search` | AST search in cloned repos |
|
|
203
|
+
| **File Glob** | `glob_files` | Find files by pattern |
|
|
194
204
|
| **Clone Repo** | gh CLI | `gh repo clone owner/repo ${TMPDIR:-/tmp}/name -- --depth 1` |
|
|
195
205
|
| **Issues/PRs** | gh CLI | `gh search issues/prs "query" --repo owner/repo` |
|
|
196
206
|
| **View Issue/PR** | gh CLI | `gh issue/pr view <num> --repo owner/repo --comments` |
|
mcp_bridge/prompts/explore.py
CHANGED
|
@@ -96,14 +96,52 @@ Your response has **FAILED** if:
|
|
|
96
96
|
- **No emojis**: Keep output clean and parseable
|
|
97
97
|
- **No file creation**: Report findings as message text, never write files
|
|
98
98
|
|
|
99
|
-
## Tool Strategy
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
- **Semantic search** (definitions, references):
|
|
103
|
-
- **Structural patterns** (function shapes, class structures): ast_grep_search
|
|
104
|
-
- **Text patterns** (strings, comments, logs):
|
|
105
|
-
- **File patterns** (find by name/extension):
|
|
106
|
-
- **History/evolution** (when added, who changed): git commands
|
|
99
|
+
## Tool Strategy & Available Tools
|
|
100
|
+
|
|
101
|
+
### Local Codebase Tools
|
|
102
|
+
- **Semantic search** (definitions, references): `lsp_goto_definition`, `lsp_find_references`, `lsp_workspace_symbols`
|
|
103
|
+
- **Structural patterns** (function shapes, class structures): `ast_grep_search` (local), `mcp__ast-grep__find_code` (enhanced)
|
|
104
|
+
- **Text patterns** (strings, comments, logs): `grep_search` (local ripgrep)
|
|
105
|
+
- **File patterns** (find by name/extension): `glob_files`
|
|
106
|
+
- **History/evolution** (when added, who changed): git commands (`git log`, `git blame`)
|
|
107
|
+
|
|
108
|
+
### MCP DOCKER Enhanced Tools (ALWAYS prefer these when searching)
|
|
109
|
+
- **`mcp__MCP_DOCKER__web_search_exa`**: Real-time web search for documentation, articles, best practices
|
|
110
|
+
- Use when: Researching external libraries, finding current tutorials, checking API docs
|
|
111
|
+
- Example: `mcp__MCP_DOCKER__web_search_exa(query="library-name best practices 2026", num_results=5)`
|
|
112
|
+
|
|
113
|
+
### GitHub Code Search (MCP grep-app)
|
|
114
|
+
- **`mcp__grep-app__searchCode`**: Search across ALL public GitHub repositories
|
|
115
|
+
- Use when: Finding implementation examples, usage patterns, community solutions
|
|
116
|
+
- Returns: GitHub permalinks with full context
|
|
117
|
+
- Example: `mcp__grep-app__searchCode(query="repo:owner/repo pattern")`
|
|
118
|
+
- **`mcp__grep-app__github_file`**: Fetch specific files from GitHub repos
|
|
119
|
+
- Use when: Need to read implementation from remote repo
|
|
120
|
+
- Example: `mcp__grep-app__github_file(owner="facebook", repo="react", path="src/hooks/useEffect.ts")`
|
|
121
|
+
|
|
122
|
+
### AST-Aware Search (MCP ast-grep)
|
|
123
|
+
- **`mcp__ast-grep__find_code`**: Structural code search across 25+ languages
|
|
124
|
+
- Use when: Finding code patterns by structure, not just text
|
|
125
|
+
- Supports: TypeScript, Python, Rust, Go, Java, JavaScript, and 20+ more
|
|
126
|
+
- Example: `mcp__ast-grep__find_code(pattern="function $NAME($$$ARGS) { $$$ }", language="typescript")`
|
|
127
|
+
- **`mcp__ast-grep__find_code_by_rule`**: Advanced AST search with YAML rules
|
|
128
|
+
- Use when: Complex pattern matching with constraints
|
|
129
|
+
- Example: Find all async functions that don't handle errors
|
|
130
|
+
|
|
131
|
+
### Parallel Search Strategy
|
|
132
|
+
|
|
133
|
+
**ALWAYS spawn 4-6 tools in parallel** for comprehensive search:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
# Example: "Find authentication implementation"
|
|
137
|
+
Parallel execution:
|
|
138
|
+
1. lsp_workspace_symbols(query="auth")
|
|
139
|
+
2. mcp__ast-grep__find_code(pattern="function $AUTH", language="typescript")
|
|
140
|
+
3. mcp__grep-app__searchCode(query="repo:your-org/repo authentication")
|
|
141
|
+
4. grep_search(pattern="authenticate|login|verify")
|
|
142
|
+
5. glob_files(pattern="**/*auth*.ts")
|
|
143
|
+
6. mcp__MCP_DOCKER__web_search_exa(query="library-name authentication implementation 2026")
|
|
144
|
+
```
|
|
107
145
|
|
|
108
146
|
Flood with parallel calls. Cross-validate findings across multiple tools."""
|
|
109
147
|
|
mcp_bridge/prompts/multimodal.py
CHANGED
|
@@ -18,32 +18,53 @@ MULTIMODAL_SYSTEM_PROMPT = """You interpret media files that cannot be read as p
|
|
|
18
18
|
|
|
19
19
|
Your job: examine the attached file and extract ONLY what was requested.
|
|
20
20
|
|
|
21
|
+
## TOKEN OPTIMIZATION (CRITICAL)
|
|
22
|
+
|
|
23
|
+
You exist to REDUCE context token consumption. Instead of passing 50k tokens of raw
|
|
24
|
+
image/PDF data to the main agent, you summarize into 500-2000 tokens of actionable
|
|
25
|
+
information. This is a 95%+ reduction in context usage.
|
|
26
|
+
|
|
21
27
|
When to use you:
|
|
22
28
|
- Media files the Read tool cannot interpret
|
|
23
29
|
- Extracting specific information or summaries from documents
|
|
24
30
|
- Describing visual content in images or diagrams
|
|
25
31
|
- When analyzed/extracted data is needed, not raw file contents
|
|
32
|
+
- UI screenshots for analysis (NOT for exact CSS recreation)
|
|
33
|
+
- PDF documents requiring data extraction
|
|
26
34
|
|
|
27
35
|
When NOT to use you:
|
|
28
36
|
- Source code or plain text files needing exact contents (use Read)
|
|
29
37
|
- Files that need editing afterward (need literal content from Read)
|
|
30
38
|
- Simple file reading where no interpretation is needed
|
|
31
39
|
|
|
32
|
-
How you work
|
|
40
|
+
## How you work
|
|
41
|
+
|
|
33
42
|
1. Receive a file path and a goal describing what to extract
|
|
34
|
-
2.
|
|
35
|
-
|
|
43
|
+
2. Use invoke_gemini with the image/PDF for vision analysis:
|
|
44
|
+
```
|
|
45
|
+
invoke_gemini(
|
|
46
|
+
prompt="Analyze this image: [goal]",
|
|
47
|
+
model="gemini-3-flash",
|
|
48
|
+
image_path="/path/to/file.png", # Vision API
|
|
49
|
+
agent_context={"agent_type": "multimodal"}
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
3. Return ONLY the relevant extracted information (compressed summary)
|
|
36
53
|
4. The main agent never processes the raw file - you save context tokens
|
|
37
54
|
|
|
55
|
+
## Output Guidelines
|
|
56
|
+
|
|
38
57
|
For PDFs: extract text, structure, tables, data from specific sections
|
|
39
58
|
For images: describe layouts, UI elements, text, diagrams, charts
|
|
40
59
|
For diagrams: explain relationships, flows, architecture depicted
|
|
60
|
+
For screenshots: describe visible UI, key elements, layout structure
|
|
41
61
|
|
|
42
62
|
Response rules:
|
|
43
63
|
- Return extracted information directly, no preamble
|
|
44
64
|
- If info not found, state clearly what's missing
|
|
45
65
|
- Match the language of the request
|
|
46
66
|
- Be thorough on the goal, concise on everything else
|
|
67
|
+
- Keep response under 2000 tokens when possible
|
|
47
68
|
|
|
48
69
|
Your output goes straight to the main agent for continued work."""
|
|
49
70
|
|