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.

Files changed (52) hide show
  1. mcp_bridge/__init__.py +1 -1
  2. mcp_bridge/auth/token_refresh.py +130 -0
  3. mcp_bridge/cli/__init__.py +6 -0
  4. mcp_bridge/cli/install_hooks.py +1265 -0
  5. mcp_bridge/cli/session_report.py +585 -0
  6. mcp_bridge/hooks/HOOKS_SETTINGS.json +175 -0
  7. mcp_bridge/hooks/README.md +215 -0
  8. mcp_bridge/hooks/__init__.py +117 -46
  9. mcp_bridge/hooks/edit_recovery.py +42 -37
  10. mcp_bridge/hooks/git_noninteractive.py +89 -0
  11. mcp_bridge/hooks/keyword_detector.py +30 -0
  12. mcp_bridge/hooks/manager.py +50 -0
  13. mcp_bridge/hooks/notification_hook.py +103 -0
  14. mcp_bridge/hooks/parallel_enforcer.py +127 -0
  15. mcp_bridge/hooks/parallel_execution.py +111 -0
  16. mcp_bridge/hooks/pre_compact.py +123 -0
  17. mcp_bridge/hooks/preemptive_compaction.py +81 -7
  18. mcp_bridge/hooks/rules_injector.py +507 -0
  19. mcp_bridge/hooks/session_idle.py +116 -0
  20. mcp_bridge/hooks/session_notifier.py +125 -0
  21. mcp_bridge/{native_hooks → hooks}/stravinsky_mode.py +51 -16
  22. mcp_bridge/hooks/subagent_stop.py +98 -0
  23. mcp_bridge/hooks/task_validator.py +73 -0
  24. mcp_bridge/hooks/tmux_manager.py +141 -0
  25. mcp_bridge/hooks/todo_continuation.py +90 -0
  26. mcp_bridge/hooks/todo_delegation.py +88 -0
  27. mcp_bridge/hooks/tool_messaging.py +164 -0
  28. mcp_bridge/hooks/truncator.py +21 -17
  29. mcp_bridge/prompts/__init__.py +3 -1
  30. mcp_bridge/prompts/dewey.py +30 -20
  31. mcp_bridge/prompts/explore.py +46 -8
  32. mcp_bridge/prompts/multimodal.py +24 -3
  33. mcp_bridge/prompts/planner.py +222 -0
  34. mcp_bridge/prompts/stravinsky.py +107 -28
  35. mcp_bridge/server.py +76 -10
  36. mcp_bridge/server_tools.py +164 -32
  37. mcp_bridge/tools/agent_manager.py +203 -96
  38. mcp_bridge/tools/background_tasks.py +2 -1
  39. mcp_bridge/tools/code_search.py +81 -9
  40. mcp_bridge/tools/lsp/tools.py +6 -2
  41. mcp_bridge/tools/model_invoke.py +270 -47
  42. mcp_bridge/tools/templates.py +32 -18
  43. stravinsky-0.2.67.dist-info/METADATA +284 -0
  44. stravinsky-0.2.67.dist-info/RECORD +76 -0
  45. stravinsky-0.2.67.dist-info/entry_points.txt +5 -0
  46. mcp_bridge/native_hooks/edit_recovery.py +0 -46
  47. mcp_bridge/native_hooks/truncator.py +0 -23
  48. stravinsky-0.2.40.dist-info/METADATA +0 -204
  49. stravinsky-0.2.40.dist-info/RECORD +0 -57
  50. stravinsky-0.2.40.dist-info/entry_points.txt +0 -3
  51. /mcp_bridge/{native_hooks → hooks}/context.py +0 -0
  52. {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.32"
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
@@ -0,0 +1,6 @@
1
+ """CLI tools for Stravinsky."""
2
+
3
+ from .session_report import main as session_report_main
4
+ from .install_hooks import main as install_hooks_main
5
+
6
+ __all__ = ["session_report_main", "install_hooks_main"]