mtrx-cli 0.1.13 → 0.1.14

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mtrx-cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "MATRX CLI for routing Codex, Claude, and Cursor through Matrx",
5
5
  "homepage": "https://mtrx.so",
6
6
  "repository": {
@@ -28,6 +28,7 @@
28
28
  "src/matrx/cli/cursor_ca.py",
29
29
  "src/matrx/cli/cursor_config.py",
30
30
  "src/matrx/cli/cursor_daemon.py",
31
+ "src/matrx/cli/cursor_launcher.py",
31
32
  "src/matrx/cli/cursor_proxy.py",
32
33
  "src/matrx/cli/cursor_service.py",
33
34
  "src/matrx/cli/launcher.py",
@@ -1 +1 @@
1
- __version__ = "0.1.13"
1
+ __version__ = "0.1.14"
@@ -0,0 +1,106 @@
1
+ """
2
+ Cross-platform launcher for Cursor IDE with proxy environment variables.
3
+
4
+ Cursor must be started with HTTP_PROXY, HTTPS_PROXY, and NODE_EXTRA_CA_CERTS
5
+ for the MITM proxy to work. Launching from Dock/Spotlight does not pass
6
+ these env vars; this module finds the Cursor executable and launches it
7
+ with the correct environment on any platform.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import logging
13
+ import os
14
+ import platform
15
+ import shutil
16
+ import subprocess
17
+ from pathlib import Path
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ def _cursor_executable_darwin() -> str | None:
23
+ """macOS: /Applications/Cursor.app/Contents/MacOS/Cursor."""
24
+ app = Path("/Applications/Cursor.app")
25
+ exe = app / "Contents" / "MacOS" / "Cursor"
26
+ if exe.exists():
27
+ return str(exe)
28
+ return None
29
+
30
+
31
+ def _cursor_executable_linux() -> str | None:
32
+ """Linux: cursor in PATH or common install locations."""
33
+ cursor = shutil.which("cursor")
34
+ if cursor:
35
+ return cursor
36
+ for path in (
37
+ Path.home() / ".local" / "share" / "cursor" / "bin" / "cursor",
38
+ Path.home() / ".local" / "bin" / "cursor",
39
+ ):
40
+ if path.exists():
41
+ return str(path)
42
+ return None
43
+
44
+
45
+ def _cursor_executable_windows() -> str | None:
46
+ """Windows: Cursor.exe in Local AppData."""
47
+ local = os.environ.get("LOCALAPPDATA", "")
48
+ if local:
49
+ for parts in (("Programs", "cursor", "Cursor.exe"), ("Cursor", "Cursor.exe")):
50
+ exe = Path(local) / Path(*parts)
51
+ if exe.exists():
52
+ return str(exe)
53
+ alt = Path(local) / "cursor" / "Cursor.exe"
54
+ if alt.exists():
55
+ return str(alt)
56
+ return None
57
+
58
+
59
+ def find_cursor_executable() -> str | None:
60
+ """Return the path to the Cursor executable for the current platform."""
61
+ system = platform.system()
62
+ if system == "Darwin":
63
+ return _cursor_executable_darwin()
64
+ if system == "Linux":
65
+ return _cursor_executable_linux()
66
+ if system == "Windows":
67
+ return _cursor_executable_windows()
68
+ return None
69
+
70
+
71
+ def launch_cursor_with_proxy(
72
+ proxy_url: str,
73
+ ca_cert_path: str,
74
+ ) -> bool:
75
+ """
76
+ Launch Cursor with HTTP_PROXY, HTTPS_PROXY, and NODE_EXTRA_CA_CERTS set.
77
+
78
+ Returns True if Cursor was launched, False if executable not found.
79
+ """
80
+ exe = find_cursor_executable()
81
+ if not exe:
82
+ return False
83
+
84
+ env = os.environ.copy()
85
+ env["HTTP_PROXY"] = proxy_url
86
+ env["HTTPS_PROXY"] = proxy_url
87
+ env["NODE_EXTRA_CA_CERTS"] = str(ca_cert_path)
88
+
89
+ kwargs: dict = {}
90
+ if platform.system() == "Windows":
91
+ kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS
92
+
93
+ try:
94
+ subprocess.Popen(
95
+ [exe],
96
+ env=env,
97
+ stdin=subprocess.DEVNULL,
98
+ stdout=subprocess.DEVNULL,
99
+ stderr=subprocess.DEVNULL,
100
+ start_new_session=(platform.system() != "Windows"),
101
+ **kwargs,
102
+ )
103
+ return True
104
+ except OSError as exc:
105
+ logger.warning("Failed to launch Cursor: %s", exc)
106
+ return False
@@ -120,6 +120,11 @@ def _build_parser() -> argparse.ArgumentParser:
120
120
  cursor.add_argument("--route", choices=["direct", "matrx"])
121
121
  cursor.add_argument("--status", action="store_true", help="Check proxy status")
122
122
  cursor.add_argument("--stop", action="store_true", help="Stop the proxy service")
123
+ cursor.add_argument(
124
+ "--launch",
125
+ action="store_true",
126
+ help="Launch Cursor with proxy env (required for traffic to flow)",
127
+ )
123
128
 
124
129
  return parser
125
130
 
@@ -841,6 +846,10 @@ def _cmd_cursor(args) -> int:
841
846
  trust_ca_system,
842
847
  )
843
848
  from matrx.cli.cursor_proxy import DEFAULT_PORT, PROXY_HOST
849
+ from matrx.cli.cursor_launcher import (
850
+ find_cursor_executable,
851
+ launch_cursor_with_proxy,
852
+ )
844
853
  from matrx.cli.cursor_service import (
845
854
  get_proxy_status,
846
855
  install_service,
@@ -963,10 +972,19 @@ def _cmd_cursor(args) -> int:
963
972
  print(f" ca_cert: {ca_cert_path()}")
964
973
  print(f" telemetry: {matrx_base_url}/v1/telemetry/cursor")
965
974
  print()
966
- if cursor_is_running():
967
- print(" Cursor is running restart it for settings to take effect.")
975
+
976
+ # Launch Cursor with proxy env vars (required for traffic to flow)
977
+ if getattr(args, "launch", False):
978
+ from matrx.cli.cursor_launcher import find_cursor_executable, launch_cursor_with_proxy
979
+
980
+ if launch_cursor_with_proxy(proxy_url, str(ca_cert_path())):
981
+ print(" Launched Cursor with proxy env vars — traffic will flow through MTRX.")
982
+ else:
983
+ print(" [warn] Could not launch Cursor. Is it installed?")
984
+ print(" To route traffic, launch Cursor via: mtrx cursor --launch")
968
985
  else:
969
- print(" Settings will apply next time Cursor starts.")
986
+ print(" To route traffic, launch Cursor via: mtrx cursor --launch")
987
+ print(" (Cursor must be started with proxy env vars; Dock/Spotlight launch won't work)")
970
988
  print()
971
989
  print(" Check status: mtrx cursor --status")
972
990
  print(" To disable: mtrx use cursor direct")