mtrx-cli 0.1.11 → 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 +7 -2
- package/src/matrx/__init__.py +1 -1
- package/src/matrx/cli/cursor_ca.py +275 -0
- package/src/matrx/cli/cursor_config.py +262 -74
- package/src/matrx/cli/cursor_daemon.py +64 -0
- package/src/matrx/cli/cursor_launcher.py +106 -0
- package/src/matrx/cli/cursor_proxy.py +459 -261
- package/src/matrx/cli/cursor_service.py +343 -0
- package/src/matrx/cli/launcher.py +47 -27
- package/src/matrx/cli/main.py +156 -52
package/src/matrx/cli/main.py
CHANGED
|
@@ -32,10 +32,13 @@ from matrx.cli.launcher import (
|
|
|
32
32
|
)
|
|
33
33
|
from matrx.cli.cursor_config import (
|
|
34
34
|
configure_cursor_for_proxy,
|
|
35
|
+
configure_cursor_proxy_settings,
|
|
35
36
|
cursor_is_running,
|
|
37
|
+
cursor_settings_json_path,
|
|
36
38
|
cursor_state_db_path,
|
|
37
39
|
print_manual_setup_instructions,
|
|
38
40
|
read_cursor_settings,
|
|
41
|
+
restore_cursor_proxy_settings,
|
|
39
42
|
restore_cursor_settings,
|
|
40
43
|
)
|
|
41
44
|
from matrx.cli.state import (
|
|
@@ -74,7 +77,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
74
77
|
if args.command in {"codex", "claude"}:
|
|
75
78
|
return _cmd_launch(args.command, args.route, remainder)
|
|
76
79
|
if args.command == "cursor":
|
|
77
|
-
return _cmd_cursor(args
|
|
80
|
+
return _cmd_cursor(args)
|
|
78
81
|
|
|
79
82
|
parser.print_help()
|
|
80
83
|
return 1
|
|
@@ -115,6 +118,13 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
115
118
|
|
|
116
119
|
cursor = subparsers.add_parser("cursor")
|
|
117
120
|
cursor.add_argument("--route", choices=["direct", "matrx"])
|
|
121
|
+
cursor.add_argument("--status", action="store_true", help="Check proxy status")
|
|
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
|
+
)
|
|
118
128
|
|
|
119
129
|
return parser
|
|
120
130
|
|
|
@@ -495,19 +505,39 @@ def _cmd_use(args) -> int:
|
|
|
495
505
|
|
|
496
506
|
def _restore_cursor_if_needed() -> None:
|
|
497
507
|
import json as _json
|
|
508
|
+
|
|
509
|
+
from matrx.cli.cursor_service import is_proxy_running, uninstall_service
|
|
510
|
+
|
|
511
|
+
# Stop the MITM proxy service if it's running
|
|
512
|
+
if is_proxy_running():
|
|
513
|
+
uninstall_service()
|
|
514
|
+
print("MTRX Cursor proxy service stopped.")
|
|
515
|
+
|
|
516
|
+
# Restore settings.json (MITM proxy settings)
|
|
517
|
+
proxy_prev_path = config_dir() / "cursor-proxy-previous-settings.json"
|
|
518
|
+
if proxy_prev_path.exists():
|
|
519
|
+
try:
|
|
520
|
+
previous = _json.loads(proxy_prev_path.read_text(encoding="utf-8"))
|
|
521
|
+
if restore_cursor_proxy_settings(previous):
|
|
522
|
+
proxy_prev_path.unlink(missing_ok=True)
|
|
523
|
+
print("Cursor proxy settings restored.")
|
|
524
|
+
except Exception:
|
|
525
|
+
pass
|
|
526
|
+
|
|
527
|
+
# Restore state.vscdb (legacy Override Base URL settings)
|
|
498
528
|
prev_path = config_dir() / "cursor-previous-settings.json"
|
|
499
529
|
db_path = cursor_state_db_path()
|
|
500
|
-
if
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
530
|
+
if prev_path.exists() and db_path.exists():
|
|
531
|
+
try:
|
|
532
|
+
previous = _json.loads(prev_path.read_text(encoding="utf-8"))
|
|
533
|
+
if restore_cursor_settings(previous, db_path=db_path):
|
|
534
|
+
prev_path.unlink(missing_ok=True)
|
|
535
|
+
print("Cursor DB settings restored to previous values.")
|
|
536
|
+
else:
|
|
537
|
+
print("[warn] Could not auto-restore Cursor DB settings.")
|
|
538
|
+
except Exception:
|
|
539
|
+
pass
|
|
540
|
+
|
|
511
541
|
if cursor_is_running():
|
|
512
542
|
print(" Restart Cursor for settings to take effect.")
|
|
513
543
|
|
|
@@ -546,6 +576,11 @@ def _cmd_status() -> int:
|
|
|
546
576
|
location = config_status["config_path"] or "unknown"
|
|
547
577
|
verified_at = config_status["last_verified_at"] or "-"
|
|
548
578
|
print(f" {tool}: {status_label} ({location}, verified={verified_at})")
|
|
579
|
+
# Cursor proxy status
|
|
580
|
+
from matrx.cli.cursor_service import is_proxy_running
|
|
581
|
+
proxy_running = is_proxy_running()
|
|
582
|
+
print(f" cursor proxy: {'running' if proxy_running else 'not running'}")
|
|
583
|
+
|
|
549
584
|
print("Executables:")
|
|
550
585
|
print(f" codex: {find_executable('codex') or 'not found'}")
|
|
551
586
|
print(f" claude: {find_executable('claude') or 'not found'}")
|
|
@@ -800,32 +835,59 @@ def _cmd_launch(tool: str, route: str | None, remainder: list[str]) -> int:
|
|
|
800
835
|
return launch(plan)
|
|
801
836
|
|
|
802
837
|
|
|
803
|
-
def _cmd_cursor(
|
|
838
|
+
def _cmd_cursor(args) -> int:
|
|
839
|
+
import json as _json
|
|
840
|
+
|
|
841
|
+
from matrx.cli.cursor_ca import (
|
|
842
|
+
ca_cert_path,
|
|
843
|
+
ca_exists,
|
|
844
|
+
generate_ca,
|
|
845
|
+
is_ca_trusted,
|
|
846
|
+
trust_ca_system,
|
|
847
|
+
)
|
|
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
|
+
)
|
|
853
|
+
from matrx.cli.cursor_service import (
|
|
854
|
+
get_proxy_status,
|
|
855
|
+
install_service,
|
|
856
|
+
is_proxy_running,
|
|
857
|
+
uninstall_service,
|
|
858
|
+
)
|
|
859
|
+
|
|
860
|
+
route = args.route
|
|
861
|
+
|
|
862
|
+
# --status: just report proxy health
|
|
863
|
+
if args.status:
|
|
864
|
+
status = get_proxy_status()
|
|
865
|
+
if status:
|
|
866
|
+
print("MTRX Cursor proxy: running")
|
|
867
|
+
print(f" requests processed: {status.get('requests', '?')}")
|
|
868
|
+
else:
|
|
869
|
+
print("MTRX Cursor proxy: not running")
|
|
870
|
+
return 0
|
|
871
|
+
|
|
872
|
+
# --stop: tear down the proxy
|
|
873
|
+
if args.stop:
|
|
874
|
+
_restore_cursor_if_needed()
|
|
875
|
+
print("Cursor route set to direct — MTRX proxy disabled.")
|
|
876
|
+
return 0
|
|
877
|
+
|
|
804
878
|
state = load_state()
|
|
805
879
|
route, promoted = _maybe_promote_direct_route(state, "cursor", route)
|
|
806
880
|
effective_route = resolve_route(state, "cursor", route)
|
|
807
881
|
|
|
808
|
-
db_path = cursor_state_db_path()
|
|
809
|
-
|
|
810
882
|
if effective_route == "direct":
|
|
811
|
-
|
|
812
|
-
previous_json = config_dir() / "cursor-previous-settings.json"
|
|
813
|
-
if previous_json.exists():
|
|
814
|
-
import json as _json
|
|
815
|
-
try:
|
|
816
|
-
previous = _json.loads(previous_json.read_text(encoding="utf-8"))
|
|
817
|
-
if restore_cursor_settings(previous, db_path=db_path):
|
|
818
|
-
previous_json.unlink(missing_ok=True)
|
|
819
|
-
print("Cursor settings restored to previous values.")
|
|
820
|
-
else:
|
|
821
|
-
print("[warn] Could not restore Cursor settings automatically.")
|
|
822
|
-
except Exception:
|
|
823
|
-
pass
|
|
883
|
+
_restore_cursor_if_needed()
|
|
824
884
|
print("Cursor route set to direct — MTRX proxy disabled.")
|
|
825
885
|
if cursor_is_running():
|
|
826
886
|
print(" Restart Cursor for settings to take effect.")
|
|
827
887
|
return 0
|
|
828
888
|
|
|
889
|
+
# --- matrx route: set up the MITM proxy ---
|
|
890
|
+
|
|
829
891
|
try:
|
|
830
892
|
state, login_changed = _complete_matrx_login(state)
|
|
831
893
|
except ValueError as exc:
|
|
@@ -845,8 +907,9 @@ def _cmd_cursor(route: str | None) -> int:
|
|
|
845
907
|
print("No Matrx key available. Run: mtrx login matrx --key mx_...", file=sys.stderr)
|
|
846
908
|
return 1
|
|
847
909
|
|
|
848
|
-
matrx_base_url = ensure_root_url(
|
|
849
|
-
|
|
910
|
+
matrx_base_url = ensure_root_url(
|
|
911
|
+
state.get("auth", {}).get("matrx", {}).get("base_url")
|
|
912
|
+
)
|
|
850
913
|
|
|
851
914
|
if initialized or login_changed or promoted:
|
|
852
915
|
save_state(state)
|
|
@@ -856,34 +919,75 @@ def _cmd_cursor(route: str | None) -> int:
|
|
|
856
919
|
"Use `mtrx use cursor direct` to opt out.",
|
|
857
920
|
)
|
|
858
921
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
print(
|
|
862
|
-
|
|
922
|
+
# Step 1: Generate CA certificate if needed
|
|
923
|
+
if not ca_exists():
|
|
924
|
+
print("Generating MTRX CA certificate...")
|
|
925
|
+
generate_ca()
|
|
926
|
+
print(f" CA cert: {ca_cert_path()}")
|
|
927
|
+
|
|
928
|
+
# Step 2: Trust CA (one-time)
|
|
929
|
+
if not is_ca_trusted():
|
|
930
|
+
print("Trusting MTRX CA certificate (may require password)...")
|
|
931
|
+
if trust_ca_system():
|
|
932
|
+
print(" CA trusted in system keychain.")
|
|
933
|
+
else:
|
|
934
|
+
print(
|
|
935
|
+
f" [warn] Could not auto-trust CA. Cursor needs NODE_EXTRA_CA_CERTS={ca_cert_path()}"
|
|
936
|
+
)
|
|
937
|
+
print(
|
|
938
|
+
" You can manually trust it or set the env var before launching Cursor."
|
|
939
|
+
)
|
|
863
940
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
)
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
print(
|
|
870
|
-
|
|
941
|
+
# Step 3: Install and start the proxy service
|
|
942
|
+
proxy_url = f"http://{PROXY_HOST}:{DEFAULT_PORT}"
|
|
943
|
+
if is_proxy_running():
|
|
944
|
+
print(f"MTRX proxy already running on {proxy_url}")
|
|
945
|
+
else:
|
|
946
|
+
print("Starting MTRX Cursor proxy service...")
|
|
947
|
+
if install_service(
|
|
948
|
+
matrx_key=mx_key,
|
|
949
|
+
matrx_base_url=matrx_base_url,
|
|
950
|
+
host=PROXY_HOST,
|
|
951
|
+
port=DEFAULT_PORT,
|
|
952
|
+
):
|
|
953
|
+
print(f" Proxy running on {proxy_url}")
|
|
954
|
+
else:
|
|
955
|
+
print("[warn] Proxy service may not have started. Check logs at:")
|
|
956
|
+
print(f" {config_dir() / 'logs' / 'cursor-proxy.err.log'}")
|
|
871
957
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
958
|
+
# Step 4: Configure Cursor's settings.json
|
|
959
|
+
conf_dir = config_dir()
|
|
960
|
+
conf_dir.mkdir(parents=True, exist_ok=True)
|
|
961
|
+
|
|
962
|
+
previous = configure_cursor_proxy_settings(
|
|
963
|
+
proxy_url=proxy_url,
|
|
964
|
+
ca_cert_path=str(ca_cert_path()),
|
|
965
|
+
)
|
|
966
|
+
prev_path = conf_dir / "cursor-proxy-previous-settings.json"
|
|
967
|
+
prev_path.write_text(_json.dumps(previous), encoding="utf-8")
|
|
876
968
|
|
|
877
|
-
print("Cursor configured to route through MTRX.")
|
|
878
|
-
print(f" base_url: {proxy_url}")
|
|
879
|
-
print(f" api_key: {mask_secret(mx_key)}")
|
|
880
969
|
print()
|
|
881
|
-
|
|
882
|
-
|
|
970
|
+
print("Cursor configured to route ALL traffic through MTRX.")
|
|
971
|
+
print(f" proxy: {proxy_url}")
|
|
972
|
+
print(f" ca_cert: {ca_cert_path()}")
|
|
973
|
+
print(f" telemetry: {matrx_base_url}/v1/telemetry/cursor")
|
|
974
|
+
print()
|
|
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")
|
|
883
985
|
else:
|
|
884
|
-
print("
|
|
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)")
|
|
885
988
|
print()
|
|
886
|
-
print("
|
|
989
|
+
print(" Check status: mtrx cursor --status")
|
|
990
|
+
print(" To disable: mtrx use cursor direct")
|
|
887
991
|
return 0
|
|
888
992
|
|
|
889
993
|
|