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
mcp_bridge/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.2.
|
|
1
|
+
__version__ = "0.2.67"
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Background Token Refresh Scheduler
|
|
3
|
+
|
|
4
|
+
Proactively refreshes OAuth tokens before they expire:
|
|
5
|
+
- Gemini: Refreshes when 30 minutes remaining (tokens expire in ~1 hour)
|
|
6
|
+
- OpenAI: Refreshes when 12 hours remaining (tokens expire in ~24 hours)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import logging
|
|
11
|
+
import time
|
|
12
|
+
from typing import TYPE_CHECKING
|
|
13
|
+
|
|
14
|
+
from .oauth import refresh_access_token as gemini_refresh
|
|
15
|
+
from .openai_oauth import refresh_access_token as openai_refresh
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from .token_store import TokenStore
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
# Refresh configuration per provider
|
|
23
|
+
REFRESH_CONFIG = {
|
|
24
|
+
"gemini": {
|
|
25
|
+
"interval": 3600, # Token expires in ~1 hour
|
|
26
|
+
"buffer": 1800, # Refresh with 30 min remaining
|
|
27
|
+
},
|
|
28
|
+
"openai": {
|
|
29
|
+
"interval": 86400, # Token expires in ~24 hours
|
|
30
|
+
"buffer": 43200, # Refresh with 12 hours remaining
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def background_token_refresh(token_store: "TokenStore") -> None:
|
|
36
|
+
"""
|
|
37
|
+
Background task that proactively refreshes tokens before expiry.
|
|
38
|
+
|
|
39
|
+
Runs in an infinite loop, checking every 5 minutes if any tokens
|
|
40
|
+
need refreshing. This prevents tokens from expiring during long
|
|
41
|
+
sessions.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
token_store: The token store to manage.
|
|
45
|
+
"""
|
|
46
|
+
logger.info("Starting background token refresh scheduler")
|
|
47
|
+
|
|
48
|
+
while True:
|
|
49
|
+
for provider, config in REFRESH_CONFIG.items():
|
|
50
|
+
await _refresh_if_needed(token_store, provider, config["buffer"])
|
|
51
|
+
|
|
52
|
+
# Check every 5 minutes
|
|
53
|
+
await asyncio.sleep(300)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
async def _refresh_if_needed(
|
|
57
|
+
token_store: "TokenStore",
|
|
58
|
+
provider: str,
|
|
59
|
+
buffer_seconds: int,
|
|
60
|
+
) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Refresh a provider's token if it's close to expiring.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
token_store: Token store instance
|
|
66
|
+
provider: Provider name (gemini, openai)
|
|
67
|
+
buffer_seconds: Refresh when this many seconds remain
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
# Check if token needs refresh
|
|
71
|
+
if not token_store.needs_refresh(provider, buffer_seconds=buffer_seconds):
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
token = token_store.get_token(provider)
|
|
75
|
+
if not token or not token.get("refresh_token"):
|
|
76
|
+
return # No token or no refresh token
|
|
77
|
+
|
|
78
|
+
# Get the appropriate refresh function
|
|
79
|
+
refresh_fn = gemini_refresh if provider == "gemini" else openai_refresh
|
|
80
|
+
|
|
81
|
+
# Perform refresh
|
|
82
|
+
result = refresh_fn(token["refresh_token"])
|
|
83
|
+
|
|
84
|
+
# Update stored token
|
|
85
|
+
token_store.update_access_token(
|
|
86
|
+
provider,
|
|
87
|
+
result.access_token,
|
|
88
|
+
result.expires_in,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
logger.info(
|
|
92
|
+
f"Proactively refreshed {provider} token "
|
|
93
|
+
f"(expires in {result.expires_in}s)"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logger.warning(f"Failed to refresh {provider} token: {e}")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def get_token_status(token_store: "TokenStore") -> dict[str, dict]:
|
|
101
|
+
"""
|
|
102
|
+
Get status of all provider tokens.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Dict mapping provider to status info.
|
|
106
|
+
"""
|
|
107
|
+
status = {}
|
|
108
|
+
|
|
109
|
+
for provider in REFRESH_CONFIG:
|
|
110
|
+
token = token_store.get_token(provider)
|
|
111
|
+
|
|
112
|
+
if not token:
|
|
113
|
+
status[provider] = {"status": "not_authenticated"}
|
|
114
|
+
continue
|
|
115
|
+
|
|
116
|
+
expires_at = token.get("expires_at", 0)
|
|
117
|
+
if expires_at <= 0:
|
|
118
|
+
status[provider] = {"status": "authenticated", "expires": "unknown"}
|
|
119
|
+
else:
|
|
120
|
+
remaining = expires_at - time.time()
|
|
121
|
+
if remaining <= 0:
|
|
122
|
+
status[provider] = {"status": "expired"}
|
|
123
|
+
else:
|
|
124
|
+
status[provider] = {
|
|
125
|
+
"status": "valid",
|
|
126
|
+
"expires_in_seconds": int(remaining),
|
|
127
|
+
"expires_in_minutes": int(remaining / 60),
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return status
|