tweek 0.1.0__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 (85) hide show
  1. tweek/__init__.py +16 -0
  2. tweek/cli.py +3390 -0
  3. tweek/cli_helpers.py +193 -0
  4. tweek/config/__init__.py +13 -0
  5. tweek/config/allowed_dirs.yaml +23 -0
  6. tweek/config/manager.py +1064 -0
  7. tweek/config/patterns.yaml +751 -0
  8. tweek/config/tiers.yaml +129 -0
  9. tweek/diagnostics.py +589 -0
  10. tweek/hooks/__init__.py +1 -0
  11. tweek/hooks/pre_tool_use.py +861 -0
  12. tweek/integrations/__init__.py +3 -0
  13. tweek/integrations/moltbot.py +243 -0
  14. tweek/licensing.py +398 -0
  15. tweek/logging/__init__.py +9 -0
  16. tweek/logging/bundle.py +350 -0
  17. tweek/logging/json_logger.py +150 -0
  18. tweek/logging/security_log.py +745 -0
  19. tweek/mcp/__init__.py +24 -0
  20. tweek/mcp/approval.py +456 -0
  21. tweek/mcp/approval_cli.py +356 -0
  22. tweek/mcp/clients/__init__.py +37 -0
  23. tweek/mcp/clients/chatgpt.py +112 -0
  24. tweek/mcp/clients/claude_desktop.py +203 -0
  25. tweek/mcp/clients/gemini.py +178 -0
  26. tweek/mcp/proxy.py +667 -0
  27. tweek/mcp/screening.py +175 -0
  28. tweek/mcp/server.py +317 -0
  29. tweek/platform/__init__.py +131 -0
  30. tweek/plugins/__init__.py +835 -0
  31. tweek/plugins/base.py +1080 -0
  32. tweek/plugins/compliance/__init__.py +30 -0
  33. tweek/plugins/compliance/gdpr.py +333 -0
  34. tweek/plugins/compliance/gov.py +324 -0
  35. tweek/plugins/compliance/hipaa.py +285 -0
  36. tweek/plugins/compliance/legal.py +322 -0
  37. tweek/plugins/compliance/pci.py +361 -0
  38. tweek/plugins/compliance/soc2.py +275 -0
  39. tweek/plugins/detectors/__init__.py +30 -0
  40. tweek/plugins/detectors/continue_dev.py +206 -0
  41. tweek/plugins/detectors/copilot.py +254 -0
  42. tweek/plugins/detectors/cursor.py +192 -0
  43. tweek/plugins/detectors/moltbot.py +205 -0
  44. tweek/plugins/detectors/windsurf.py +214 -0
  45. tweek/plugins/git_discovery.py +395 -0
  46. tweek/plugins/git_installer.py +491 -0
  47. tweek/plugins/git_lockfile.py +338 -0
  48. tweek/plugins/git_registry.py +503 -0
  49. tweek/plugins/git_security.py +482 -0
  50. tweek/plugins/providers/__init__.py +30 -0
  51. tweek/plugins/providers/anthropic.py +181 -0
  52. tweek/plugins/providers/azure_openai.py +289 -0
  53. tweek/plugins/providers/bedrock.py +248 -0
  54. tweek/plugins/providers/google.py +197 -0
  55. tweek/plugins/providers/openai.py +230 -0
  56. tweek/plugins/scope.py +130 -0
  57. tweek/plugins/screening/__init__.py +26 -0
  58. tweek/plugins/screening/llm_reviewer.py +149 -0
  59. tweek/plugins/screening/pattern_matcher.py +273 -0
  60. tweek/plugins/screening/rate_limiter.py +174 -0
  61. tweek/plugins/screening/session_analyzer.py +159 -0
  62. tweek/proxy/__init__.py +302 -0
  63. tweek/proxy/addon.py +223 -0
  64. tweek/proxy/interceptor.py +313 -0
  65. tweek/proxy/server.py +315 -0
  66. tweek/sandbox/__init__.py +71 -0
  67. tweek/sandbox/executor.py +382 -0
  68. tweek/sandbox/linux.py +278 -0
  69. tweek/sandbox/profile_generator.py +323 -0
  70. tweek/screening/__init__.py +13 -0
  71. tweek/screening/context.py +81 -0
  72. tweek/security/__init__.py +22 -0
  73. tweek/security/llm_reviewer.py +348 -0
  74. tweek/security/rate_limiter.py +682 -0
  75. tweek/security/secret_scanner.py +506 -0
  76. tweek/security/session_analyzer.py +600 -0
  77. tweek/vault/__init__.py +40 -0
  78. tweek/vault/cross_platform.py +251 -0
  79. tweek/vault/keychain.py +288 -0
  80. tweek-0.1.0.dist-info/METADATA +335 -0
  81. tweek-0.1.0.dist-info/RECORD +85 -0
  82. tweek-0.1.0.dist-info/WHEEL +5 -0
  83. tweek-0.1.0.dist-info/entry_points.txt +25 -0
  84. tweek-0.1.0.dist-info/licenses/LICENSE +190 -0
  85. tweek-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Tweek Moltbot Detector Plugin
4
+
5
+ Detects Moltbot AI coding assistant:
6
+ - Global npm installation
7
+ - Running process
8
+ - Gateway configuration
9
+ - Potential proxy conflicts
10
+ """
11
+
12
+ import os
13
+ import subprocess
14
+ import json
15
+ from pathlib import Path
16
+ from typing import Optional, List, Dict, Any
17
+ from tweek.plugins.base import ToolDetectorPlugin, DetectionResult
18
+
19
+
20
+ class MoltbotDetector(ToolDetectorPlugin):
21
+ """
22
+ Moltbot AI coding assistant detector.
23
+
24
+ Detects:
25
+ - npm global installation
26
+ - Running moltbot process
27
+ - Gateway service on default port
28
+ - Configuration file location
29
+ """
30
+
31
+ VERSION = "1.0.0"
32
+ DESCRIPTION = "Detect Moltbot AI coding assistant"
33
+ AUTHOR = "Tweek"
34
+ REQUIRES_LICENSE = "free"
35
+ TAGS = ["detector", "moltbot", "ide"]
36
+
37
+ DEFAULT_PORT = 8080
38
+ CONFIG_LOCATIONS = [
39
+ Path.home() / ".moltbot" / "config.json",
40
+ Path.home() / ".config" / "moltbot" / "config.json",
41
+ ]
42
+
43
+ @property
44
+ def name(self) -> str:
45
+ return "moltbot"
46
+
47
+ def detect(self) -> DetectionResult:
48
+ """
49
+ Detect Moltbot installation and status.
50
+ """
51
+ result = DetectionResult(
52
+ detected=False,
53
+ tool_name=self.name,
54
+ )
55
+
56
+ # Check npm global installation
57
+ npm_info = self._check_npm_installation()
58
+ if npm_info:
59
+ result.detected = True
60
+ result.version = npm_info.get("version")
61
+ result.install_path = npm_info.get("path")
62
+
63
+ # Check for config file
64
+ config_path = self._find_config()
65
+ if config_path:
66
+ result.detected = True
67
+ result.config_path = str(config_path)
68
+
69
+ # Read config for port info
70
+ try:
71
+ with open(config_path) as f:
72
+ config = json.load(f)
73
+ result.port = config.get("gateway", {}).get("port", self.DEFAULT_PORT)
74
+ except (json.JSONDecodeError, IOError):
75
+ result.port = self.DEFAULT_PORT
76
+
77
+ # Check for running process
78
+ process_info = self._check_running_process()
79
+ if process_info:
80
+ result.detected = True
81
+ result.running = True
82
+ result.metadata["pid"] = process_info.get("pid")
83
+ if process_info.get("port"):
84
+ result.port = process_info["port"]
85
+
86
+ # Check if gateway is active
87
+ if result.port:
88
+ result.metadata["gateway_active"] = self._check_gateway_active(result.port)
89
+
90
+ return result
91
+
92
+ def _check_npm_installation(self) -> Optional[Dict[str, str]]:
93
+ """Check if moltbot is installed via npm."""
94
+ try:
95
+ # Try npm list -g
96
+ proc = subprocess.run(
97
+ ["npm", "list", "-g", "moltbot", "--json"],
98
+ capture_output=True,
99
+ text=True,
100
+ timeout=10,
101
+ )
102
+ if proc.returncode == 0:
103
+ data = json.loads(proc.stdout)
104
+ deps = data.get("dependencies", {})
105
+ if "moltbot" in deps:
106
+ return {
107
+ "version": deps["moltbot"].get("version", "unknown"),
108
+ "path": data.get("path", ""),
109
+ }
110
+ except (subprocess.TimeoutExpired, json.JSONDecodeError, FileNotFoundError):
111
+ pass
112
+
113
+ # Try which/where
114
+ try:
115
+ proc = subprocess.run(
116
+ ["which", "moltbot"] if os.name != "nt" else ["where", "moltbot"],
117
+ capture_output=True,
118
+ text=True,
119
+ timeout=5,
120
+ )
121
+ if proc.returncode == 0 and proc.stdout.strip():
122
+ return {"path": proc.stdout.strip().split("\n")[0]}
123
+ except (subprocess.TimeoutExpired, FileNotFoundError):
124
+ pass
125
+
126
+ return None
127
+
128
+ def _find_config(self) -> Optional[Path]:
129
+ """Find moltbot config file."""
130
+ for path in self.CONFIG_LOCATIONS:
131
+ if path.exists():
132
+ return path
133
+ return None
134
+
135
+ def _check_running_process(self) -> Optional[Dict[str, Any]]:
136
+ """Check if moltbot process is running."""
137
+ try:
138
+ if os.name == "nt":
139
+ # Windows
140
+ proc = subprocess.run(
141
+ ["tasklist", "/FI", "IMAGENAME eq node.exe", "/FO", "CSV"],
142
+ capture_output=True,
143
+ text=True,
144
+ timeout=10,
145
+ )
146
+ # This is a rough check - would need more sophisticated detection
147
+ if "moltbot" in proc.stdout.lower():
148
+ return {"running": True}
149
+ else:
150
+ # Unix-like
151
+ proc = subprocess.run(
152
+ ["pgrep", "-f", "moltbot"],
153
+ capture_output=True,
154
+ text=True,
155
+ timeout=10,
156
+ )
157
+ if proc.returncode == 0 and proc.stdout.strip():
158
+ pids = proc.stdout.strip().split("\n")
159
+ return {"pid": pids[0]}
160
+
161
+ # Also check for node process with moltbot
162
+ proc = subprocess.run(
163
+ ["pgrep", "-af", "node.*moltbot"],
164
+ capture_output=True,
165
+ text=True,
166
+ timeout=10,
167
+ )
168
+ if proc.returncode == 0 and proc.stdout.strip():
169
+ return {"running": True}
170
+
171
+ except (subprocess.TimeoutExpired, FileNotFoundError):
172
+ pass
173
+
174
+ return None
175
+
176
+ def _check_gateway_active(self, port: int) -> bool:
177
+ """Check if moltbot gateway is listening on port."""
178
+ try:
179
+ import socket
180
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
181
+ sock.settimeout(1)
182
+ result = sock.connect_ex(("127.0.0.1", port))
183
+ sock.close()
184
+ return result == 0
185
+ except (socket.error, OSError):
186
+ return False
187
+
188
+ def get_conflicts(self) -> List[str]:
189
+ """Get potential conflicts with Tweek."""
190
+ conflicts = []
191
+
192
+ result = self.detect()
193
+ if result.detected:
194
+ if result.metadata.get("gateway_active"):
195
+ conflicts.append(
196
+ f"Moltbot gateway is active on port {result.port}. "
197
+ "This may intercept LLM API calls before Tweek."
198
+ )
199
+ elif result.running:
200
+ conflicts.append(
201
+ "Moltbot process is running. Gateway may start and "
202
+ "intercept LLM API calls."
203
+ )
204
+
205
+ return conflicts
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Tweek Windsurf Detector Plugin
4
+
5
+ Detects Windsurf AI-powered IDE (by Codeium):
6
+ - Application installation (macOS, Windows, Linux)
7
+ - Running process
8
+ - Configuration location
9
+ """
10
+
11
+ import os
12
+ import subprocess
13
+ import json
14
+ from pathlib import Path
15
+ from typing import Optional, List, Dict, Any
16
+ from tweek.plugins.base import ToolDetectorPlugin, DetectionResult
17
+
18
+
19
+ class WindsurfDetector(ToolDetectorPlugin):
20
+ """
21
+ Windsurf IDE detector.
22
+
23
+ Windsurf is an AI-powered IDE built by Codeium, featuring:
24
+ - Deep integration with AI assistants
25
+ - Code completion and generation
26
+ - Multi-file editing capabilities
27
+
28
+ Detects:
29
+ - Application installation
30
+ - Running Windsurf process
31
+ - Configuration and settings
32
+ """
33
+
34
+ VERSION = "1.0.0"
35
+ DESCRIPTION = "Detect Windsurf AI IDE (by Codeium)"
36
+ AUTHOR = "Tweek"
37
+ REQUIRES_LICENSE = "free"
38
+ TAGS = ["detector", "windsurf", "codeium", "ide", "ai"]
39
+
40
+ @property
41
+ def name(self) -> str:
42
+ return "windsurf"
43
+
44
+ def _get_install_paths(self) -> List[Path]:
45
+ """Get platform-specific installation paths."""
46
+ import platform
47
+ system = platform.system()
48
+
49
+ if system == "Darwin":
50
+ return [
51
+ Path("/Applications/Windsurf.app"),
52
+ Path.home() / "Applications" / "Windsurf.app",
53
+ ]
54
+ elif system == "Windows":
55
+ return [
56
+ Path(os.environ.get("LOCALAPPDATA", "")) / "Programs" / "Windsurf" / "Windsurf.exe",
57
+ Path(os.environ.get("PROGRAMFILES", "")) / "Windsurf" / "Windsurf.exe",
58
+ ]
59
+ else: # Linux
60
+ return [
61
+ Path("/usr/bin/windsurf"),
62
+ Path("/usr/local/bin/windsurf"),
63
+ Path.home() / ".local" / "bin" / "windsurf",
64
+ Path("/opt/Windsurf/windsurf"),
65
+ Path.home() / "Applications" / "Windsurf.AppImage",
66
+ ]
67
+
68
+ def _get_config_paths(self) -> List[Path]:
69
+ """Get platform-specific config paths."""
70
+ import platform
71
+ system = platform.system()
72
+
73
+ if system == "Darwin":
74
+ return [
75
+ Path.home() / "Library" / "Application Support" / "Windsurf",
76
+ Path.home() / ".windsurf",
77
+ Path.home() / ".config" / "Windsurf",
78
+ ]
79
+ elif system == "Windows":
80
+ return [
81
+ Path(os.environ.get("APPDATA", "")) / "Windsurf",
82
+ Path(os.environ.get("LOCALAPPDATA", "")) / "Windsurf",
83
+ ]
84
+ else: # Linux
85
+ return [
86
+ Path.home() / ".config" / "Windsurf",
87
+ Path.home() / ".windsurf",
88
+ ]
89
+
90
+ def detect(self) -> DetectionResult:
91
+ """
92
+ Detect Windsurf installation and status.
93
+ """
94
+ result = DetectionResult(
95
+ detected=False,
96
+ tool_name=self.name,
97
+ )
98
+
99
+ # Check installation paths
100
+ for path in self._get_install_paths():
101
+ if path.exists():
102
+ result.detected = True
103
+ result.install_path = str(path)
104
+ break
105
+
106
+ # Check config paths
107
+ for path in self._get_config_paths():
108
+ if path.exists():
109
+ result.detected = True
110
+ result.config_path = str(path)
111
+
112
+ # Try to get version from package.json or similar
113
+ version_file = path / "product.json"
114
+ if version_file.exists():
115
+ try:
116
+ with open(version_file) as f:
117
+ data = json.load(f)
118
+ result.version = data.get("version")
119
+ except (json.JSONDecodeError, IOError):
120
+ pass
121
+
122
+ # Also check settings.json for Codeium configuration
123
+ settings_file = path / "User" / "settings.json"
124
+ if settings_file.exists():
125
+ try:
126
+ with open(settings_file) as f:
127
+ settings = json.load(f)
128
+ result.metadata["has_settings"] = True
129
+ # Check if Codeium is configured
130
+ if any("codeium" in k.lower() for k in settings.keys()):
131
+ result.metadata["codeium_configured"] = True
132
+ except (json.JSONDecodeError, IOError):
133
+ pass
134
+ break
135
+
136
+ # Check if running
137
+ result.running = self._check_running()
138
+ if result.running:
139
+ result.detected = True
140
+
141
+ return result
142
+
143
+ def _check_running(self) -> bool:
144
+ """Check if Windsurf is running."""
145
+ import platform
146
+ system = platform.system()
147
+
148
+ try:
149
+ if system == "Darwin":
150
+ proc = subprocess.run(
151
+ ["pgrep", "-f", "Windsurf"],
152
+ capture_output=True,
153
+ text=True,
154
+ timeout=5,
155
+ )
156
+ return proc.returncode == 0 and proc.stdout.strip() != ""
157
+
158
+ elif system == "Windows":
159
+ proc = subprocess.run(
160
+ ["tasklist", "/FI", "IMAGENAME eq Windsurf.exe", "/FO", "CSV"],
161
+ capture_output=True,
162
+ text=True,
163
+ timeout=5,
164
+ )
165
+ return "Windsurf.exe" in proc.stdout
166
+
167
+ else: # Linux
168
+ proc = subprocess.run(
169
+ ["pgrep", "-f", "windsurf"],
170
+ capture_output=True,
171
+ text=True,
172
+ timeout=5,
173
+ )
174
+ return proc.returncode == 0 and proc.stdout.strip() != ""
175
+
176
+ except (subprocess.TimeoutExpired, FileNotFoundError):
177
+ pass
178
+
179
+ return False
180
+
181
+ def get_conflicts(self) -> List[str]:
182
+ """Get potential conflicts with Tweek."""
183
+ conflicts = []
184
+
185
+ result = self.detect()
186
+ if result.detected and result.running:
187
+ conflicts.append(
188
+ "Windsurf IDE is running. It makes direct API calls to Codeium servers. "
189
+ "Configure Windsurf to use Tweek proxy for protection."
190
+ )
191
+
192
+ return conflicts
193
+
194
+ def get_proxy_config_instructions(self) -> str:
195
+ """Get instructions for configuring Windsurf with Tweek proxy."""
196
+ return """
197
+ To protect Windsurf with Tweek proxy:
198
+
199
+ 1. Start Tweek proxy:
200
+ tweek proxy start
201
+
202
+ 2. Configure Windsurf to use proxy:
203
+ - Open Windsurf Settings (Cmd/Ctrl + ,)
204
+ - Search for "proxy"
205
+ - Set HTTP Proxy: http://127.0.0.1:9877
206
+ - Enable "Proxy Support"
207
+
208
+ 3. Or set environment variables before starting Windsurf:
209
+ export HTTPS_PROXY=http://127.0.0.1:9877
210
+ export HTTP_PROXY=http://127.0.0.1:9877
211
+
212
+ 4. Trust the Tweek CA certificate:
213
+ tweek proxy trust
214
+ """