mcpower-proxy 0.0.65__py3-none-any.whl → 0.0.79__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 mcpower-proxy might be problematic. Click here for more details.
- ide_tools/__init__.py +12 -0
- ide_tools/common/__init__.py +5 -0
- ide_tools/common/hooks/__init__.py +5 -0
- ide_tools/common/hooks/init.py +130 -0
- ide_tools/common/hooks/output.py +63 -0
- ide_tools/common/hooks/prompt_submit.py +136 -0
- ide_tools/common/hooks/read_file.py +170 -0
- ide_tools/common/hooks/shell_execution.py +257 -0
- ide_tools/common/hooks/shell_parser_bashlex.py +394 -0
- ide_tools/common/hooks/types.py +34 -0
- ide_tools/common/hooks/utils.py +286 -0
- ide_tools/cursor/__init__.py +11 -0
- ide_tools/cursor/constants.py +77 -0
- ide_tools/cursor/format.py +35 -0
- ide_tools/cursor/router.py +107 -0
- ide_tools/router.py +48 -0
- main.py +11 -4
- {mcpower_proxy-0.0.65.dist-info → mcpower_proxy-0.0.79.dist-info}/METADATA +4 -3
- mcpower_proxy-0.0.79.dist-info/RECORD +62 -0
- {mcpower_proxy-0.0.65.dist-info → mcpower_proxy-0.0.79.dist-info}/top_level.txt +1 -0
- modules/apis/security_policy.py +11 -6
- modules/decision_handler.py +219 -0
- modules/logs/audit_trail.py +20 -18
- modules/logs/logger.py +14 -18
- modules/redaction/gitleaks_rules.py +1 -1
- modules/redaction/pii_rules.py +0 -48
- modules/redaction/redactor.py +112 -107
- modules/ui/__init__.py +1 -1
- modules/ui/confirmation.py +0 -1
- modules/utils/cli.py +36 -6
- modules/utils/ids.py +55 -10
- modules/utils/json.py +3 -3
- modules/utils/platform.py +23 -0
- modules/utils/string.py +17 -0
- wrapper/__version__.py +1 -1
- wrapper/middleware.py +144 -221
- wrapper/server.py +19 -11
- mcpower_proxy-0.0.65.dist-info/RECORD +0 -43
- {mcpower_proxy-0.0.65.dist-info → mcpower_proxy-0.0.79.dist-info}/WHEEL +0 -0
- {mcpower_proxy-0.0.65.dist-info → mcpower_proxy-0.0.79.dist-info}/entry_points.txt +0 -0
- {mcpower_proxy-0.0.65.dist-info → mcpower_proxy-0.0.79.dist-info}/licenses/LICENSE +0 -0
modules/utils/ids.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Utilities for generating event IDs, session IDs, app UIDs, and timing helpers
|
|
3
3
|
"""
|
|
4
4
|
import os
|
|
5
|
+
import sys
|
|
5
6
|
import time
|
|
6
7
|
import uuid
|
|
7
8
|
from pathlib import Path
|
|
@@ -23,6 +24,16 @@ def generate_event_id() -> str:
|
|
|
23
24
|
return f"{timestamp}-{unique_part}"
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
def generate_prompt_id() -> str:
|
|
28
|
+
"""
|
|
29
|
+
Generate truly-random 8-character prompt ID for user request correlation
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
8-character random ID string
|
|
33
|
+
"""
|
|
34
|
+
return str(uuid.uuid4())[:8]
|
|
35
|
+
|
|
36
|
+
|
|
26
37
|
def get_session_id() -> str:
|
|
27
38
|
"""
|
|
28
39
|
Get session ID for the current process. Returns the same value for all calls
|
|
@@ -67,7 +78,8 @@ def _atomic_write_uuid(file_path: Path, new_uuid: str) -> bool:
|
|
|
67
78
|
True if write succeeded, False if file exists
|
|
68
79
|
"""
|
|
69
80
|
try:
|
|
70
|
-
|
|
81
|
+
mode = 0o666 if sys.platform == 'win32' else 0o600
|
|
82
|
+
fd = os.open(str(file_path), os.O_CREAT | os.O_EXCL | os.O_WRONLY, mode)
|
|
71
83
|
try:
|
|
72
84
|
os.write(fd, new_uuid.encode('utf-8'))
|
|
73
85
|
finally:
|
|
@@ -91,7 +103,7 @@ def _get_or_create_uuid(uid_path: Path, logger, id_type: str) -> str:
|
|
|
91
103
|
UUID string
|
|
92
104
|
"""
|
|
93
105
|
uid_path.parent.mkdir(parents=True, exist_ok=True)
|
|
94
|
-
|
|
106
|
+
|
|
95
107
|
max_attempts = 3
|
|
96
108
|
for attempt in range(max_attempts):
|
|
97
109
|
if uid_path.exists():
|
|
@@ -107,20 +119,53 @@ def _get_or_create_uuid(uid_path: Path, logger, id_type: str) -> str:
|
|
|
107
119
|
time.sleep(0.1 * (2 ** attempt))
|
|
108
120
|
continue
|
|
109
121
|
raise
|
|
110
|
-
|
|
122
|
+
|
|
111
123
|
new_uid = str(uuid.uuid4())
|
|
112
|
-
|
|
124
|
+
|
|
113
125
|
if _atomic_write_uuid(uid_path, new_uid):
|
|
114
|
-
logger.info(f"Generated {id_type}: {new_uid}")
|
|
126
|
+
logger.info(f"Generated {id_type}: {new_uid} at {uid_path}")
|
|
115
127
|
return new_uid
|
|
116
|
-
|
|
117
|
-
logger.debug(
|
|
128
|
+
|
|
129
|
+
logger.debug(
|
|
130
|
+
f"{id_type.title()} file created by another process, reading (attempt {attempt + 1}/{max_attempts})")
|
|
118
131
|
if attempt < max_attempts - 1:
|
|
119
132
|
time.sleep(0.05)
|
|
120
|
-
|
|
133
|
+
|
|
121
134
|
raise RuntimeError(f"Failed to get or create {id_type} after {max_attempts} attempts")
|
|
122
135
|
|
|
123
136
|
|
|
137
|
+
def get_home_mcpower_dir() -> Path:
|
|
138
|
+
"""
|
|
139
|
+
Get the global MCPower directory path in user's home directory
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Path to ~/.mcpower directory
|
|
143
|
+
"""
|
|
144
|
+
return Path.home() / ".mcpower"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def get_project_mcpower_dir(project_path: Optional[str] = None) -> str:
|
|
148
|
+
"""
|
|
149
|
+
Get the MCPower directory path, with fallback to global ~/.mcpower
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
project_path: Optional project/workspace path. If None or invalid, falls back to ~/.mcpower
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Path to use for MCPower data (either project/.mcpower or ~/.mcpower)
|
|
156
|
+
"""
|
|
157
|
+
if project_path:
|
|
158
|
+
try:
|
|
159
|
+
path = Path(project_path)
|
|
160
|
+
if path.exists() and path.is_dir():
|
|
161
|
+
return str(path)
|
|
162
|
+
except Exception:
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
# Fallback to global ~/.mcpower
|
|
166
|
+
return str(get_home_mcpower_dir())
|
|
167
|
+
|
|
168
|
+
|
|
124
169
|
def get_or_create_user_id(logger) -> str:
|
|
125
170
|
"""
|
|
126
171
|
Get or create machine-wide user ID from ~/.mcpower/uid
|
|
@@ -132,7 +177,7 @@ def get_or_create_user_id(logger) -> str:
|
|
|
132
177
|
Returns:
|
|
133
178
|
User ID string
|
|
134
179
|
"""
|
|
135
|
-
uid_path =
|
|
180
|
+
uid_path = get_home_mcpower_dir() / "uid"
|
|
136
181
|
return _get_or_create_uuid(uid_path, logger, "user ID")
|
|
137
182
|
|
|
138
183
|
|
|
@@ -156,5 +201,5 @@ def read_app_uid(logger, project_folder_path: str) -> str:
|
|
|
156
201
|
else:
|
|
157
202
|
# Project-specific case
|
|
158
203
|
uid_path = project_path / ".mcpower" / "app_uid"
|
|
159
|
-
|
|
204
|
+
|
|
160
205
|
return _get_or_create_uuid(uid_path, logger, "app UID")
|
modules/utils/json.py
CHANGED
|
@@ -52,7 +52,7 @@ def safe_json_dumps(obj: Any, **kwargs) -> str:
|
|
|
52
52
|
# If it's a Pydantic BaseModel, use its built-in JSON serialization
|
|
53
53
|
if isinstance(obj, BaseModel):
|
|
54
54
|
return obj.model_dump_json(**kwargs)
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
# If it's a dict or list that might contain Pydantic objects, use custom serializer
|
|
57
57
|
def default_serializer(o):
|
|
58
58
|
if isinstance(o, BaseModel):
|
|
@@ -72,7 +72,7 @@ def safe_json_dumps(obj: Any, **kwargs) -> str:
|
|
|
72
72
|
return o.__dict__
|
|
73
73
|
# Fallback to string representation
|
|
74
74
|
return str(o)
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
return json.dumps(obj, default=default_serializer, **kwargs)
|
|
77
77
|
|
|
78
78
|
|
|
@@ -117,4 +117,4 @@ def parse_jsonc(text: str) -> Any:
|
|
|
117
117
|
return json.loads(text)
|
|
118
118
|
except json.JSONDecodeError:
|
|
119
119
|
# Re-raise the original JSONC error if JSON also fails
|
|
120
|
-
raise json.JSONDecodeError(f"JSONC parsing failed: {str(e)}", text, 0)
|
|
120
|
+
raise json.JSONDecodeError(f"JSONC parsing failed: {str(e)}", text, 0)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Platform detection utilities"""
|
|
2
|
+
import sys
|
|
3
|
+
from typing import Optional, Literal
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_client_os() -> Optional[Literal["macos", "windows", "linux"]]:
|
|
7
|
+
"""
|
|
8
|
+
Fetch Python's sys.platform and convert to standardized OS names.
|
|
9
|
+
|
|
10
|
+
Returns:
|
|
11
|
+
"macos", "windows", "linux", or None if platform is unknown
|
|
12
|
+
"""
|
|
13
|
+
platform = sys.platform
|
|
14
|
+
|
|
15
|
+
if platform == "darwin":
|
|
16
|
+
return "macos"
|
|
17
|
+
elif platform == "win32":
|
|
18
|
+
return "windows"
|
|
19
|
+
elif platform == "linux":
|
|
20
|
+
return "linux"
|
|
21
|
+
else:
|
|
22
|
+
return None
|
|
23
|
+
|
modules/utils/string.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""String utility functions"""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def truncate_at(text: str, max_length: int) -> str:
|
|
5
|
+
"""
|
|
6
|
+
Truncate string at max_length, appending '...' only if truncated.
|
|
7
|
+
|
|
8
|
+
Args:
|
|
9
|
+
text: String to truncate
|
|
10
|
+
max_length: Maximum length before truncation
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
Truncated string with '...' suffix if truncated, original if not
|
|
14
|
+
"""
|
|
15
|
+
if len(text) <= max_length:
|
|
16
|
+
return text
|
|
17
|
+
return f"{text[:max_length]}..."
|
wrapper/__version__.py
CHANGED