mcpower-proxy 0.0.67__py3-none-any.whl → 0.0.77__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.
Files changed (41) hide show
  1. ide_tools/__init__.py +12 -0
  2. ide_tools/common/__init__.py +5 -0
  3. ide_tools/common/hooks/__init__.py +5 -0
  4. ide_tools/common/hooks/init.py +129 -0
  5. ide_tools/common/hooks/output.py +63 -0
  6. ide_tools/common/hooks/prompt_submit.py +136 -0
  7. ide_tools/common/hooks/read_file.py +170 -0
  8. ide_tools/common/hooks/shell_execution.py +257 -0
  9. ide_tools/common/hooks/shell_parser_bashlex.py +394 -0
  10. ide_tools/common/hooks/types.py +34 -0
  11. ide_tools/common/hooks/utils.py +286 -0
  12. ide_tools/cursor/__init__.py +11 -0
  13. ide_tools/cursor/constants.py +58 -0
  14. ide_tools/cursor/format.py +35 -0
  15. ide_tools/cursor/router.py +101 -0
  16. ide_tools/router.py +48 -0
  17. main.py +11 -4
  18. {mcpower_proxy-0.0.67.dist-info → mcpower_proxy-0.0.77.dist-info}/METADATA +4 -3
  19. mcpower_proxy-0.0.77.dist-info/RECORD +62 -0
  20. {mcpower_proxy-0.0.67.dist-info → mcpower_proxy-0.0.77.dist-info}/top_level.txt +1 -0
  21. modules/apis/security_policy.py +11 -6
  22. modules/decision_handler.py +219 -0
  23. modules/logs/audit_trail.py +20 -18
  24. modules/logs/logger.py +14 -18
  25. modules/redaction/gitleaks_rules.py +1 -1
  26. modules/redaction/pii_rules.py +0 -48
  27. modules/redaction/redactor.py +112 -107
  28. modules/ui/__init__.py +1 -1
  29. modules/ui/confirmation.py +0 -1
  30. modules/utils/cli.py +36 -6
  31. modules/utils/ids.py +50 -7
  32. modules/utils/json.py +3 -3
  33. modules/utils/platform.py +23 -0
  34. modules/utils/string.py +17 -0
  35. wrapper/__version__.py +1 -1
  36. wrapper/middleware.py +136 -221
  37. wrapper/server.py +19 -11
  38. mcpower_proxy-0.0.67.dist-info/RECORD +0 -43
  39. {mcpower_proxy-0.0.67.dist-info → mcpower_proxy-0.0.77.dist-info}/WHEEL +0 -0
  40. {mcpower_proxy-0.0.67.dist-info → mcpower_proxy-0.0.77.dist-info}/entry_points.txt +0 -0
  41. {mcpower_proxy-0.0.67.dist-info → mcpower_proxy-0.0.77.dist-info}/licenses/LICENSE +0 -0
modules/utils/ids.py CHANGED
@@ -24,6 +24,16 @@ def generate_event_id() -> str:
24
24
  return f"{timestamp}-{unique_part}"
25
25
 
26
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
+
27
37
  def get_session_id() -> str:
28
38
  """
29
39
  Get session ID for the current process. Returns the same value for all calls
@@ -109,20 +119,53 @@ def _get_or_create_uuid(uid_path: Path, logger, id_type: str) -> str:
109
119
  time.sleep(0.1 * (2 ** attempt))
110
120
  continue
111
121
  raise
112
-
122
+
113
123
  new_uid = str(uuid.uuid4())
114
-
124
+
115
125
  if _atomic_write_uuid(uid_path, new_uid):
116
126
  logger.info(f"Generated {id_type}: {new_uid} at {uid_path}")
117
127
  return new_uid
118
-
119
- logger.debug(f"{id_type.title()} file created by another process, reading (attempt {attempt + 1}/{max_attempts})")
128
+
129
+ logger.debug(
130
+ f"{id_type.title()} file created by another process, reading (attempt {attempt + 1}/{max_attempts})")
120
131
  if attempt < max_attempts - 1:
121
132
  time.sleep(0.05)
122
-
133
+
123
134
  raise RuntimeError(f"Failed to get or create {id_type} after {max_attempts} attempts")
124
135
 
125
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
+
126
169
  def get_or_create_user_id(logger) -> str:
127
170
  """
128
171
  Get or create machine-wide user ID from ~/.mcpower/uid
@@ -134,7 +177,7 @@ def get_or_create_user_id(logger) -> str:
134
177
  Returns:
135
178
  User ID string
136
179
  """
137
- uid_path = Path.home() / ".mcpower" / "uid"
180
+ uid_path = get_home_mcpower_dir() / "uid"
138
181
  return _get_or_create_uuid(uid_path, logger, "user ID")
139
182
 
140
183
 
@@ -158,5 +201,5 @@ def read_app_uid(logger, project_folder_path: str) -> str:
158
201
  else:
159
202
  # Project-specific case
160
203
  uid_path = project_path / ".mcpower" / "app_uid"
161
-
204
+
162
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
+
@@ -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
@@ -3,4 +3,4 @@
3
3
  Wrapper MCP Server Version
4
4
  """
5
5
 
6
- __version__ = "0.0.67"
6
+ __version__ = "0.0.77"