stravinsky 0.2.7__py3-none-any.whl → 0.2.40__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.
- mcp_bridge/__init__.py +1 -1
- mcp_bridge/auth/cli.py +84 -46
- mcp_bridge/auth/oauth.py +88 -63
- mcp_bridge/hooks/__init__.py +29 -8
- mcp_bridge/hooks/agent_reminder.py +61 -0
- mcp_bridge/hooks/auto_slash_command.py +186 -0
- mcp_bridge/hooks/comment_checker.py +136 -0
- mcp_bridge/hooks/context_monitor.py +58 -0
- mcp_bridge/hooks/empty_message_sanitizer.py +240 -0
- mcp_bridge/hooks/keyword_detector.py +122 -0
- mcp_bridge/hooks/manager.py +27 -8
- mcp_bridge/hooks/preemptive_compaction.py +157 -0
- mcp_bridge/hooks/session_recovery.py +186 -0
- mcp_bridge/hooks/todo_enforcer.py +75 -0
- mcp_bridge/hooks/truncator.py +1 -1
- mcp_bridge/native_hooks/stravinsky_mode.py +109 -0
- mcp_bridge/native_hooks/truncator.py +1 -1
- mcp_bridge/prompts/delphi.py +3 -2
- mcp_bridge/prompts/dewey.py +105 -21
- mcp_bridge/prompts/stravinsky.py +451 -127
- mcp_bridge/server.py +304 -38
- mcp_bridge/server_tools.py +21 -3
- mcp_bridge/tools/__init__.py +2 -1
- mcp_bridge/tools/agent_manager.py +313 -236
- mcp_bridge/tools/init.py +1 -1
- mcp_bridge/tools/model_invoke.py +534 -52
- mcp_bridge/tools/skill_loader.py +51 -47
- mcp_bridge/tools/task_runner.py +74 -30
- mcp_bridge/tools/templates.py +101 -12
- {stravinsky-0.2.7.dist-info → stravinsky-0.2.40.dist-info}/METADATA +6 -12
- stravinsky-0.2.40.dist-info/RECORD +57 -0
- stravinsky-0.2.7.dist-info/RECORD +0 -47
- {stravinsky-0.2.7.dist-info → stravinsky-0.2.40.dist-info}/WHEEL +0 -0
- {stravinsky-0.2.7.dist-info → stravinsky-0.2.40.dist-info}/entry_points.txt +0 -0
mcp_bridge/tools/skill_loader.py
CHANGED
|
@@ -17,21 +17,21 @@ from typing import Any
|
|
|
17
17
|
def parse_frontmatter(content: str) -> tuple[dict[str, Any], str]:
|
|
18
18
|
"""
|
|
19
19
|
Parse YAML frontmatter from markdown content.
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
Returns:
|
|
22
22
|
Tuple of (metadata dict, body content)
|
|
23
23
|
"""
|
|
24
24
|
if not content.startswith("---"):
|
|
25
25
|
return {}, content
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
# Find the closing ---
|
|
28
28
|
end_match = content.find("---", 3)
|
|
29
29
|
if end_match == -1:
|
|
30
30
|
return {}, content
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
frontmatter = content[3:end_match].strip()
|
|
33
|
-
body = content[end_match + 3:].strip()
|
|
34
|
-
|
|
33
|
+
body = content[end_match + 3 :].strip()
|
|
34
|
+
|
|
35
35
|
# Simple YAML parsing for key: value pairs
|
|
36
36
|
metadata = {}
|
|
37
37
|
for line in frontmatter.split("\n"):
|
|
@@ -40,122 +40,126 @@ def parse_frontmatter(content: str) -> tuple[dict[str, Any], str]:
|
|
|
40
40
|
key = key.strip()
|
|
41
41
|
value = value.strip().strip('"').strip("'")
|
|
42
42
|
metadata[key] = value
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
return metadata, body
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def discover_skills(project_path: str | None = None) -> list[dict[str, Any]]:
|
|
48
48
|
"""
|
|
49
49
|
Discover available skills/commands.
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
Searches:
|
|
52
52
|
1. Project-local: {project}/.claude/commands/
|
|
53
53
|
2. User-global: ~/.claude/commands/
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
Args:
|
|
56
56
|
project_path: Project directory to search (defaults to cwd)
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
Returns:
|
|
59
59
|
List of skill definitions.
|
|
60
60
|
"""
|
|
61
61
|
skills = []
|
|
62
62
|
search_paths = []
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
# Project-local commands
|
|
65
65
|
project = Path(project_path) if project_path else Path.cwd()
|
|
66
66
|
project_commands = project / ".claude" / "commands"
|
|
67
67
|
if project_commands.exists():
|
|
68
68
|
search_paths.append(("project", project_commands))
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
# User-global commands
|
|
71
71
|
user_commands = Path.home() / ".claude" / "commands"
|
|
72
72
|
if user_commands.exists():
|
|
73
73
|
search_paths.append(("user", user_commands))
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
for scope, commands_dir in search_paths:
|
|
76
|
-
for md_file in commands_dir.glob("
|
|
76
|
+
for md_file in commands_dir.glob("**/*.md"):
|
|
77
77
|
try:
|
|
78
78
|
content = md_file.read_text()
|
|
79
79
|
metadata, body = parse_frontmatter(content)
|
|
80
|
-
|
|
81
|
-
skills.append(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
|
|
81
|
+
skills.append(
|
|
82
|
+
{
|
|
83
|
+
"name": md_file.stem,
|
|
84
|
+
"scope": scope,
|
|
85
|
+
"path": str(md_file),
|
|
86
|
+
"description": metadata.get("description", ""),
|
|
87
|
+
"allowed_tools": metadata.get("allowed-tools", "").split(",")
|
|
88
|
+
if metadata.get("allowed-tools")
|
|
89
|
+
else [],
|
|
90
|
+
"body_preview": body[:200] + "..." if len(body) > 200 else body,
|
|
91
|
+
}
|
|
92
|
+
)
|
|
89
93
|
except Exception:
|
|
90
94
|
continue
|
|
91
|
-
|
|
95
|
+
|
|
92
96
|
return skills
|
|
93
97
|
|
|
94
98
|
|
|
95
99
|
def list_skills(project_path: str | None = None) -> str:
|
|
96
100
|
"""
|
|
97
101
|
List all available skills for MCP tool.
|
|
98
|
-
|
|
102
|
+
|
|
99
103
|
Args:
|
|
100
104
|
project_path: Project directory to search
|
|
101
|
-
|
|
105
|
+
|
|
102
106
|
Returns:
|
|
103
107
|
Formatted skill listing.
|
|
104
108
|
"""
|
|
105
109
|
skills = discover_skills(project_path)
|
|
106
|
-
|
|
110
|
+
|
|
107
111
|
if not skills:
|
|
108
112
|
return "No skills found. Create .claude/commands/*.md files to add skills."
|
|
109
|
-
|
|
113
|
+
|
|
110
114
|
lines = [f"Found {len(skills)} skill(s):\n"]
|
|
111
|
-
|
|
115
|
+
|
|
112
116
|
for skill in skills:
|
|
113
117
|
scope_badge = "[project]" if skill["scope"] == "project" else "[user]"
|
|
114
118
|
lines.append(f" /{skill['name']} {scope_badge}")
|
|
115
119
|
if skill["description"]:
|
|
116
120
|
lines.append(f" {skill['description']}")
|
|
117
|
-
|
|
121
|
+
|
|
118
122
|
return "\n".join(lines)
|
|
119
123
|
|
|
120
124
|
|
|
121
125
|
def get_skill(name: str, project_path: str | None = None) -> str:
|
|
122
126
|
"""
|
|
123
127
|
Get the content of a specific skill.
|
|
124
|
-
|
|
128
|
+
|
|
125
129
|
Args:
|
|
126
130
|
name: Skill name (filename without .md)
|
|
127
131
|
project_path: Project directory to search
|
|
128
|
-
|
|
132
|
+
|
|
129
133
|
Returns:
|
|
130
134
|
Skill content or error message.
|
|
131
135
|
"""
|
|
132
136
|
skills = discover_skills(project_path)
|
|
133
|
-
|
|
137
|
+
|
|
134
138
|
skill = next((s for s in skills if s["name"] == name), None)
|
|
135
139
|
if not skill:
|
|
136
140
|
available = ", ".join(s["name"] for s in skills)
|
|
137
141
|
return f"Skill '{name}' not found. Available: {available or 'none'}"
|
|
138
|
-
|
|
142
|
+
|
|
139
143
|
try:
|
|
140
144
|
content = Path(skill["path"]).read_text()
|
|
141
145
|
metadata, body = parse_frontmatter(content)
|
|
142
|
-
|
|
146
|
+
|
|
143
147
|
lines = [
|
|
144
148
|
f"## Skill: {name}",
|
|
145
149
|
f"**Scope**: {skill['scope']}",
|
|
146
150
|
f"**Path**: {skill['path']}",
|
|
147
151
|
]
|
|
148
|
-
|
|
152
|
+
|
|
149
153
|
if metadata.get("description"):
|
|
150
154
|
lines.append(f"**Description**: {metadata['description']}")
|
|
151
|
-
|
|
155
|
+
|
|
152
156
|
if metadata.get("allowed-tools"):
|
|
153
157
|
lines.append(f"**Allowed Tools**: {metadata['allowed-tools']}")
|
|
154
|
-
|
|
158
|
+
|
|
155
159
|
lines.extend(["", "---", "", body])
|
|
156
|
-
|
|
160
|
+
|
|
157
161
|
return "\n".join(lines)
|
|
158
|
-
|
|
162
|
+
|
|
159
163
|
except Exception as e:
|
|
160
164
|
return f"Error reading skill: {e}"
|
|
161
165
|
|
|
@@ -169,34 +173,34 @@ def create_skill(
|
|
|
169
173
|
) -> str:
|
|
170
174
|
"""
|
|
171
175
|
Create a new skill file.
|
|
172
|
-
|
|
176
|
+
|
|
173
177
|
Args:
|
|
174
178
|
name: Skill name (will be used as filename)
|
|
175
179
|
description: Short description for frontmatter
|
|
176
180
|
content: Skill body content
|
|
177
181
|
scope: "project" or "user"
|
|
178
182
|
project_path: Project directory for project-scope skills
|
|
179
|
-
|
|
183
|
+
|
|
180
184
|
Returns:
|
|
181
185
|
Success or error message.
|
|
182
186
|
"""
|
|
183
187
|
# Sanitize name
|
|
184
188
|
name = re.sub(r"[^a-zA-Z0-9_-]", "-", name.lower())
|
|
185
|
-
|
|
189
|
+
|
|
186
190
|
if scope == "project":
|
|
187
191
|
base_dir = Path(project_path) if project_path else Path.cwd()
|
|
188
192
|
commands_dir = base_dir / ".claude" / "commands"
|
|
189
193
|
else:
|
|
190
194
|
commands_dir = Path.home() / ".claude" / "commands"
|
|
191
|
-
|
|
195
|
+
|
|
192
196
|
# Ensure directory exists
|
|
193
197
|
commands_dir.mkdir(parents=True, exist_ok=True)
|
|
194
|
-
|
|
198
|
+
|
|
195
199
|
skill_path = commands_dir / f"{name}.md"
|
|
196
|
-
|
|
200
|
+
|
|
197
201
|
if skill_path.exists():
|
|
198
202
|
return f"Skill '{name}' already exists at {skill_path}"
|
|
199
|
-
|
|
203
|
+
|
|
200
204
|
# Create skill content
|
|
201
205
|
skill_content = f"""---
|
|
202
206
|
description: {description}
|
|
@@ -204,7 +208,7 @@ description: {description}
|
|
|
204
208
|
|
|
205
209
|
{content}
|
|
206
210
|
"""
|
|
207
|
-
|
|
211
|
+
|
|
208
212
|
try:
|
|
209
213
|
skill_path.write_text(skill_content)
|
|
210
214
|
return f"Created skill '{name}' at {skill_path}"
|
mcp_bridge/tools/task_runner.py
CHANGED
|
@@ -11,18 +11,20 @@ import logging
|
|
|
11
11
|
import os
|
|
12
12
|
import sys
|
|
13
13
|
import asyncio
|
|
14
|
+
import subprocess
|
|
14
15
|
from datetime import datetime
|
|
15
16
|
from pathlib import Path
|
|
16
17
|
|
|
17
18
|
# Setup logging
|
|
18
|
-
logging.basicConfig(level=logging.INFO, format=
|
|
19
|
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
|
19
20
|
logger = logging.getLogger("task_runner")
|
|
20
21
|
|
|
22
|
+
|
|
21
23
|
async def run_task(task_id: str, base_dir: str):
|
|
22
24
|
base_path = Path(base_dir)
|
|
23
25
|
tasks_file = base_path / "tasks.json"
|
|
24
26
|
agents_dir = base_path / "agents"
|
|
25
|
-
|
|
27
|
+
|
|
26
28
|
# Load task details
|
|
27
29
|
try:
|
|
28
30
|
with open(tasks_file, "r") as f:
|
|
@@ -38,60 +40,102 @@ async def run_task(task_id: str, base_dir: str):
|
|
|
38
40
|
|
|
39
41
|
prompt = task.get("prompt")
|
|
40
42
|
model = task.get("model", "gemini-2.0-flash")
|
|
41
|
-
|
|
43
|
+
|
|
42
44
|
output_file = agents_dir / f"{task_id}.out"
|
|
43
45
|
agents_dir.mkdir(parents=True, exist_ok=True)
|
|
44
46
|
|
|
45
47
|
try:
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
# Use Claude CLI for background tasks to ensure tool access
|
|
49
|
+
# Discover CLI path
|
|
50
|
+
claude_cli = os.environ.get("CLAUDE_CLI", "/opt/homebrew/bin/claude")
|
|
51
|
+
|
|
52
|
+
cmd = [
|
|
53
|
+
claude_cli,
|
|
54
|
+
"-p",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
if model:
|
|
58
|
+
cmd.extend(["--model", model])
|
|
59
|
+
|
|
60
|
+
cmd.append(prompt)
|
|
61
|
+
|
|
62
|
+
logger.info(f"Executing task {task_id} via CLI ({model})...")
|
|
63
|
+
|
|
64
|
+
# Open output and log files
|
|
65
|
+
with (
|
|
66
|
+
open(output_file, "w") as out_f,
|
|
67
|
+
open(base_path / "tasks" / f"{task_id}.log", "a") as log_f,
|
|
68
|
+
):
|
|
69
|
+
process = await asyncio.create_subprocess_exec(
|
|
70
|
+
*cmd, stdout=out_f, stderr=log_f, cwd=os.getcwd()
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
await process.wait()
|
|
74
|
+
|
|
75
|
+
# Read result
|
|
76
|
+
if output_file.exists():
|
|
77
|
+
result = output_file.read_text()
|
|
78
|
+
else:
|
|
79
|
+
result = ""
|
|
80
|
+
|
|
54
81
|
# Save result
|
|
55
82
|
with open(output_file, "w") as f:
|
|
56
83
|
f.write(result)
|
|
57
|
-
|
|
84
|
+
|
|
58
85
|
# Update status
|
|
59
86
|
with open(tasks_file, "r") as f:
|
|
60
87
|
tasks = json.load(f)
|
|
61
|
-
|
|
88
|
+
|
|
62
89
|
if task_id in tasks:
|
|
63
|
-
tasks[task_id].update(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
90
|
+
tasks[task_id].update(
|
|
91
|
+
{
|
|
92
|
+
"status": "completed",
|
|
93
|
+
"result": result,
|
|
94
|
+
"completed_at": datetime.now().isoformat(),
|
|
95
|
+
}
|
|
96
|
+
)
|
|
68
97
|
with open(tasks_file, "w") as f:
|
|
69
98
|
json.dump(tasks, f, indent=2)
|
|
70
|
-
|
|
99
|
+
|
|
71
100
|
logger.info(f"Task {task_id} completed successfully")
|
|
72
|
-
|
|
101
|
+
|
|
73
102
|
except Exception as e:
|
|
74
103
|
logger.exception(f"Task {task_id} failed: {e}")
|
|
75
|
-
|
|
104
|
+
|
|
76
105
|
# Update status with error
|
|
77
106
|
try:
|
|
78
107
|
with open(tasks_file, "r") as f:
|
|
79
108
|
tasks = json.load(f)
|
|
80
109
|
if task_id in tasks:
|
|
81
|
-
tasks[task_id].update(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
110
|
+
tasks[task_id].update(
|
|
111
|
+
{
|
|
112
|
+
"status": "failed",
|
|
113
|
+
"error": str(e),
|
|
114
|
+
"completed_at": datetime.now().isoformat(),
|
|
115
|
+
}
|
|
116
|
+
)
|
|
86
117
|
with open(tasks_file, "w") as f:
|
|
87
118
|
json.dump(tasks, f, indent=2)
|
|
88
119
|
except:
|
|
89
120
|
pass
|
|
90
121
|
|
|
122
|
+
|
|
91
123
|
if __name__ == "__main__":
|
|
92
|
-
parser = argparse.ArgumentParser(
|
|
93
|
-
|
|
94
|
-
|
|
124
|
+
parser = argparse.ArgumentParser(
|
|
125
|
+
description="Internal task runner for Stravinsky background agents. "
|
|
126
|
+
"Executes agent tasks via Claude CLI and manages output/status.",
|
|
127
|
+
prog="task_runner",
|
|
128
|
+
)
|
|
129
|
+
parser.add_argument(
|
|
130
|
+
"--task-id",
|
|
131
|
+
required=True,
|
|
132
|
+
help="Unique identifier for the task to execute",
|
|
133
|
+
)
|
|
134
|
+
parser.add_argument(
|
|
135
|
+
"--base-dir",
|
|
136
|
+
required=True,
|
|
137
|
+
help="Base directory containing tasks.json and agents/ output folder",
|
|
138
|
+
)
|
|
95
139
|
args = parser.parse_args()
|
|
96
|
-
|
|
140
|
+
|
|
97
141
|
asyncio.run(run_task(args.task_id, args.base_dir))
|
mcp_bridge/tools/templates.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Templates for
|
|
2
|
+
Templates for stravinsky repository initialization.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
CLAUDE_MD_TEMPLATE = """##
|
|
5
|
+
CLAUDE_MD_TEMPLATE = """## stravinsky MCP (Parallel Agents)
|
|
6
6
|
|
|
7
|
-
Use
|
|
7
|
+
Use stravinsky MCP tools. **DEFAULT: spawn parallel agents for multi-step tasks.**
|
|
8
8
|
|
|
9
9
|
### Agent Tools
|
|
10
10
|
- `agent_spawn(prompt, agent_type, description)` - Spawn background agent with full tool access
|
|
@@ -13,30 +13,90 @@ Use Stravinsky MCP tools. **DEFAULT: spawn parallel agents for multi-step tasks.
|
|
|
13
13
|
- `agent_list()` - Overview of all running agents
|
|
14
14
|
- `agent_cancel(task_id)` - Stop a running agent
|
|
15
15
|
|
|
16
|
-
###
|
|
16
|
+
### Agent Types
|
|
17
|
+
- `explore` - Codebase search, "where is X?" questions
|
|
18
|
+
- `dewey` - Documentation research, implementation examples
|
|
19
|
+
- `frontend` - UI/UX work, component design
|
|
20
|
+
- `delphi` - Strategic advice, architecture review
|
|
21
|
+
|
|
22
|
+
### Parallel Execution (IRONSTAR)
|
|
17
23
|
For ANY task with 2+ independent steps:
|
|
18
24
|
1. **Immediately use agent_spawn** for each independent component
|
|
19
25
|
2. Fire all agents simultaneously, don't wait
|
|
20
26
|
3. Monitor with agent_progress, collect with agent_output
|
|
21
27
|
|
|
22
28
|
### Trigger Commands
|
|
23
|
-
- **
|
|
29
|
+
- **IRONSTAR** / **IRS**: Maximum parallel execution - spawn agents aggressively for every subtask
|
|
24
30
|
- **ULTRATHINK**: Engage exhaustive deep reasoning, multi-dimensional analysis
|
|
31
|
+
- **SEARCH**: Maximize search effort across codebase and external resources
|
|
32
|
+
- **ANALYZE**: Deep analysis mode with delphi consultation for complex issues
|
|
25
33
|
"""
|
|
26
34
|
|
|
27
|
-
# Slash Commands
|
|
28
35
|
COMMAND_STRAVINSKY = """---
|
|
29
|
-
description:
|
|
36
|
+
description: stravinsky Orchestrator - Parallel agent execution for complex workflows.
|
|
30
37
|
---
|
|
31
38
|
|
|
32
|
-
|
|
39
|
+
## CRITICAL: USE STRAVINSKY MCP TOOLS
|
|
40
|
+
|
|
41
|
+
You MUST use the Stravinsky MCP server tools for ALL file reading, searching, and parallel work.
|
|
42
|
+
|
|
43
|
+
### MANDATORY TOOL USAGE:
|
|
44
|
+
|
|
45
|
+
**For ANY file reading or searching:**
|
|
46
|
+
```
|
|
47
|
+
stravinsky:agent_spawn(
|
|
48
|
+
prompt="Read and analyze [file path]. Return: [what you need]",
|
|
49
|
+
agent_type="explore",
|
|
50
|
+
description="Read [file]"
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**For documentation/library research:**
|
|
55
|
+
```
|
|
56
|
+
stravinsky:agent_spawn(
|
|
57
|
+
prompt="Find documentation for [topic]",
|
|
58
|
+
agent_type="dewey",
|
|
59
|
+
description="Research [topic]"
|
|
60
|
+
)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**For 2+ independent tasks (ALWAYS parallel):**
|
|
64
|
+
```
|
|
65
|
+
// Fire ALL at once in ONE response - NEVER sequential
|
|
66
|
+
stravinsky:agent_spawn(prompt="Task 1...", agent_type="explore", description="Task 1")
|
|
67
|
+
stravinsky:agent_spawn(prompt="Task 2...", agent_type="explore", description="Task 2")
|
|
68
|
+
stravinsky:agent_spawn(prompt="Task 3...", agent_type="dewey", description="Task 3")
|
|
69
|
+
// Then immediately continue - don't wait
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**To get results:**
|
|
73
|
+
```
|
|
74
|
+
stravinsky:agent_output(task_id="[id]", block=true)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### DO NOT USE:
|
|
78
|
+
- ❌ Built-in Read tool for file reading
|
|
79
|
+
- ❌ Built-in Search/Glob for searching
|
|
80
|
+
- ❌ Built-in Task tool for subagents
|
|
81
|
+
|
|
82
|
+
### ALWAYS USE:
|
|
83
|
+
- ✅ stravinsky:agent_spawn for ALL exploration
|
|
84
|
+
- ✅ stravinsky:agent_output for collecting results
|
|
85
|
+
- ✅ stravinsky:agent_list to see running agents
|
|
86
|
+
|
|
87
|
+
### Execution Modes:
|
|
88
|
+
- `ironstar` / `irs` / `ultrawork` - Maximum parallel execution (10+ agents)
|
|
89
|
+
- `ultrathink` - Deep reasoning with delphi consultation
|
|
90
|
+
- `search` - Exhaustive multi-agent search
|
|
91
|
+
|
|
92
|
+
**Your FIRST action must be spawning agents, not using Read/Search tools.**
|
|
33
93
|
"""
|
|
34
94
|
|
|
35
95
|
COMMAND_PARALLEL = """---
|
|
36
96
|
description: Execute a task with multiple parallel agents for speed.
|
|
37
97
|
---
|
|
38
98
|
|
|
39
|
-
Use the
|
|
99
|
+
Use the stravinsky MCP tools to execute this task with PARALLEL AGENTS.
|
|
40
100
|
|
|
41
101
|
**MANDATORY:** For the following task items, spawn a SEPARATE `agent_spawn` call for EACH independent item. Do not work on them sequentially - fire all agents simultaneously:
|
|
42
102
|
|
|
@@ -63,24 +123,53 @@ Call the `get_system_health` tool to verify that all CLI dependencies (rg, fd, s
|
|
|
63
123
|
"""
|
|
64
124
|
|
|
65
125
|
COMMAND_DELPHI = """---
|
|
66
|
-
description: Consult the
|
|
126
|
+
description: Consult the delphi Strategic Advisor for architecture and hard debugging.
|
|
67
127
|
---
|
|
68
128
|
|
|
69
129
|
Use the `delphi` prompt to analyze the current problem. This triggers a GPT-based consulting phase focused on strategic reasoning, architectural trade-offs, and root-cause analysis for difficult bugs.
|
|
130
|
+
|
|
131
|
+
**When to use delphi:**
|
|
132
|
+
- Complex architecture design decisions
|
|
133
|
+
- After 2+ failed fix attempts
|
|
134
|
+
- Multi-system tradeoffs
|
|
135
|
+
- Security/performance concerns
|
|
136
|
+
- Unfamiliar code patterns
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
COMMAND_LIST = """---
|
|
140
|
+
description: List all active and recent background agent tasks.
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
Call the `agent_list` tool to see an overview of all currently running and completed background agents, including their Task IDs and statuses.
|
|
70
144
|
"""
|
|
71
145
|
|
|
72
146
|
COMMAND_DEWEY = """---
|
|
73
|
-
description: Trigger
|
|
147
|
+
description: Trigger dewey for documentation research and implementation examples.
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
Use the `dewey` prompt to find evidence and documentation for the topic at hand. dewey specializes in multi-repository search and official documentation retrieval.
|
|
151
|
+
|
|
152
|
+
**When to use dewey:**
|
|
153
|
+
- Unfamiliar npm/pip/cargo packages
|
|
154
|
+
- "How do I use [library]?"
|
|
155
|
+
- "What's the best practice for [framework feature]?"
|
|
156
|
+
- Finding OSS implementation examples
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
COMMAND_VERSION = """---
|
|
160
|
+
description: Returns the current version and diagnostic info for stravinsky.
|
|
74
161
|
---
|
|
75
162
|
|
|
76
|
-
|
|
163
|
+
Display the stravinsky MCP version, registered hooks, available agents, and system health status.
|
|
77
164
|
"""
|
|
78
165
|
|
|
79
166
|
SLASH_COMMANDS = {
|
|
80
167
|
"stravinsky.md": COMMAND_STRAVINSKY,
|
|
81
168
|
"parallel.md": COMMAND_PARALLEL,
|
|
169
|
+
"list.md": COMMAND_LIST,
|
|
82
170
|
"context.md": COMMAND_CONTEXT,
|
|
83
171
|
"health.md": COMMAND_HEALTH,
|
|
84
172
|
"delphi.md": COMMAND_DELPHI,
|
|
85
173
|
"dewey.md": COMMAND_DEWEY,
|
|
174
|
+
"version.md": COMMAND_VERSION,
|
|
86
175
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stravinsky
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.40
|
|
4
4
|
Summary: MCP Bridge for Claude Code with Multi-Model Support. Install globally: claude mcp add --scope user stravinsky -- uvx stravinsky. Add to CLAUDE.md: See https://pypi.org/project/stravinsky/
|
|
5
5
|
Project-URL: Repository, https://github.com/GratefulDave/stravinsky
|
|
6
6
|
Project-URL: Issues, https://github.com/GratefulDave/stravinsky/issues
|
|
@@ -90,19 +90,13 @@ stravinsky-auth status
|
|
|
90
90
|
# Logout
|
|
91
91
|
stravinsky-auth logout gemini
|
|
92
92
|
|
|
93
|
-
###
|
|
93
|
+
### Slash Commands
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
Slash commands are discovered from:
|
|
96
|
+
- Project-local: `.claude/commands/**/*.md` (recursive)
|
|
97
|
+
- User-global: `~/.claude/commands/**/*.md` (recursive)
|
|
96
98
|
|
|
97
|
-
|
|
98
|
-
# In the root of your project:
|
|
99
|
-
stravinsky-auth init
|
|
100
|
-
````
|
|
101
|
-
|
|
102
|
-
This will:
|
|
103
|
-
|
|
104
|
-
1. Create/Update `CLAUDE.md` with Stravinsky parallel execution rules.
|
|
105
|
-
2. Install standard slash commands into `.claude/commands/stra/`.
|
|
99
|
+
Commands can be organized in subdirectories (e.g., `.claude/commands/strav/stravinsky.md`).
|
|
106
100
|
|
|
107
101
|
````
|
|
108
102
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
mcp_bridge/__init__.py,sha256=TZEL7NbFvxLaphGOCsAqfJrHhPB2LHR2ab0Eb5xxaU0,23
|
|
2
|
+
mcp_bridge/server.py,sha256=2GuvJdCMxoMYLAbQtsPUrFyF0dTBgvjs8pBx-uF2Vbg,23035
|
|
3
|
+
mcp_bridge/server_tools.py,sha256=1eweAvO4f0OolXajHFvJYbTkXdxsCLcr9JWxu7MbCpk,23386
|
|
4
|
+
mcp_bridge/auth/__init__.py,sha256=AGHNtKzqvZYMLQ35Qg6aOabpxBqmkR-pjXv8Iby9oMw,797
|
|
5
|
+
mcp_bridge/auth/cli.py,sha256=jaXyrzq6HwnW61g6CHHcj8bF5PJLYrYufD_jmN0jeiQ,8502
|
|
6
|
+
mcp_bridge/auth/oauth.py,sha256=gWYk3KJWbUM1J5AKVDJ_4k4zdQzwwaYJZ5J25If0r8c,12804
|
|
7
|
+
mcp_bridge/auth/openai_oauth.py,sha256=0Ks2X-NXLCBzqs3xnbj9QLZpugICOX5qB5y5vtDENOo,11522
|
|
8
|
+
mcp_bridge/auth/token_store.py,sha256=3A6TZJ7Wju6QfhALeX4IMhY5jzb9OWMrDzwRbfAukiU,5650
|
|
9
|
+
mcp_bridge/config/__init__.py,sha256=uapHdrSWWrafVKD9CTB1J_7Dw0_RajRhoDGjy9zH21o,256
|
|
10
|
+
mcp_bridge/config/hooks.py,sha256=WvWC6ZUc8y1IXPlGCjLYAAsGGigd5tWeGiw585OGNwA,4624
|
|
11
|
+
mcp_bridge/hooks/__init__.py,sha256=QYE1-NXnC_2x-N1Y9XL8BwI_6q38PniH5KJ2Pj7xcvc,2068
|
|
12
|
+
mcp_bridge/hooks/agent_reminder.py,sha256=OxKPxi7e2MIBm44Ebzzl9j9fDV5bBgogGF0lj7wun5s,1913
|
|
13
|
+
mcp_bridge/hooks/auto_slash_command.py,sha256=LUndZHxUzEF7PQuOdp3v7VfqNUgsiDE2gzI_TkR9he4,5280
|
|
14
|
+
mcp_bridge/hooks/budget_optimizer.py,sha256=Im0qSGVUdRByk04hP5VyKt7tjlDVYG0LJb6IeUjjnj8,1323
|
|
15
|
+
mcp_bridge/hooks/comment_checker.py,sha256=MslXZYiHjfxjUU7VzmZfa1n2WR9o4lnaktJ6eUPBUDs,3772
|
|
16
|
+
mcp_bridge/hooks/compaction.py,sha256=UXTwmyo9C4Jm3j72KvVU11ukSAHaGaTey_h3L43e3rY,1186
|
|
17
|
+
mcp_bridge/hooks/context_monitor.py,sha256=IEr75e_gqbPEUslxxfkwftiy6alDmJxQhSB6cy8BVg4,1885
|
|
18
|
+
mcp_bridge/hooks/directory_context.py,sha256=0VjdJITJIGUqR4-q-wZlB6kmkFQMraaFvU2Nz2PnJCM,1225
|
|
19
|
+
mcp_bridge/hooks/edit_recovery.py,sha256=CyhdFF3rV-sqZ13Mn8I8I5oMqB2KLIl6Bziv7GcsX0o,1749
|
|
20
|
+
mcp_bridge/hooks/empty_message_sanitizer.py,sha256=iZZnETju1wBvJXV1k4msV8FxLNg5LkVm2eaFA2nQWxI,6606
|
|
21
|
+
mcp_bridge/hooks/keyword_detector.py,sha256=5kztrsQ2NtT5qdDTC-J49nxPB_D0tIjT1AVAAry4FPE,4866
|
|
22
|
+
mcp_bridge/hooks/manager.py,sha256=qqB-j-LN1dMQe4n1IpRBbgBkzAym94Jv9LK43n47OIs,3521
|
|
23
|
+
mcp_bridge/hooks/preemptive_compaction.py,sha256=DY0O8ALOAQPT00QzpB1KBxX2AqzpnynQyXWXtDHBr4o,5530
|
|
24
|
+
mcp_bridge/hooks/session_recovery.py,sha256=c5eoIWJAgMTPY0wq_64MmCUNLCB_GSowZlA3lo4R9LU,6260
|
|
25
|
+
mcp_bridge/hooks/todo_enforcer.py,sha256=LRvVxYILqQ6YuQl3tky4hgyD-irXIPDE5e0EdKr6jcc,2274
|
|
26
|
+
mcp_bridge/hooks/truncator.py,sha256=Rse93FS2aJxJGUOJIGY_ZYAS4yIUQBpBlVFo-IYbbKE,598
|
|
27
|
+
mcp_bridge/native_hooks/context.py,sha256=JBHqnX75qtMO3JAEFooBEAK6DxcsVaXykhrP7tdFm6E,949
|
|
28
|
+
mcp_bridge/native_hooks/edit_recovery.py,sha256=1OWpb3v87txFUsgnNe1hoeTI7rIKCkKYONld5BK1TyA,1503
|
|
29
|
+
mcp_bridge/native_hooks/stravinsky_mode.py,sha256=UCiBk4YtGX6ubKTXYyGZUBIQG_CuFlHKPW-8S494BqU,2856
|
|
30
|
+
mcp_bridge/native_hooks/truncator.py,sha256=h3hb8sZXTvc59C0-5GdZwCVZHlxBKdo47JT9TMxHG3g,530
|
|
31
|
+
mcp_bridge/prompts/__init__.py,sha256=pQmPxbdfS_S-ENB-VX33MXbgfGs8zHfLB_QOBtaPjis,322
|
|
32
|
+
mcp_bridge/prompts/delphi.py,sha256=ZlnLY2o1PrK3CxLLaCkozAGPIAJ5OFmw5u8o6-LXmgI,4960
|
|
33
|
+
mcp_bridge/prompts/dewey.py,sha256=kSuYiSB1ab0xddvIRVrq7czXMkZJOgu9wXSH-Zw49Ag,8023
|
|
34
|
+
mcp_bridge/prompts/document_writer.py,sha256=hiCbxgTU8HKPJkS0eNpPPtzSqDXPreApU2OqiS6zh-0,5618
|
|
35
|
+
mcp_bridge/prompts/explore.py,sha256=121R3bNFbb7AIte69eDtLfxdyHdOo3l16L6cUH1p-kk,3592
|
|
36
|
+
mcp_bridge/prompts/frontend.py,sha256=j91I8k5vcVed13eeX-Ebiv49x9Qj4HO_SQN1xhB8TLQ,4943
|
|
37
|
+
mcp_bridge/prompts/multimodal.py,sha256=Svw11N392LjshalasOd80X0Qw_qtOMqu_lD-_HmQDIo,1936
|
|
38
|
+
mcp_bridge/prompts/stravinsky.py,sha256=_ar9w9ZJkYKu73cW0YUrqqz7EAfsPX98SH8AiPQIcsg,24793
|
|
39
|
+
mcp_bridge/tools/__init__.py,sha256=SRnMaUni0BhlvCABBEYeyveNiOAMQPNBXmjUKG6aXQA,1150
|
|
40
|
+
mcp_bridge/tools/agent_manager.py,sha256=OiKEpG-wBEVySD-ulmKkrLzEVXYfal-0Dtllp5agb40,28233
|
|
41
|
+
mcp_bridge/tools/background_tasks.py,sha256=G1iQ00538q939-DJbzaEsA0uZI2TfwzawFCDx8QC5Hg,5178
|
|
42
|
+
mcp_bridge/tools/code_search.py,sha256=sR-alLQuxaXUFB9hby_wQsQu3Io644wdnpdOM_vm0aw,9978
|
|
43
|
+
mcp_bridge/tools/continuous_loop.py,sha256=MM3FnF3ULuR32h0tqJP8uF48iJg6R9dbyHy_36KLOls,2100
|
|
44
|
+
mcp_bridge/tools/init.py,sha256=sU95M9M_tjsfuew389TrFrxxeCavuSC16qbkydk_6PU,1586
|
|
45
|
+
mcp_bridge/tools/model_invoke.py,sha256=m04A5dDmn0prO3Bi46YNXdqZlegQDwCYl2EagEI44hY,26161
|
|
46
|
+
mcp_bridge/tools/project_context.py,sha256=bXKxuW1pGjtIbeNjMgpBoQL-d_CI94UPBVpRjUyhX20,4707
|
|
47
|
+
mcp_bridge/tools/session_manager.py,sha256=tCVLLvO-Kttla7OxPImb_NSGL_9aW46ilq5ej_IcnlA,9252
|
|
48
|
+
mcp_bridge/tools/skill_loader.py,sha256=RQ5eC357pm-6q85G3EyrQugz0S3OO5lxWtM9n9ECF-c,6010
|
|
49
|
+
mcp_bridge/tools/task_runner.py,sha256=xjE3MXv62gcUCwOEwHjAGL_Ud_ZlKFBN0UHpvFjj3uk,3918
|
|
50
|
+
mcp_bridge/tools/templates.py,sha256=A7eFk08Y2TZ2FPnsYLkVYCGOm1dd8scpNfcjCl_vC24,5928
|
|
51
|
+
mcp_bridge/tools/lsp/__init__.py,sha256=fLiII9qgeachI3MlkO6uGulfUH3T0YDeyEfO65bbxdw,549
|
|
52
|
+
mcp_bridge/tools/lsp/tools.py,sha256=nfXT3LBD5Mas_98f1zwu62jkpInGXUR-1vLl1zIykUw,16315
|
|
53
|
+
mcp_bridge/utils/__init__.py,sha256=pbHV4nq5SLUYcAyTmLUZYrp293Ctud57X8hwsMGA_BM,20
|
|
54
|
+
stravinsky-0.2.40.dist-info/METADATA,sha256=dtiavtqJ4fboG8mRZIxMOrTGPI_7wKFar_Muuq-qy7Y,7091
|
|
55
|
+
stravinsky-0.2.40.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
56
|
+
stravinsky-0.2.40.dist-info/entry_points.txt,sha256=BISwF7i71Oen7jFVmBXz8fxiU11Cp415wPF0xXG2Q3s,97
|
|
57
|
+
stravinsky-0.2.40.dist-info/RECORD,,
|