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.
- tweek/__init__.py +16 -0
- tweek/cli.py +3390 -0
- tweek/cli_helpers.py +193 -0
- tweek/config/__init__.py +13 -0
- tweek/config/allowed_dirs.yaml +23 -0
- tweek/config/manager.py +1064 -0
- tweek/config/patterns.yaml +751 -0
- tweek/config/tiers.yaml +129 -0
- tweek/diagnostics.py +589 -0
- tweek/hooks/__init__.py +1 -0
- tweek/hooks/pre_tool_use.py +861 -0
- tweek/integrations/__init__.py +3 -0
- tweek/integrations/moltbot.py +243 -0
- tweek/licensing.py +398 -0
- tweek/logging/__init__.py +9 -0
- tweek/logging/bundle.py +350 -0
- tweek/logging/json_logger.py +150 -0
- tweek/logging/security_log.py +745 -0
- tweek/mcp/__init__.py +24 -0
- tweek/mcp/approval.py +456 -0
- tweek/mcp/approval_cli.py +356 -0
- tweek/mcp/clients/__init__.py +37 -0
- tweek/mcp/clients/chatgpt.py +112 -0
- tweek/mcp/clients/claude_desktop.py +203 -0
- tweek/mcp/clients/gemini.py +178 -0
- tweek/mcp/proxy.py +667 -0
- tweek/mcp/screening.py +175 -0
- tweek/mcp/server.py +317 -0
- tweek/platform/__init__.py +131 -0
- tweek/plugins/__init__.py +835 -0
- tweek/plugins/base.py +1080 -0
- tweek/plugins/compliance/__init__.py +30 -0
- tweek/plugins/compliance/gdpr.py +333 -0
- tweek/plugins/compliance/gov.py +324 -0
- tweek/plugins/compliance/hipaa.py +285 -0
- tweek/plugins/compliance/legal.py +322 -0
- tweek/plugins/compliance/pci.py +361 -0
- tweek/plugins/compliance/soc2.py +275 -0
- tweek/plugins/detectors/__init__.py +30 -0
- tweek/plugins/detectors/continue_dev.py +206 -0
- tweek/plugins/detectors/copilot.py +254 -0
- tweek/plugins/detectors/cursor.py +192 -0
- tweek/plugins/detectors/moltbot.py +205 -0
- tweek/plugins/detectors/windsurf.py +214 -0
- tweek/plugins/git_discovery.py +395 -0
- tweek/plugins/git_installer.py +491 -0
- tweek/plugins/git_lockfile.py +338 -0
- tweek/plugins/git_registry.py +503 -0
- tweek/plugins/git_security.py +482 -0
- tweek/plugins/providers/__init__.py +30 -0
- tweek/plugins/providers/anthropic.py +181 -0
- tweek/plugins/providers/azure_openai.py +289 -0
- tweek/plugins/providers/bedrock.py +248 -0
- tweek/plugins/providers/google.py +197 -0
- tweek/plugins/providers/openai.py +230 -0
- tweek/plugins/scope.py +130 -0
- tweek/plugins/screening/__init__.py +26 -0
- tweek/plugins/screening/llm_reviewer.py +149 -0
- tweek/plugins/screening/pattern_matcher.py +273 -0
- tweek/plugins/screening/rate_limiter.py +174 -0
- tweek/plugins/screening/session_analyzer.py +159 -0
- tweek/proxy/__init__.py +302 -0
- tweek/proxy/addon.py +223 -0
- tweek/proxy/interceptor.py +313 -0
- tweek/proxy/server.py +315 -0
- tweek/sandbox/__init__.py +71 -0
- tweek/sandbox/executor.py +382 -0
- tweek/sandbox/linux.py +278 -0
- tweek/sandbox/profile_generator.py +323 -0
- tweek/screening/__init__.py +13 -0
- tweek/screening/context.py +81 -0
- tweek/security/__init__.py +22 -0
- tweek/security/llm_reviewer.py +348 -0
- tweek/security/rate_limiter.py +682 -0
- tweek/security/secret_scanner.py +506 -0
- tweek/security/session_analyzer.py +600 -0
- tweek/vault/__init__.py +40 -0
- tweek/vault/cross_platform.py +251 -0
- tweek/vault/keychain.py +288 -0
- tweek-0.1.0.dist-info/METADATA +335 -0
- tweek-0.1.0.dist-info/RECORD +85 -0
- tweek-0.1.0.dist-info/WHEEL +5 -0
- tweek-0.1.0.dist-info/entry_points.txt +25 -0
- tweek-0.1.0.dist-info/licenses/LICENSE +190 -0
- 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
|
+
"""
|