stravinsky 0.2.52__py3-none-any.whl → 0.4.18__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 (58) hide show
  1. mcp_bridge/__init__.py +1 -1
  2. mcp_bridge/auth/token_store.py +113 -11
  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/config/MANIFEST_SCHEMA.md +305 -0
  7. mcp_bridge/config/README.md +276 -0
  8. mcp_bridge/config/hook_config.py +249 -0
  9. mcp_bridge/config/hooks_manifest.json +138 -0
  10. mcp_bridge/config/rate_limits.py +222 -0
  11. mcp_bridge/config/skills_manifest.json +128 -0
  12. mcp_bridge/hooks/HOOKS_SETTINGS.json +175 -0
  13. mcp_bridge/hooks/README.md +215 -0
  14. mcp_bridge/hooks/__init__.py +119 -60
  15. mcp_bridge/hooks/edit_recovery.py +42 -37
  16. mcp_bridge/hooks/git_noninteractive.py +89 -0
  17. mcp_bridge/hooks/keyword_detector.py +30 -0
  18. mcp_bridge/hooks/manager.py +8 -0
  19. mcp_bridge/hooks/notification_hook.py +103 -0
  20. mcp_bridge/hooks/parallel_execution.py +111 -0
  21. mcp_bridge/hooks/pre_compact.py +82 -183
  22. mcp_bridge/hooks/rules_injector.py +507 -0
  23. mcp_bridge/hooks/session_notifier.py +125 -0
  24. mcp_bridge/{native_hooks → hooks}/stravinsky_mode.py +51 -16
  25. mcp_bridge/hooks/subagent_stop.py +98 -0
  26. mcp_bridge/hooks/task_validator.py +73 -0
  27. mcp_bridge/hooks/tmux_manager.py +141 -0
  28. mcp_bridge/hooks/todo_continuation.py +90 -0
  29. mcp_bridge/hooks/todo_delegation.py +88 -0
  30. mcp_bridge/hooks/tool_messaging.py +267 -0
  31. mcp_bridge/hooks/truncator.py +21 -17
  32. mcp_bridge/notifications.py +151 -0
  33. mcp_bridge/prompts/multimodal.py +24 -3
  34. mcp_bridge/server.py +214 -49
  35. mcp_bridge/server_tools.py +445 -0
  36. mcp_bridge/tools/__init__.py +22 -18
  37. mcp_bridge/tools/agent_manager.py +220 -32
  38. mcp_bridge/tools/code_search.py +97 -11
  39. mcp_bridge/tools/lsp/__init__.py +7 -0
  40. mcp_bridge/tools/lsp/manager.py +448 -0
  41. mcp_bridge/tools/lsp/tools.py +637 -150
  42. mcp_bridge/tools/model_invoke.py +208 -106
  43. mcp_bridge/tools/query_classifier.py +323 -0
  44. mcp_bridge/tools/semantic_search.py +3042 -0
  45. mcp_bridge/tools/templates.py +32 -18
  46. mcp_bridge/update_manager.py +589 -0
  47. mcp_bridge/update_manager_pypi.py +299 -0
  48. stravinsky-0.4.18.dist-info/METADATA +468 -0
  49. stravinsky-0.4.18.dist-info/RECORD +88 -0
  50. stravinsky-0.4.18.dist-info/entry_points.txt +5 -0
  51. mcp_bridge/native_hooks/edit_recovery.py +0 -46
  52. mcp_bridge/native_hooks/todo_delegation.py +0 -54
  53. mcp_bridge/native_hooks/truncator.py +0 -23
  54. stravinsky-0.2.52.dist-info/METADATA +0 -204
  55. stravinsky-0.2.52.dist-info/RECORD +0 -63
  56. stravinsky-0.2.52.dist-info/entry_points.txt +0 -3
  57. /mcp_bridge/{native_hooks → hooks}/context.py +0 -0
  58. {stravinsky-0.2.52.dist-info → stravinsky-0.4.18.dist-info}/WHEEL +0 -0
@@ -1,224 +1,123 @@
1
+ #!/usr/bin/env python3
1
2
  """
2
- PreCompact Hook - Context Preservation Before Compaction.
3
+ PreCompact hook: Context preservation before compaction.
3
4
 
4
- Triggers before session compaction to preserve critical context
5
- that should survive summarization. Uses Gemini for intelligent
6
- context extraction and preservation.
5
+ Fires before Claude Code compacts conversation context to:
6
+ 1. Preserve critical context patterns
7
+ 2. Maintain stravinsky mode state
8
+ 3. Warn about information loss
9
+ 4. Save state for recovery
7
10
 
8
- Based on oh-my-opencode's pre-compact hook pattern.
11
+ Cannot block compaction (exit 2 only shows error).
9
12
  """
10
13
 
11
- import logging
12
- from typing import Any, Dict, List, Optional
14
+ import json
15
+ import sys
16
+ from pathlib import Path
17
+ from datetime import datetime
18
+ from typing import List, Dict, Any
13
19
 
14
- logger = logging.getLogger(__name__)
15
20
 
16
- # Flag to prevent recursive calls during Gemini invocation
17
- _in_preservation = False
21
+ STRAVINSKY_MODE_FILE = Path.home() / ".stravinsky_mode"
22
+ STATE_DIR = Path.home() / ".claude" / "state"
23
+ COMPACTION_LOG = STATE_DIR / "compaction.jsonl"
18
24
 
19
- # Critical context patterns to preserve
25
+ # Patterns to preserve
20
26
  PRESERVE_PATTERNS = [
21
- # Architecture decisions
22
27
  "ARCHITECTURE:",
23
28
  "DESIGN DECISION:",
24
- "## Architecture",
25
-
26
- # Important constraints
27
29
  "CONSTRAINT:",
28
30
  "REQUIREMENT:",
29
31
  "MUST NOT:",
30
32
  "NEVER:",
31
-
32
- # Session state
33
+ "CRITICAL ERROR:",
33
34
  "CURRENT TASK:",
34
35
  "BLOCKED BY:",
35
- "WAITING FOR:",
36
-
37
- # Critical errors
38
- "CRITICAL ERROR:",
39
- "SECURITY ISSUE:",
40
- "BREAKING CHANGE:",
36
+ "[STRAVINSKY MODE]",
37
+ "PARALLEL_DELEGATION:",
41
38
  ]
42
39
 
43
- # Memory anchors to inject into compaction
44
- MEMORY_ANCHORS: List[str] = []
45
-
46
-
47
- def register_memory_anchor(anchor: str, priority: str = "normal"):
48
- """
49
- Register a memory anchor to preserve during compaction.
50
-
51
- Args:
52
- anchor: The text to preserve
53
- priority: "critical" or "normal"
54
- """
55
- if priority == "critical":
56
- MEMORY_ANCHORS.insert(0, f"[CRITICAL] {anchor}")
57
- else:
58
- MEMORY_ANCHORS.append(anchor)
59
-
60
- # Limit to 10 anchors to prevent bloat
61
- while len(MEMORY_ANCHORS) > 10:
62
- MEMORY_ANCHORS.pop()
63
-
64
-
65
- def clear_memory_anchors():
66
- """Clear all registered memory anchors."""
67
- MEMORY_ANCHORS.clear()
68
-
69
-
70
- async def pre_compact_hook(params: Dict[str, Any]) -> Optional[Dict[str, Any]]:
71
- """
72
- Pre-model-invoke hook that runs before context compaction.
73
-
74
- Uses Gemini to intelligently extract and preserve critical context
75
- that should survive summarization.
76
- """
77
- global _in_preservation
78
-
79
- # Prevent recursive calls
80
- if _in_preservation:
81
- return None
82
-
83
- prompt = params.get("prompt", "")
84
-
85
- # Only activate for compaction-related prompts
86
- if not _is_compaction_prompt(prompt):
87
- return None
88
-
89
- # Collect pattern-matched context
90
- preserved_context = _extract_preserved_context(prompt)
91
- preserved_context.extend(MEMORY_ANCHORS)
92
-
93
- # Use Gemini for intelligent context extraction if prompt is long
94
- if len(prompt) > 50000:
95
- try:
96
- _in_preservation = True
97
- gemini_context = await _extract_context_with_gemini(prompt)
98
- if gemini_context:
99
- preserved_context.extend(gemini_context)
100
- except Exception as e:
101
- logger.warning(f"[PreCompactHook] Gemini extraction failed: {e}")
102
- finally:
103
- _in_preservation = False
104
-
105
- if not preserved_context:
106
- return None
107
-
108
- # Build preservation section
109
- preservation_section = _build_preservation_section(preserved_context)
110
-
111
- logger.info(f"[PreCompactHook] Preserving {len(preserved_context)} context items")
112
-
113
- # Inject into prompt
114
- modified_prompt = prompt + "\n\n" + preservation_section
115
-
116
- return {**params, "prompt": modified_prompt}
117
40
 
41
+ def ensure_state_dir():
42
+ """Ensure state directory exists."""
43
+ STATE_DIR.mkdir(parents=True, exist_ok=True)
118
44
 
119
- async def _extract_context_with_gemini(prompt: str) -> List[str]:
120
- """
121
- Use Gemini to intelligently extract critical context to preserve.
122
45
 
123
- Args:
124
- prompt: The full conversation/context to analyze
125
-
126
- Returns:
127
- List of critical context items to preserve
128
- """
46
+ def get_stravinsky_mode_state() -> Dict[str, Any]:
47
+ """Read stravinsky mode state."""
48
+ if not STRAVINSKY_MODE_FILE.exists():
49
+ return {"active": False}
129
50
  try:
130
- from ..tools.model_invoke import invoke_gemini_impl
131
-
132
- # Truncate prompt if too long for Gemini
133
- max_chars = 100000
134
- truncated = prompt[:max_chars] if len(prompt) > max_chars else prompt
135
-
136
- extraction_prompt = f"""Analyze this conversation and extract ONLY the most critical information that MUST be preserved during summarization.
137
-
138
- Focus on:
139
- 1. Architecture decisions and their rationale
140
- 2. Critical constraints or requirements
141
- 3. Important error patterns or debugging insights
142
- 4. Key file paths and their purposes
143
- 5. Unfinished tasks or blocking issues
144
-
145
- Return a bullet list of critical items (max 10). Be extremely concise.
146
-
147
- CONVERSATION:
148
- {truncated}
51
+ content = STRAVINSKY_MODE_FILE.read_text().strip()
52
+ return json.loads(content) if content else {"active": True}
53
+ except (json.JSONDecodeError, IOError):
54
+ return {"active": True}
149
55
 
150
- CRITICAL ITEMS TO PRESERVE:"""
151
56
 
152
- result = await invoke_gemini_impl(
153
- prompt=extraction_prompt,
154
- model="gemini-3-flash",
155
- max_tokens=2000,
156
- temperature=0.1,
157
- )
57
+ def extract_preserved_context(prompt: str) -> List[str]:
58
+ """Extract context matching preservation patterns."""
59
+ preserved = []
60
+ lines = prompt.split("\n")
158
61
 
159
- if not result:
160
- return []
62
+ for i, line in enumerate(lines):
63
+ for pattern in PRESERVE_PATTERNS:
64
+ if pattern in line:
65
+ # Capture line + 2 more for context
66
+ context = "\n".join(lines[i:min(i+3, len(lines))])
67
+ preserved.append(context)
68
+ break
161
69
 
162
- # Parse bullet points from response
163
- lines = result.strip().split("\n")
164
- items = []
165
- for line in lines:
166
- line = line.strip()
167
- if line.startswith(("-", "*", "•")) or (len(line) > 1 and line[0].isdigit() and line[1] in ".):"):
168
- # Clean up the bullet
169
- item = line.lstrip("-*•0123456789.): ").strip()
170
- if item and len(item) > 10:
171
- items.append(item)
70
+ return preserved[:15] # Max 15 items
172
71
 
173
- return items[:10] # Max 10 items
174
72
 
175
- except Exception as e:
176
- logger.warning(f"[PreCompactHook] Gemini context extraction error: {e}")
177
- return []
73
+ def log_compaction(preserved: List[str], stravinsky_active: bool):
74
+ """Log compaction event for audit."""
75
+ ensure_state_dir()
178
76
 
77
+ entry = {
78
+ "timestamp": datetime.utcnow().isoformat(),
79
+ "preserved_count": len(preserved),
80
+ "stravinsky_mode": stravinsky_active,
81
+ "preview": [p[:50] for p in preserved[:3]],
82
+ }
179
83
 
180
- def _is_compaction_prompt(prompt: str) -> bool:
181
- """Detect if this is a compaction/summarization prompt."""
182
- compaction_signals = [
183
- "summarize the conversation",
184
- "compact the context",
185
- "reduce context size",
186
- "context window",
187
- "summarization",
188
- ]
84
+ try:
85
+ with COMPACTION_LOG.open("a") as f:
86
+ f.write(json.dumps(entry) + "\n")
87
+ except IOError:
88
+ pass
189
89
 
190
- prompt_lower = prompt.lower()
191
- return any(signal in prompt_lower for signal in compaction_signals)
192
90
 
91
+ def main():
92
+ """Main hook entry point."""
93
+ try:
94
+ hook_input = json.load(sys.stdin)
95
+ except (json.JSONDecodeError, EOFError):
96
+ return 0
193
97
 
194
- def _extract_preserved_context(prompt: str) -> List[str]:
195
- """Extract context matching preservation patterns."""
196
- preserved = []
197
- lines = prompt.split("\n")
98
+ prompt = hook_input.get("prompt", "")
99
+ trigger = hook_input.get("trigger", "auto")
198
100
 
199
- for i, line in enumerate(lines):
200
- for pattern in PRESERVE_PATTERNS:
201
- if pattern in line:
202
- # Capture the line and next 2 lines for context
203
- context_lines = lines[i:i+3]
204
- preserved.append("\n".join(context_lines))
205
- break
101
+ # Get stravinsky mode state
102
+ strav_state = get_stravinsky_mode_state()
103
+ stravinsky_active = strav_state.get("active", False)
206
104
 
207
- return preserved
105
+ # Extract preserved context
106
+ preserved = extract_preserved_context(prompt)
208
107
 
108
+ # Log compaction event
109
+ log_compaction(preserved, stravinsky_active)
209
110
 
210
- def _build_preservation_section(context_items: List[str]) -> str:
211
- """Build the preservation section to inject."""
212
- section = """
213
- ## CRITICAL CONTEXT TO PRESERVE
111
+ # Output preservation warning
112
+ if preserved or stravinsky_active:
113
+ print(f"\n[PreCompact] Context compaction triggered ({trigger})", file=sys.stderr)
114
+ print(f" Preserved items: {len(preserved)}", file=sys.stderr)
115
+ if stravinsky_active:
116
+ print(" [STRAVINSKY MODE ACTIVE] - State will persist", file=sys.stderr)
117
+ print(" Audit log: ~/.claude/state/compaction.jsonl", file=sys.stderr)
214
118
 
215
- The following information MUST be preserved in any summarization:
119
+ return 0
216
120
 
217
- """
218
- for i, item in enumerate(context_items, 1):
219
- section += f"{i}. {item}\n\n"
220
121
 
221
- section += """
222
- When summarizing, ensure these items are included verbatim or with minimal paraphrasing.
223
- """
224
- return section
122
+ if __name__ == "__main__":
123
+ sys.exit(main())