meshcode 2.8.4__tar.gz → 2.8.6__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.
Files changed (31) hide show
  1. {meshcode-2.8.4 → meshcode-2.8.6}/PKG-INFO +1 -1
  2. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/__init__.py +1 -1
  3. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/comms_v4.py +12 -1
  4. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/run_agent.py +53 -0
  5. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode.egg-info/PKG-INFO +1 -1
  6. {meshcode-2.8.4 → meshcode-2.8.6}/pyproject.toml +1 -1
  7. {meshcode-2.8.4 → meshcode-2.8.6}/README.md +0 -0
  8. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/cli.py +0 -0
  9. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/invites.py +0 -0
  10. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/launcher.py +0 -0
  11. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/launcher_install.py +0 -0
  12. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/meshcode_mcp/__init__.py +0 -0
  13. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/meshcode_mcp/__main__.py +0 -0
  14. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/meshcode_mcp/backend.py +0 -0
  15. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/meshcode_mcp/realtime.py +0 -0
  16. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/meshcode_mcp/server.py +0 -0
  17. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/meshcode_mcp/test_backend.py +0 -0
  18. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  19. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  20. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/preferences.py +0 -0
  21. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/protocol_v2.py +0 -0
  22. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/secrets.py +0 -0
  23. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/self_update.py +0 -0
  24. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode/setup_clients.py +0 -0
  25. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode.egg-info/SOURCES.txt +0 -0
  26. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode.egg-info/dependency_links.txt +0 -0
  27. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode.egg-info/entry_points.txt +0 -0
  28. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode.egg-info/requires.txt +0 -0
  29. {meshcode-2.8.4 → meshcode-2.8.6}/meshcode.egg-info/top_level.txt +0 -0
  30. {meshcode-2.8.4 → meshcode-2.8.6}/setup.cfg +0 -0
  31. {meshcode-2.8.4 → meshcode-2.8.6}/tests/test_status_enum_coverage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.8.4
3
+ Version: 2.8.6
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -1,2 +1,2 @@
1
1
  """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.8.4"
2
+ __version__ = "2.8.6"
@@ -1392,9 +1392,20 @@ def _start_heartbeat_daemon(project, name):
1392
1392
  " d=json.loads(urllib.request.urlopen(req,timeout=10).read())\n"
1393
1393
  " return d[0]['id'] if d else None\n"
1394
1394
  " except Exception: return None\n"
1395
+ "def check_still_leased(pid):\n"
1396
+ " \"\"\"Return False if force-disconnected (instance_id cleared).\"\"\"\n"
1397
+ " try:\n"
1398
+ " req=urllib.request.Request(url+'/rest/v1/mc_agents?select=instance_id&project_id=eq.'+pid+'&name=eq.'+urllib.parse.quote(name),\n"
1399
+ " headers={'apikey':key,'Authorization':'Bearer '+key,'Accept-Profile':'meshcode'})\n"
1400
+ " d=json.loads(urllib.request.urlopen(req,timeout=10).read())\n"
1401
+ " return bool(d and d[0].get('instance_id'))\n"
1402
+ " except Exception: return True\n"
1395
1403
  "pid=get_pid_for_project()\n"
1396
1404
  "while True:\n"
1397
- " if pid: post('/rest/v1/rpc/mc_heartbeat', {'p_project_id':pid,'p_agent_name':name})\n"
1405
+ " if pid:\n"
1406
+ " if not check_still_leased(pid):\n"
1407
+ " sys.exit(0)\n"
1408
+ " post('/rest/v1/rpc/mc_heartbeat', {'p_project_id':pid,'p_agent_name':name})\n"
1398
1409
  " time.sleep(30)\n"
1399
1410
  )
1400
1411
  # Windows: start_new_session kwarg doesn't exist. Use creationflags.
@@ -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()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.8.4
3
+ Version: 2.8.6
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meshcode"
7
- version = "2.8.4"
7
+ version = "2.8.6"
8
8
  description = "Real-time communication between AI agents — Supabase-backed CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes