meshcode 2.8.3__tar.gz → 2.8.5__tar.gz
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.
- {meshcode-2.8.3 → meshcode-2.8.5}/PKG-INFO +1 -1
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/__init__.py +1 -1
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/comms_v4.py +18 -10
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/run_agent.py +53 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.8.3 → meshcode-2.8.5}/pyproject.toml +1 -1
- {meshcode-2.8.3 → meshcode-2.8.5}/README.md +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/cli.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/invites.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/launcher.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/launcher_install.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/preferences.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/secrets.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/self_update.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode/setup_clients.py +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/setup.cfg +0 -0
- {meshcode-2.8.3 → meshcode-2.8.5}/tests/test_status_enum_coverage.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""MeshCode — Real-time communication between AI agents."""
|
|
2
|
-
__version__ = "2.8.
|
|
2
|
+
__version__ = "2.8.5"
|
|
@@ -1426,10 +1426,10 @@ def _stop_heartbeat_daemon(project, name):
|
|
|
1426
1426
|
|
|
1427
1427
|
|
|
1428
1428
|
def connect_terminal(project, name, role=""):
|
|
1429
|
-
"""Bind THIS terminal to (project, agent). Calls
|
|
1430
|
-
starts a 30s heartbeat loop. MeshCode is mesh
|
|
1431
|
-
command does NOT spawn claude. The user must
|
|
1432
|
-
running in this terminal."""
|
|
1429
|
+
"""Bind THIS terminal to (project, agent). Calls mc_acquire_agent_lease RPC
|
|
1430
|
+
(ownership-validated) and starts a 30s heartbeat loop. MeshCode is mesh
|
|
1431
|
+
infrastructure only — this command does NOT spawn claude. The user must
|
|
1432
|
+
already have a claude session running in this terminal."""
|
|
1433
1433
|
ensure_sessions()
|
|
1434
1434
|
project_id = get_project_id(project)
|
|
1435
1435
|
if not project_id:
|
|
@@ -1452,12 +1452,20 @@ def connect_terminal(project, name, role=""):
|
|
|
1452
1452
|
"p_status": "needs_setup",
|
|
1453
1453
|
})
|
|
1454
1454
|
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
"
|
|
1460
|
-
|
|
1455
|
+
# Use mc_acquire_agent_lease (ownership-validated) instead of mc_connect_agent
|
|
1456
|
+
import uuid as _uuid
|
|
1457
|
+
_instance_id = f"{tty or 'no-tty'}-{ppid}-{_uuid.uuid4().hex[:8]}"
|
|
1458
|
+
if _api_key:
|
|
1459
|
+
rpc_result = sb_rpc("mc_acquire_agent_lease", {
|
|
1460
|
+
"p_api_key": _api_key,
|
|
1461
|
+
"p_project_id": project_id,
|
|
1462
|
+
"p_agent_name": name,
|
|
1463
|
+
"p_instance_id": _instance_id,
|
|
1464
|
+
})
|
|
1465
|
+
else:
|
|
1466
|
+
print("[ERROR] No API key found — cannot connect without authentication.")
|
|
1467
|
+
print("[ERROR] Run: meshcode setup-key")
|
|
1468
|
+
return
|
|
1461
1469
|
if rpc_result and rpc_result.get("error"):
|
|
1462
1470
|
print(f"[ERROR] {rpc_result['error']}")
|
|
1463
1471
|
return
|
|
@@ -32,6 +32,51 @@ WORKSPACES_ROOT = Path.home() / "meshcode"
|
|
|
32
32
|
REGISTRY_PATH = WORKSPACES_ROOT / ".registry.json"
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def _check_agent_ownership(agent: str, project: str) -> Optional[str]:
|
|
36
|
+
"""Pre-flight check: verify caller owns this agent before launching editor.
|
|
37
|
+
|
|
38
|
+
Returns an error message string if blocked, None if OK.
|
|
39
|
+
"""
|
|
40
|
+
try:
|
|
41
|
+
from .setup_clients import _load_supabase_env
|
|
42
|
+
import importlib
|
|
43
|
+
secrets_mod = importlib.import_module("meshcode.secrets")
|
|
44
|
+
except Exception:
|
|
45
|
+
return None # Can't check — let the RPC catch it later
|
|
46
|
+
|
|
47
|
+
profile = os.environ.get("MESHCODE_KEYCHAIN_PROFILE") or "default"
|
|
48
|
+
api_key = secrets_mod.get_api_key(profile=profile)
|
|
49
|
+
if not api_key:
|
|
50
|
+
return None # No key — RPC will reject later
|
|
51
|
+
|
|
52
|
+
sb = _load_supabase_env()
|
|
53
|
+
try:
|
|
54
|
+
from urllib.request import Request, urlopen
|
|
55
|
+
body = json.dumps({
|
|
56
|
+
"p_api_key": api_key,
|
|
57
|
+
"p_project_name": project,
|
|
58
|
+
"p_agent_name": agent,
|
|
59
|
+
}).encode()
|
|
60
|
+
req = Request(
|
|
61
|
+
f"{sb['SUPABASE_URL']}/rest/v1/rpc/mc_check_agent_ownership",
|
|
62
|
+
data=body,
|
|
63
|
+
method="POST",
|
|
64
|
+
headers={
|
|
65
|
+
"apikey": sb["SUPABASE_KEY"],
|
|
66
|
+
"Authorization": f"Bearer {sb['SUPABASE_KEY']}",
|
|
67
|
+
"Content-Type": "application/json",
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
with urlopen(req, timeout=10) as resp:
|
|
71
|
+
data = json.loads(resp.read().decode())
|
|
72
|
+
except Exception:
|
|
73
|
+
return None # Network error — let the RPC catch it later
|
|
74
|
+
|
|
75
|
+
if isinstance(data, dict) and data.get("error"):
|
|
76
|
+
return data["error"]
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
35
80
|
def _try_auto_setup(agent: str, project: Optional[str] = None) -> Optional[Tuple[Path, str]]:
|
|
36
81
|
"""If agent exists on the server but has no local workspace, auto-create it.
|
|
37
82
|
|
|
@@ -203,6 +248,14 @@ def run(agent: str, project: Optional[str] = None, editor_override: Optional[str
|
|
|
203
248
|
print(f"[meshcode] Run `meshcode setup <project> {agent}` first.", file=sys.stderr)
|
|
204
249
|
return 2
|
|
205
250
|
ws, resolved_project = found
|
|
251
|
+
|
|
252
|
+
# ── Ownership pre-check ──────────────────────────────────────────
|
|
253
|
+
# Before launching the editor, verify the caller owns this agent.
|
|
254
|
+
# This prevents hijacking another user's agent in shared meshworks.
|
|
255
|
+
ownership_err = _check_agent_ownership(agent, resolved_project)
|
|
256
|
+
if ownership_err:
|
|
257
|
+
print(f"[meshcode] ERROR: {ownership_err}", file=sys.stderr)
|
|
258
|
+
return 2
|
|
206
259
|
server_id = f"meshcode-{resolved_project}-{agent}"
|
|
207
260
|
|
|
208
261
|
editor = editor_override or _detect_editor()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|