stravinsky 0.2.67__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.
- mcp_bridge/__init__.py +1 -1
- mcp_bridge/auth/token_store.py +113 -11
- mcp_bridge/config/MANIFEST_SCHEMA.md +305 -0
- mcp_bridge/config/README.md +276 -0
- mcp_bridge/config/hook_config.py +249 -0
- mcp_bridge/config/hooks_manifest.json +138 -0
- mcp_bridge/config/rate_limits.py +222 -0
- mcp_bridge/config/skills_manifest.json +128 -0
- mcp_bridge/hooks/__init__.py +8 -3
- mcp_bridge/hooks/manager.py +8 -0
- mcp_bridge/hooks/tool_messaging.py +113 -10
- mcp_bridge/notifications.py +151 -0
- mcp_bridge/server.py +202 -48
- mcp_bridge/server_tools.py +440 -0
- mcp_bridge/tools/__init__.py +22 -18
- mcp_bridge/tools/agent_manager.py +197 -28
- mcp_bridge/tools/code_search.py +16 -2
- mcp_bridge/tools/lsp/__init__.py +7 -0
- mcp_bridge/tools/lsp/manager.py +448 -0
- mcp_bridge/tools/lsp/tools.py +634 -151
- mcp_bridge/tools/model_invoke.py +186 -159
- mcp_bridge/tools/query_classifier.py +323 -0
- mcp_bridge/tools/semantic_search.py +3042 -0
- mcp_bridge/update_manager.py +589 -0
- mcp_bridge/update_manager_pypi.py +299 -0
- {stravinsky-0.2.67.dist-info → stravinsky-0.4.18.dist-info}/METADATA +209 -25
- {stravinsky-0.2.67.dist-info → stravinsky-0.4.18.dist-info}/RECORD +29 -17
- {stravinsky-0.2.67.dist-info → stravinsky-0.4.18.dist-info}/WHEEL +0 -0
- {stravinsky-0.2.67.dist-info → stravinsky-0.4.18.dist-info}/entry_points.txt +0 -0
mcp_bridge/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.4.18"
|
mcp_bridge/auth/token_store.py
CHANGED
|
@@ -8,10 +8,12 @@ Stores OAuth tokens securely using the OS keyring:
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
+
import os
|
|
11
12
|
import time
|
|
13
|
+
from pathlib import Path
|
|
12
14
|
from typing import TypedDict
|
|
13
15
|
|
|
14
|
-
import
|
|
16
|
+
from cryptography.fernet import Fernet
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
class TokenData(TypedDict, total=False):
|
|
@@ -26,13 +28,15 @@ class TokenData(TypedDict, total=False):
|
|
|
26
28
|
|
|
27
29
|
class TokenStore:
|
|
28
30
|
"""
|
|
29
|
-
Secure storage for OAuth tokens using system keyring.
|
|
31
|
+
Secure storage for OAuth tokens using system keyring with encrypted file fallback.
|
|
30
32
|
|
|
31
33
|
Each provider (gemini, openai) stores its tokens separately.
|
|
32
34
|
Tokens are serialized as JSON for storage.
|
|
35
|
+
Falls back to encrypted file storage if keyring fails.
|
|
33
36
|
"""
|
|
34
37
|
|
|
35
38
|
SERVICE_NAME = "stravinsky"
|
|
39
|
+
FALLBACK_DIR = Path.home() / ".stravinsky" / "tokens"
|
|
36
40
|
|
|
37
41
|
def __init__(self, service_name: str | None = None):
|
|
38
42
|
"""Initialize the token store.
|
|
@@ -41,6 +45,63 @@ class TokenStore:
|
|
|
41
45
|
service_name: Override the default service name for testing.
|
|
42
46
|
"""
|
|
43
47
|
self.service_name = service_name or self.SERVICE_NAME
|
|
48
|
+
self._init_fallback_storage()
|
|
49
|
+
|
|
50
|
+
def _init_fallback_storage(self) -> None:
|
|
51
|
+
"""Initialize encrypted file storage fallback directory."""
|
|
52
|
+
self.FALLBACK_DIR.mkdir(parents=True, exist_ok=True)
|
|
53
|
+
|
|
54
|
+
def _get_fallback_path(self, provider: str) -> Path:
|
|
55
|
+
"""Get the path for encrypted fallback storage."""
|
|
56
|
+
return self.FALLBACK_DIR / f"{provider}.enc"
|
|
57
|
+
|
|
58
|
+
def _get_or_create_key(self) -> bytes:
|
|
59
|
+
"""Get or create encryption key for fallback storage."""
|
|
60
|
+
key_file = self.FALLBACK_DIR / ".key"
|
|
61
|
+
if key_file.exists():
|
|
62
|
+
return key_file.read_bytes()
|
|
63
|
+
# Create new key and save it
|
|
64
|
+
key = Fernet.generate_key()
|
|
65
|
+
key_file.write_bytes(key)
|
|
66
|
+
key_file.chmod(0o600) # Read/write for owner only
|
|
67
|
+
return key
|
|
68
|
+
|
|
69
|
+
def _save_encrypted(self, provider: str, data: str) -> None:
|
|
70
|
+
"""Save data to encrypted file."""
|
|
71
|
+
try:
|
|
72
|
+
key = self._get_or_create_key()
|
|
73
|
+
cipher = Fernet(key)
|
|
74
|
+
encrypted = cipher.encrypt(data.encode())
|
|
75
|
+
path = self._get_fallback_path(provider)
|
|
76
|
+
path.write_bytes(encrypted)
|
|
77
|
+
path.chmod(0o600)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
raise RuntimeError(f"Failed to save encrypted token: {e}")
|
|
80
|
+
|
|
81
|
+
def _load_encrypted(self, provider: str) -> str | None:
|
|
82
|
+
"""Load data from encrypted file."""
|
|
83
|
+
try:
|
|
84
|
+
path = self._get_fallback_path(provider)
|
|
85
|
+
if not path.exists():
|
|
86
|
+
return None
|
|
87
|
+
key = self._get_or_create_key()
|
|
88
|
+
cipher = Fernet(key)
|
|
89
|
+
encrypted = path.read_bytes()
|
|
90
|
+
decrypted = cipher.decrypt(encrypted)
|
|
91
|
+
return decrypted.decode()
|
|
92
|
+
except Exception:
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
def _delete_encrypted(self, provider: str) -> bool:
|
|
96
|
+
"""Delete encrypted token file."""
|
|
97
|
+
try:
|
|
98
|
+
path = self._get_fallback_path(provider)
|
|
99
|
+
if path.exists():
|
|
100
|
+
path.unlink()
|
|
101
|
+
return True
|
|
102
|
+
return False
|
|
103
|
+
except Exception:
|
|
104
|
+
return False
|
|
44
105
|
|
|
45
106
|
def _key(self, provider: str) -> str:
|
|
46
107
|
"""Generate the keyring key for a provider."""
|
|
@@ -56,13 +117,24 @@ class TokenStore:
|
|
|
56
117
|
Returns:
|
|
57
118
|
TokenData if found and valid, None otherwise.
|
|
58
119
|
"""
|
|
120
|
+
# Try keyring first (import inside try to catch backend initialization errors)
|
|
59
121
|
try:
|
|
122
|
+
import keyring
|
|
60
123
|
data = keyring.get_password(self.service_name, self._key(provider))
|
|
61
|
-
if
|
|
62
|
-
return
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
124
|
+
if data:
|
|
125
|
+
return json.loads(data)
|
|
126
|
+
except Exception:
|
|
127
|
+
pass # Fall back to encrypted file (catches KeyringError, import errors, etc.)
|
|
128
|
+
|
|
129
|
+
# Fall back to encrypted file storage
|
|
130
|
+
try:
|
|
131
|
+
data = self._load_encrypted(provider)
|
|
132
|
+
if data:
|
|
133
|
+
return json.loads(data)
|
|
134
|
+
except json.JSONDecodeError:
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
return None
|
|
66
138
|
|
|
67
139
|
def set_token(
|
|
68
140
|
self,
|
|
@@ -77,6 +149,7 @@ class TokenStore:
|
|
|
77
149
|
Store a token for a provider.
|
|
78
150
|
|
|
79
151
|
Can be called with a TokenData dict or individual parameters.
|
|
152
|
+
Falls back to encrypted file storage if keyring fails.
|
|
80
153
|
|
|
81
154
|
Args:
|
|
82
155
|
provider: The provider name (e.g., 'gemini', 'openai')
|
|
@@ -96,7 +169,27 @@ class TokenStore:
|
|
|
96
169
|
if expires_at:
|
|
97
170
|
token_data["expires_at"] = expires_at
|
|
98
171
|
data = json.dumps(token_data)
|
|
99
|
-
|
|
172
|
+
|
|
173
|
+
# Try keyring first, but always also write to encrypted storage
|
|
174
|
+
# Import inside try to catch backend initialization errors (e.g., "No recommended backend")
|
|
175
|
+
keyring_failed = False
|
|
176
|
+
try:
|
|
177
|
+
import keyring
|
|
178
|
+
keyring.set_password(self.service_name, self._key(provider), data)
|
|
179
|
+
except Exception:
|
|
180
|
+
# Keyring failed - fall back to encrypted file
|
|
181
|
+
keyring_failed = True
|
|
182
|
+
|
|
183
|
+
# Always write to encrypted file storage as fallback
|
|
184
|
+
try:
|
|
185
|
+
self._save_encrypted(provider, data)
|
|
186
|
+
except Exception as e:
|
|
187
|
+
# Only fail if both backends failed
|
|
188
|
+
if keyring_failed:
|
|
189
|
+
raise RuntimeError(
|
|
190
|
+
f"Failed to save token to both keyring and encrypted storage: {e}"
|
|
191
|
+
)
|
|
192
|
+
|
|
100
193
|
|
|
101
194
|
def delete_token(self, provider: str) -> bool:
|
|
102
195
|
"""
|
|
@@ -108,11 +201,20 @@ class TokenStore:
|
|
|
108
201
|
Returns:
|
|
109
202
|
True if deleted, False if not found.
|
|
110
203
|
"""
|
|
204
|
+
# Try keyring first (import inside try to catch backend initialization errors)
|
|
205
|
+
deleted_from_keyring = False
|
|
111
206
|
try:
|
|
207
|
+
import keyring
|
|
112
208
|
keyring.delete_password(self.service_name, self._key(provider))
|
|
113
|
-
|
|
114
|
-
except
|
|
115
|
-
|
|
209
|
+
deleted_from_keyring = True
|
|
210
|
+
except Exception:
|
|
211
|
+
# Keyring failed (no backend, delete error, etc.) - continue to encrypted file
|
|
212
|
+
pass
|
|
213
|
+
|
|
214
|
+
# Also delete from encrypted file storage
|
|
215
|
+
deleted_from_file = self._delete_encrypted(provider)
|
|
216
|
+
|
|
217
|
+
return deleted_from_keyring or deleted_from_file
|
|
116
218
|
|
|
117
219
|
def has_valid_token(self, provider: str) -> bool:
|
|
118
220
|
"""
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# Stravinsky Manifest Schema Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The manifest files (`hooks_manifest.json` and `skills_manifest.json`) track version information, integrity, and metadata for all Stravinsky-provided hooks and skills. These manifests enable:
|
|
6
|
+
|
|
7
|
+
- **Integrity Verification**: Detect unauthorized or accidental modifications
|
|
8
|
+
- **Update Management**: Determine which files need updating during package upgrades
|
|
9
|
+
- **User Customization**: Distinguish between official Stravinsky files and user modifications
|
|
10
|
+
- **Dependency Tracking**: Understand hook dependencies and required relationships
|
|
11
|
+
|
|
12
|
+
## File Locations
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
mcp_bridge/config/
|
|
16
|
+
├── hooks_manifest.json # Official hook metadata
|
|
17
|
+
├── skills_manifest.json # Slash command metadata
|
|
18
|
+
└── MANIFEST_SCHEMA.md # This documentation
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Manifest Structure
|
|
22
|
+
|
|
23
|
+
### Common Fields
|
|
24
|
+
|
|
25
|
+
Both manifests share these top-level fields:
|
|
26
|
+
|
|
27
|
+
| Field | Type | Purpose |
|
|
28
|
+
|-------|------|---------|
|
|
29
|
+
| `schema_version` | string | Manifest format version (e.g., "1.0.0") |
|
|
30
|
+
| `manifest_version` | string | Stravinsky package version this manifest was generated for |
|
|
31
|
+
| `description` | string | Brief description of manifest purpose |
|
|
32
|
+
| `generated_date` | ISO 8601 | Timestamp when manifest was created/updated |
|
|
33
|
+
| `schema` | object | Field definitions and their meanings |
|
|
34
|
+
| `[items]` | object | Collection of hooks or skills with metadata |
|
|
35
|
+
| `usage` | object | Integration notes for `update_manager.py` |
|
|
36
|
+
|
|
37
|
+
### hooks_manifest.json Schema
|
|
38
|
+
|
|
39
|
+
Each hook entry has these fields:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"hook_name": {
|
|
44
|
+
"version": "0.2.63",
|
|
45
|
+
"source": "mcp_bridge/hooks/hook_name.py",
|
|
46
|
+
"description": "Brief description of hook purpose",
|
|
47
|
+
"hook_type": "PreToolUse|PostToolUse|UserPromptSubmit|Notification|SubagentStop|PreCompact|package|manager|session_idle|session_manager",
|
|
48
|
+
"checksum": "sha256_first_12_chars",
|
|
49
|
+
"lines_of_code": 150,
|
|
50
|
+
"updatable": true,
|
|
51
|
+
"priority": "critical|high|medium|low",
|
|
52
|
+
"required": true,
|
|
53
|
+
"dependencies": ["manager.py", "other_hook.py"]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### skills_manifest.json Schema
|
|
59
|
+
|
|
60
|
+
Each skill entry has these fields:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"skill_name": {
|
|
65
|
+
"file_path": "strav.md or str/search.md",
|
|
66
|
+
"description": "Description from skill frontmatter",
|
|
67
|
+
"category": "core|research|implementation|architecture",
|
|
68
|
+
"checksum": "sha256_first_12_chars",
|
|
69
|
+
"lines_of_code": 200,
|
|
70
|
+
"updatable": true,
|
|
71
|
+
"priority": "critical|high|medium|low",
|
|
72
|
+
"agent_type": "explore|dewey|frontend|delphi|stravinsky|implementation_lead|code_reviewer",
|
|
73
|
+
"blocking": true,
|
|
74
|
+
"requires_auth": true,
|
|
75
|
+
"version_first_added": "0.1.0",
|
|
76
|
+
"notes": "Additional context or special considerations"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Field Definitions
|
|
82
|
+
|
|
83
|
+
### `version`
|
|
84
|
+
Semantic version of the hook/skill implementation. Format: `X.Y.Z` (e.g., `0.2.63`).
|
|
85
|
+
|
|
86
|
+
### `source` / `file_path`
|
|
87
|
+
Absolute path (hooks) or relative path from `.claude/commands/` (skills).
|
|
88
|
+
|
|
89
|
+
### `description`
|
|
90
|
+
One-line functional description of what the hook/skill does.
|
|
91
|
+
|
|
92
|
+
### `hook_type` (hooks only)
|
|
93
|
+
Claude Code hook type that this hook implements:
|
|
94
|
+
- **PreToolUse**: Runs before tool execution (can block with exit code 2)
|
|
95
|
+
- **PostToolUse**: Runs after tool completes
|
|
96
|
+
- **UserPromptSubmit**: Runs when user submits prompt
|
|
97
|
+
- **Notification**: Runs on notification events
|
|
98
|
+
- **SubagentStop**: Runs when agent completes
|
|
99
|
+
- **PreCompact**: Runs before context compaction
|
|
100
|
+
- **package**: Module/package initialization
|
|
101
|
+
- **manager**: Hook management infrastructure
|
|
102
|
+
- **session_idle**: Session idle detection
|
|
103
|
+
|
|
104
|
+
### `category` (skills only)
|
|
105
|
+
Skill category for organization:
|
|
106
|
+
- **core**: Essential orchestration features
|
|
107
|
+
- **research**: Documentation and code search
|
|
108
|
+
- **implementation**: Development workflows (test, review, deploy)
|
|
109
|
+
- **architecture**: Strategic advice and complex debugging
|
|
110
|
+
|
|
111
|
+
### `checksum`
|
|
112
|
+
SHA-256 hash (first 12 characters) for integrity verification.
|
|
113
|
+
|
|
114
|
+
**How to verify/generate:**
|
|
115
|
+
```bash
|
|
116
|
+
# Generate checksum
|
|
117
|
+
sha256sum mcp_bridge/hooks/hook_name.py | awk '{print substr($1,1,12)}'
|
|
118
|
+
|
|
119
|
+
# Verify file hasn't been modified
|
|
120
|
+
sha256sum -c <<< "checksum_value mcp_bridge/hooks/hook_name.py"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### `updatable`
|
|
124
|
+
- **true**: Official Stravinsky file - can be auto-updated by `update_manager.py`
|
|
125
|
+
- **false**: User customization or user-provided hook - skip during updates
|
|
126
|
+
|
|
127
|
+
**CRITICAL**: User hooks from `.claude/hooks/` should ALWAYS have `updatable: false` in the internal manifest comparison.
|
|
128
|
+
|
|
129
|
+
### `priority`
|
|
130
|
+
Update urgency level:
|
|
131
|
+
- **critical**: Security fixes, core functionality - update immediately
|
|
132
|
+
- **high**: New features, important improvements - include in next release
|
|
133
|
+
- **medium**: Enhancements, can batch with other updates
|
|
134
|
+
- **low**: Optional improvements, can defer
|
|
135
|
+
|
|
136
|
+
### `required`
|
|
137
|
+
- **true**: Hook is essential for core functionality and cannot be disabled
|
|
138
|
+
- **false**: Optional hook that provides enhanced behavior but isn't critical
|
|
139
|
+
|
|
140
|
+
### `blocking` (skills only)
|
|
141
|
+
- **true**: Skill blocks execution until completion
|
|
142
|
+
- **false**: Skill runs asynchronously in background
|
|
143
|
+
|
|
144
|
+
### `agent_type` (skills only)
|
|
145
|
+
Primary agent spawned by this skill:
|
|
146
|
+
- **stravinsky**: Task orchestration
|
|
147
|
+
- **explore**: Codebase search
|
|
148
|
+
- **dewey**: Documentation research
|
|
149
|
+
- **delphi**: Strategic architecture advisor
|
|
150
|
+
- **frontend**: UI/UX design
|
|
151
|
+
- **implementation_lead**: Coordinates implementation
|
|
152
|
+
- **code_reviewer**: Quality analysis
|
|
153
|
+
|
|
154
|
+
### `requires_auth` (skills only)
|
|
155
|
+
- **true**: Skill requires OAuth setup (Gemini or OpenAI)
|
|
156
|
+
- **false**: Skill works without authentication
|
|
157
|
+
|
|
158
|
+
### `dependencies`
|
|
159
|
+
List of other files this hook/skill depends on:
|
|
160
|
+
- Hooks typically depend on `manager.py`
|
|
161
|
+
- Some hooks depend on other hooks they coordinate with
|
|
162
|
+
- Skills may list dependent tools or agents
|
|
163
|
+
|
|
164
|
+
## Integration with update_manager.py
|
|
165
|
+
|
|
166
|
+
The `update_manager.py` module should use these manifests to:
|
|
167
|
+
|
|
168
|
+
### 1. Version Checking
|
|
169
|
+
```python
|
|
170
|
+
# Load installed manifest
|
|
171
|
+
installed_manifest = load_manifest("hooks_manifest.json")
|
|
172
|
+
|
|
173
|
+
# Compare with remote version
|
|
174
|
+
if installed_manifest.version < remote_manifest.version:
|
|
175
|
+
# Updates available
|
|
176
|
+
pass
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 2. Integrity Verification
|
|
180
|
+
```python
|
|
181
|
+
# Before updating, verify file hasn't been locally modified
|
|
182
|
+
current_checksum = compute_sha256(file_path)
|
|
183
|
+
expected_checksum = manifest[hook_name].checksum
|
|
184
|
+
|
|
185
|
+
if current_checksum != expected_checksum and manifest[hook_name].updatable:
|
|
186
|
+
# Local modifications detected - warn user or skip
|
|
187
|
+
skip_update(hook_name)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 3. Selective Updates
|
|
191
|
+
```python
|
|
192
|
+
# Only update files marked updatable=true
|
|
193
|
+
for hook_name, hook_info in manifest.items():
|
|
194
|
+
if hook_info.updatable and should_update(hook_info.priority):
|
|
195
|
+
update_hook(hook_name, new_version)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 4. Dependency Resolution
|
|
199
|
+
```python
|
|
200
|
+
# Ensure dependencies are met before updating
|
|
201
|
+
for dependency in hook_info.dependencies:
|
|
202
|
+
if not is_dependency_installed(dependency):
|
|
203
|
+
error("Missing dependency: " + dependency)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Usage Examples
|
|
207
|
+
|
|
208
|
+
### Checking Hook Status
|
|
209
|
+
```bash
|
|
210
|
+
# Find all critical hooks needing updates
|
|
211
|
+
jq '.hooks | to_entries[] | select(.value.priority == "critical")' \
|
|
212
|
+
mcp_bridge/config/hooks_manifest.json
|
|
213
|
+
|
|
214
|
+
# Check if a hook is required
|
|
215
|
+
jq '.hooks.parallel_enforcer.required' \
|
|
216
|
+
mcp_bridge/config/hooks_manifest.json
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Verifying File Integrity
|
|
220
|
+
```bash
|
|
221
|
+
# Verify all hooks match expected checksums
|
|
222
|
+
python -c "
|
|
223
|
+
import json
|
|
224
|
+
from pathlib import Path
|
|
225
|
+
|
|
226
|
+
with open('mcp_bridge/config/hooks_manifest.json') as f:
|
|
227
|
+
manifest = json.load(f)
|
|
228
|
+
|
|
229
|
+
for hook_name, info in manifest['hooks'].items():
|
|
230
|
+
file_path = info['source']
|
|
231
|
+
if Path(file_path).exists():
|
|
232
|
+
# Compute checksum and compare
|
|
233
|
+
pass
|
|
234
|
+
"
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Listing Available Skills
|
|
238
|
+
```bash
|
|
239
|
+
# Extract all skills with their agents
|
|
240
|
+
jq '.skills | to_entries[] | {name: .key, agent: .value.agent_type, blocking: .value.blocking}' \
|
|
241
|
+
mcp_bridge/config/skills_manifest.json
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Best Practices
|
|
245
|
+
|
|
246
|
+
### For Stravinsky Maintainers
|
|
247
|
+
|
|
248
|
+
1. **Update on Release**: Regenerate manifests when releasing a new version
|
|
249
|
+
2. **Verify Checksums**: Ensure all checksums are current and accurate
|
|
250
|
+
3. **Document Changes**: Add notes to skills when updating functionality
|
|
251
|
+
4. **Priority Assignment**: Use priority levels consistently across releases
|
|
252
|
+
5. **Dependency Tracking**: Keep dependency lists current and accurate
|
|
253
|
+
|
|
254
|
+
### For Package Users
|
|
255
|
+
|
|
256
|
+
1. **Don't Modify Manifests**: Let `update_manager.py` handle manifest updates
|
|
257
|
+
2. **Preserve Customizations**: Don't modify hooks marked as required=true without good reason
|
|
258
|
+
3. **Check Auth Requirements**: Ensure OAuth is configured for skills requiring authentication
|
|
259
|
+
4. **Monitor Critical Updates**: Subscribe to updates for hooks marked priority=critical
|
|
260
|
+
|
|
261
|
+
### For Developers
|
|
262
|
+
|
|
263
|
+
1. **Custom Hooks**: Create custom hooks in `.claude/hooks/` (not in package)
|
|
264
|
+
2. **Hook Testing**: Always test hooks with sample input before deploying
|
|
265
|
+
3. **Checksum Calculation**: Update checksums when modifying hook files
|
|
266
|
+
4. **Dependency Management**: Clearly document all hook dependencies
|
|
267
|
+
|
|
268
|
+
## Schema Evolution
|
|
269
|
+
|
|
270
|
+
### Version 1.0.0 (Current)
|
|
271
|
+
- Initial manifest format
|
|
272
|
+
- Hook and skill metadata tracking
|
|
273
|
+
- Integrity verification via checksums
|
|
274
|
+
- Priority-based update strategy
|
|
275
|
+
|
|
276
|
+
### Future Versions
|
|
277
|
+
- Will be tracked in `schema_version`
|
|
278
|
+
- Backward compatibility maintained where possible
|
|
279
|
+
- Migration guides provided for breaking changes
|
|
280
|
+
|
|
281
|
+
## Troubleshooting
|
|
282
|
+
|
|
283
|
+
### Checksum Mismatch
|
|
284
|
+
**Problem**: Hook has been modified locally
|
|
285
|
+
**Solution**:
|
|
286
|
+
- If intentional: Update manifest checksum or move to custom hooks
|
|
287
|
+
- If accidental: Restore original file from package
|
|
288
|
+
|
|
289
|
+
### Missing Dependencies
|
|
290
|
+
**Problem**: Hook dependency is not installed
|
|
291
|
+
**Solution**: Ensure all required hooks in `dependencies` list are installed
|
|
292
|
+
|
|
293
|
+
### Update Failures
|
|
294
|
+
**Problem**: `update_manager.py` fails to update a hook
|
|
295
|
+
**Solution**:
|
|
296
|
+
- Check file permissions
|
|
297
|
+
- Verify checksum hasn't changed unexpectedly
|
|
298
|
+
- Check for read-only files
|
|
299
|
+
|
|
300
|
+
## Related Files
|
|
301
|
+
|
|
302
|
+
- `mcp_bridge/cli/install_hooks.py` - Hook installation script
|
|
303
|
+
- `mcp_bridge/config/hooks.py` - Hook configuration utilities
|
|
304
|
+
- `mcp_bridge/hooks/manager.py` - Hook execution manager
|
|
305
|
+
- `.claude/settings.json` - Claude Code hook configuration
|