stravinsky 0.4.41__tar.gz → 0.4.42__tar.gz
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.
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/tool_messaging.py +7 -0
- stravinsky-0.4.42/.claude/task_dependencies.json +39 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/PKG-INFO +1 -1
- stravinsky-0.4.42/mcp_bridge/__init__.py +1 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/server.py +35 -20
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/server_tools.py +27 -3
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/agent_manager.py +121 -4
- {stravinsky-0.4.41 → stravinsky-0.4.42}/pyproject.toml +1 -1
- stravinsky-0.4.41/.claude/task_dependencies.json +0 -9
- stravinsky-0.4.41/mcp_bridge/__init__.py +0 -1
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/HOOKS_INTEGRATION.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/agents/HOOKS.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/agents/code-reviewer.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/agents/debugger.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/agents/delphi.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/agents/dewey.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/agents/explore.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/agents/frontend.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/agents/implementation-lead.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/agents/research-lead.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/agents/stravinsky.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/delphi.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/dewey.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/git-master.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/index.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/publish.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/review.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/str/cancel.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/str/clean.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/str/index.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/str/list_watchers.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/str/search.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/str/start_filewatch.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/str/stats.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/str/stop_filewatch.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/str/unwatch.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/str/watch.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/strav.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/verify.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/commands/version.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/README.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/comment_checker.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/context.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/context_monitor.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/dependency_tracker.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/edit_recovery.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/execution_state_tracker.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/notification_hook.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/notification_hook_v2.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/parallel_execution.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/parallel_reinforcement.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/parallel_reinforcement_v2.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/pre_compact.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/session_recovery.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/stravinsky_mode.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/subagent_stop.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/todo_continuation.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/todo_delegation.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/hooks/truncator.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/rules/deployment_safety.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/rules/pypi_deployment.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/settings.json +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/skills/chrome-devtools/SKILL.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/skills/sqlite/SKILL.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.claude/skills/supabase/SKILL.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/.gitignore +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/README.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/auth/__init__.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/auth/cli.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/auth/oauth.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/auth/openai_oauth.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/auth/token_refresh.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/auth/token_store.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/cli/__init__.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/cli/install_hooks.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/cli/session_report.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/config/MANIFEST_SCHEMA.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/config/README.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/config/__init__.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/config/hook_config.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/config/hooks.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/config/hooks_manifest.json +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/config/rate_limits.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/config/skills_manifest.json +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/HOOKS_SETTINGS.json +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/README.md +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/__init__.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/agent_reminder.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/auto_slash_command.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/budget_optimizer.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/comment_checker.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/compaction.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/context.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/context_monitor.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/directory_context.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/edit_recovery.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/empty_message_sanitizer.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/git_noninteractive.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/keyword_detector.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/manager.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/notification_hook.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/parallel_enforcer.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/parallel_execution.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/pre_compact.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/preemptive_compaction.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/rules_injector.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/session_idle.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/session_notifier.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/session_recovery.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/stravinsky_mode.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/subagent_stop.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/task_validator.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/tmux_manager.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/todo_continuation.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/todo_delegation.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/todo_enforcer.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/tool_messaging.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/hooks/truncator.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/notifications.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/prompts/__init__.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/prompts/delphi.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/prompts/dewey.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/prompts/document_writer.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/prompts/explore.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/prompts/frontend.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/prompts/multimodal.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/prompts/planner.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/prompts/stravinsky.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/__init__.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/background_tasks.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/code_search.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/continuous_loop.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/init.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/lsp/__init__.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/lsp/manager.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/lsp/tools.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/model_invoke.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/project_context.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/query_classifier.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/semantic_search.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/session_manager.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/skill_loader.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/task_runner.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/tools/templates.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/update_manager.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/update_manager_pypi.py +0 -0
- {stravinsky-0.4.41 → stravinsky-0.4.42}/mcp_bridge/utils/__init__.py +0 -0
|
@@ -216,6 +216,13 @@ def extract_description(tool_name: str, params: dict) -> str:
|
|
|
216
216
|
repo = params.get("repo", "")
|
|
217
217
|
return f"Fetching {path} from {repo}"
|
|
218
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
|
+
|
|
219
226
|
# Task delegation
|
|
220
227
|
if tool_name == "Task":
|
|
221
228
|
subagent_type = params.get("subagent_type", "unknown")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"1": {
|
|
4
|
+
"deps": [],
|
|
5
|
+
"independent": true,
|
|
6
|
+
"parallel_safe": true
|
|
7
|
+
},
|
|
8
|
+
"2": {
|
|
9
|
+
"deps": [],
|
|
10
|
+
"independent": true,
|
|
11
|
+
"parallel_safe": true
|
|
12
|
+
},
|
|
13
|
+
"3": {
|
|
14
|
+
"deps": [],
|
|
15
|
+
"independent": false,
|
|
16
|
+
"parallel_safe": false
|
|
17
|
+
},
|
|
18
|
+
"4": {
|
|
19
|
+
"deps": [],
|
|
20
|
+
"independent": true,
|
|
21
|
+
"parallel_safe": true
|
|
22
|
+
},
|
|
23
|
+
"5": {
|
|
24
|
+
"deps": [],
|
|
25
|
+
"independent": true,
|
|
26
|
+
"parallel_safe": true
|
|
27
|
+
},
|
|
28
|
+
"6": {
|
|
29
|
+
"deps": [],
|
|
30
|
+
"independent": true,
|
|
31
|
+
"parallel_safe": true
|
|
32
|
+
},
|
|
33
|
+
"7": {
|
|
34
|
+
"deps": [],
|
|
35
|
+
"independent": false,
|
|
36
|
+
"parallel_safe": true
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stravinsky
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.42
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.42"
|
|
@@ -314,7 +314,15 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
|
|
|
314
314
|
elif name == "agent_list":
|
|
315
315
|
from .tools.agent_manager import agent_list
|
|
316
316
|
|
|
317
|
-
result_content = await agent_list()
|
|
317
|
+
result_content = await agent_list(show_all=arguments.get("show_all", True))
|
|
318
|
+
|
|
319
|
+
elif name == "agent_cleanup":
|
|
320
|
+
from .tools.agent_manager import agent_cleanup
|
|
321
|
+
|
|
322
|
+
result_content = await agent_cleanup(
|
|
323
|
+
max_age_minutes=arguments.get("max_age_minutes", 30),
|
|
324
|
+
statuses=arguments.get("statuses"),
|
|
325
|
+
)
|
|
318
326
|
|
|
319
327
|
elif name == "agent_progress":
|
|
320
328
|
from .tools.agent_manager import agent_progress
|
|
@@ -507,27 +515,34 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
|
|
|
507
515
|
debounce_seconds=arguments.get("debounce_seconds", 2.0),
|
|
508
516
|
)
|
|
509
517
|
|
|
510
|
-
result_content = json.dumps(
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
518
|
+
result_content = json.dumps(
|
|
519
|
+
{
|
|
520
|
+
"status": "started",
|
|
521
|
+
"project_path": str(watcher.project_path),
|
|
522
|
+
"debounce_seconds": watcher.debounce_seconds,
|
|
523
|
+
"provider": watcher.store.provider_name,
|
|
524
|
+
"is_running": watcher.is_running(),
|
|
525
|
+
},
|
|
526
|
+
indent=2,
|
|
527
|
+
)
|
|
517
528
|
except ValueError as e:
|
|
518
529
|
# No index exists
|
|
519
|
-
result_content = json.dumps(
|
|
520
|
-
"error": str(e),
|
|
521
|
-
|
|
522
|
-
|
|
530
|
+
result_content = json.dumps(
|
|
531
|
+
{"error": str(e), "hint": "Run semantic_index() before starting file watcher"},
|
|
532
|
+
indent=2,
|
|
533
|
+
)
|
|
523
534
|
print(f"⚠️ start_file_watcher ValueError: {e}", file=sys.stderr)
|
|
524
535
|
except Exception as e:
|
|
525
536
|
# Unexpected error
|
|
526
537
|
import traceback
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
538
|
+
|
|
539
|
+
result_content = json.dumps(
|
|
540
|
+
{
|
|
541
|
+
"error": f"{type(e).__name__}: {str(e)}",
|
|
542
|
+
"hint": "Check MCP server logs for details",
|
|
543
|
+
},
|
|
544
|
+
indent=2,
|
|
545
|
+
)
|
|
531
546
|
print(f"❌ start_file_watcher error: {e}", file=sys.stderr)
|
|
532
547
|
traceback.print_exc(file=sys.stderr)
|
|
533
548
|
|
|
@@ -540,10 +555,9 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
|
|
|
540
555
|
project_path=arguments.get("project_path", "."),
|
|
541
556
|
)
|
|
542
557
|
|
|
543
|
-
result_content = json.dumps(
|
|
544
|
-
"stopped": stopped,
|
|
545
|
-
|
|
546
|
-
}, indent=2)
|
|
558
|
+
result_content = json.dumps(
|
|
559
|
+
{"stopped": stopped, "project_path": arguments.get("project_path", ".")}, indent=2
|
|
560
|
+
)
|
|
547
561
|
|
|
548
562
|
elif name == "cancel_indexing":
|
|
549
563
|
from .tools.semantic_search import cancel_indexing
|
|
@@ -724,6 +738,7 @@ def sync_user_assets():
|
|
|
724
738
|
# Try importlib.resources as last resort (Python 3.9+)
|
|
725
739
|
try:
|
|
726
740
|
import importlib.resources as resources
|
|
741
|
+
|
|
727
742
|
# Check if stravinsky_claude_assets is a package
|
|
728
743
|
with resources.files("stravinsky_claude_assets") as assets_path:
|
|
729
744
|
if assets_path.is_dir():
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
from mcp.types import Prompt, Tool
|
|
3
2
|
|
|
4
3
|
|
|
@@ -466,10 +465,35 @@ def get_tool_definitions() -> list[Tool]:
|
|
|
466
465
|
),
|
|
467
466
|
Tool(
|
|
468
467
|
name="agent_list",
|
|
469
|
-
description="List all background agent tasks with their status.",
|
|
468
|
+
description="List all background agent tasks with their status. By default shows all agents; use show_all=false to see only running/pending.",
|
|
470
469
|
inputSchema={
|
|
471
470
|
"type": "object",
|
|
472
|
-
"properties": {
|
|
471
|
+
"properties": {
|
|
472
|
+
"show_all": {
|
|
473
|
+
"type": "boolean",
|
|
474
|
+
"description": "If false, only show running/pending agents. If true (default), show all.",
|
|
475
|
+
"default": True,
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
),
|
|
480
|
+
Tool(
|
|
481
|
+
name="agent_cleanup",
|
|
482
|
+
description="Clean up old completed/failed/cancelled agents to reduce clutter in agent_list. Removes agents older than max_age_minutes.",
|
|
483
|
+
inputSchema={
|
|
484
|
+
"type": "object",
|
|
485
|
+
"properties": {
|
|
486
|
+
"max_age_minutes": {
|
|
487
|
+
"type": "integer",
|
|
488
|
+
"description": "Remove agents older than this many minutes (default: 30)",
|
|
489
|
+
"default": 30,
|
|
490
|
+
},
|
|
491
|
+
"statuses": {
|
|
492
|
+
"type": "array",
|
|
493
|
+
"items": {"type": "string"},
|
|
494
|
+
"description": "List of statuses to remove (default: ['completed', 'failed', 'cancelled'])",
|
|
495
|
+
},
|
|
496
|
+
},
|
|
473
497
|
},
|
|
474
498
|
),
|
|
475
499
|
Tool(
|
|
@@ -258,14 +258,29 @@ class AgentManager:
|
|
|
258
258
|
tasks = self._load_tasks()
|
|
259
259
|
return tasks.get(task_id)
|
|
260
260
|
|
|
261
|
-
def list_tasks(
|
|
262
|
-
|
|
261
|
+
def list_tasks(
|
|
262
|
+
self, parent_session_id: str | None = None, show_all: bool = True
|
|
263
|
+
) -> list[dict[str, Any]]:
|
|
264
|
+
"""
|
|
265
|
+
List tasks, optionally filtered by parent session and status.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
parent_session_id: Optional filter by parent session
|
|
269
|
+
show_all: If False, only show running/pending agents. If True (default), show all.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
List of task dictionaries
|
|
273
|
+
"""
|
|
263
274
|
tasks = self._load_tasks()
|
|
264
275
|
task_list = list(tasks.values())
|
|
265
276
|
|
|
266
277
|
if parent_session_id:
|
|
267
278
|
task_list = [t for t in task_list if t.get("parent_session_id") == parent_session_id]
|
|
268
279
|
|
|
280
|
+
# Filter by status if not showing all
|
|
281
|
+
if not show_all:
|
|
282
|
+
task_list = [t for t in task_list if t.get("status") in ["running", "pending"]]
|
|
283
|
+
|
|
269
284
|
return task_list
|
|
270
285
|
|
|
271
286
|
def spawn(
|
|
@@ -453,6 +468,8 @@ class AgentManager:
|
|
|
453
468
|
|
|
454
469
|
except FileNotFoundError:
|
|
455
470
|
error_msg = f"Claude CLI not found at {self.CLAUDE_CLI}. Install with: npm install -g @anthropic-ai/claude-code"
|
|
471
|
+
# Ensure agents directory exists before writing log files
|
|
472
|
+
self.agents_dir.mkdir(parents=True, exist_ok=True)
|
|
456
473
|
log_file.write_text(error_msg)
|
|
457
474
|
# Write error to .out file for debugging
|
|
458
475
|
output_file.write_text(f"❌ FILE NOT FOUND: {error_msg}")
|
|
@@ -466,6 +483,8 @@ class AgentManager:
|
|
|
466
483
|
|
|
467
484
|
except Exception as e:
|
|
468
485
|
error_msg = str(e)
|
|
486
|
+
# Ensure agents directory exists before writing log files
|
|
487
|
+
self.agents_dir.mkdir(parents=True, exist_ok=True)
|
|
469
488
|
log_file.write_text(error_msg)
|
|
470
489
|
# Write error to .out file for debugging
|
|
471
490
|
output_file.write_text(f"❌ EXCEPTION: {error_msg}")
|
|
@@ -569,6 +588,76 @@ class AgentManager:
|
|
|
569
588
|
|
|
570
589
|
return stopped_count
|
|
571
590
|
|
|
591
|
+
def cleanup(
|
|
592
|
+
self,
|
|
593
|
+
max_age_minutes: int = 30,
|
|
594
|
+
statuses: list[str] | None = None,
|
|
595
|
+
) -> dict[str, Any]:
|
|
596
|
+
"""
|
|
597
|
+
Clean up old completed/failed/cancelled agents.
|
|
598
|
+
|
|
599
|
+
Args:
|
|
600
|
+
max_age_minutes: Remove tasks older than this (default: 30 minutes)
|
|
601
|
+
statuses: List of statuses to remove (default: ['completed', 'failed', 'cancelled'])
|
|
602
|
+
|
|
603
|
+
Returns:
|
|
604
|
+
{
|
|
605
|
+
"removed": int,
|
|
606
|
+
"task_ids": list[str],
|
|
607
|
+
"summary": str
|
|
608
|
+
}
|
|
609
|
+
"""
|
|
610
|
+
if statuses is None:
|
|
611
|
+
statuses = ["completed", "failed", "cancelled"]
|
|
612
|
+
|
|
613
|
+
tasks = self._load_tasks()
|
|
614
|
+
now = datetime.now()
|
|
615
|
+
removed_ids = []
|
|
616
|
+
|
|
617
|
+
for task_id, task in list(tasks.items()):
|
|
618
|
+
# Skip if status not in cleanup list
|
|
619
|
+
if task.get("status") not in statuses:
|
|
620
|
+
continue
|
|
621
|
+
|
|
622
|
+
# Check age
|
|
623
|
+
completed_at = task.get("completed_at")
|
|
624
|
+
if not completed_at:
|
|
625
|
+
continue
|
|
626
|
+
|
|
627
|
+
try:
|
|
628
|
+
completed_time = datetime.fromisoformat(completed_at)
|
|
629
|
+
age_minutes = (now - completed_time).total_seconds() / 60
|
|
630
|
+
|
|
631
|
+
if age_minutes > max_age_minutes:
|
|
632
|
+
removed_ids.append(task_id)
|
|
633
|
+
del tasks[task_id]
|
|
634
|
+
|
|
635
|
+
# Clean up associated files
|
|
636
|
+
task_files = [
|
|
637
|
+
self.agents_dir / f"{task_id}.log",
|
|
638
|
+
self.agents_dir / f"{task_id}.out",
|
|
639
|
+
self.agents_dir / f"{task_id}.system",
|
|
640
|
+
]
|
|
641
|
+
for f in task_files:
|
|
642
|
+
if f.exists():
|
|
643
|
+
try:
|
|
644
|
+
f.unlink()
|
|
645
|
+
except Exception:
|
|
646
|
+
pass
|
|
647
|
+
except (ValueError, AttributeError):
|
|
648
|
+
# Invalid timestamp, skip
|
|
649
|
+
continue
|
|
650
|
+
|
|
651
|
+
# Save updated tasks
|
|
652
|
+
if removed_ids:
|
|
653
|
+
self._save_tasks(tasks)
|
|
654
|
+
|
|
655
|
+
return {
|
|
656
|
+
"removed": len(removed_ids),
|
|
657
|
+
"task_ids": removed_ids,
|
|
658
|
+
"summary": f"Removed {len(removed_ids)} agent(s) older than {max_age_minutes} minutes",
|
|
659
|
+
}
|
|
660
|
+
|
|
572
661
|
def get_output(self, task_id: str, block: bool = False, timeout: float = 30.0) -> str:
|
|
573
662
|
"""
|
|
574
663
|
Get output from an agent task.
|
|
@@ -1086,15 +1175,43 @@ async def agent_cancel(task_id: str) -> str:
|
|
|
1086
1175
|
return f"⚠️ Task {task_id} is not running (status: {task['status']}). Cannot cancel."
|
|
1087
1176
|
|
|
1088
1177
|
|
|
1089
|
-
async def
|
|
1178
|
+
async def agent_cleanup(max_age_minutes: int = 30, statuses: list[str] | None = None) -> str:
|
|
1179
|
+
"""
|
|
1180
|
+
Clean up old completed/failed/cancelled agents.
|
|
1181
|
+
|
|
1182
|
+
Args:
|
|
1183
|
+
max_age_minutes: Remove agents older than this many minutes (default: 30)
|
|
1184
|
+
statuses: List of statuses to remove (default: ['completed', 'failed', 'cancelled'])
|
|
1185
|
+
|
|
1186
|
+
Returns:
|
|
1187
|
+
Formatted cleanup summary
|
|
1188
|
+
"""
|
|
1189
|
+
manager = get_manager()
|
|
1190
|
+
result = manager.cleanup(max_age_minutes=max_age_minutes, statuses=statuses)
|
|
1191
|
+
|
|
1192
|
+
if result["removed"] == 0:
|
|
1193
|
+
return f"🧹 No agents older than {max_age_minutes} minutes to clean up."
|
|
1194
|
+
|
|
1195
|
+
return (
|
|
1196
|
+
f"🧹 {Colors.BOLD}Cleanup Complete{Colors.RESET}\n\n"
|
|
1197
|
+
f"{result['summary']}\n\n"
|
|
1198
|
+
f"Removed agents:\n"
|
|
1199
|
+
+ "\n".join(f" • {Colors.BRIGHT_BLACK}{tid}{Colors.RESET}" for tid in result["task_ids"])
|
|
1200
|
+
)
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
async def agent_list(show_all: bool = True) -> str:
|
|
1090
1204
|
"""
|
|
1091
1205
|
List all background agent tasks.
|
|
1092
1206
|
|
|
1207
|
+
Args:
|
|
1208
|
+
show_all: If False, only show running/pending agents. If True (default), show all.
|
|
1209
|
+
|
|
1093
1210
|
Returns:
|
|
1094
1211
|
Formatted list of tasks
|
|
1095
1212
|
"""
|
|
1096
1213
|
manager = get_manager()
|
|
1097
|
-
tasks = manager.list_tasks()
|
|
1214
|
+
tasks = manager.list_tasks(show_all=show_all)
|
|
1098
1215
|
|
|
1099
1216
|
if not tasks:
|
|
1100
1217
|
return "No background agent tasks found."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "stravinsky"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.42"
|
|
4
4
|
description = "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
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11,<3.14"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.4.41"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|