meshcode 1.8.6__tar.gz → 1.8.8__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-1.8.6 → meshcode-1.8.8}/PKG-INFO +1 -1
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/__init__.py +1 -1
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/comms_v4.py +53 -4
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/invites.py +2 -2
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/meshcode_mcp/backend.py +2 -2
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/run_agent.py +10 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/setup_clients.py +2 -2
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-1.8.6 → meshcode-1.8.8}/pyproject.toml +1 -1
- {meshcode-1.8.6 → meshcode-1.8.8}/README.md +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/cli.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/launcher.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/launcher_install.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/preferences.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/protocol_v2.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/secrets.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode/self_update.py +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-1.8.6 → meshcode-1.8.8}/setup.cfg +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""MeshCode — Real-time communication between AI agents."""
|
|
2
|
-
__version__ = "1.8.
|
|
2
|
+
__version__ = "1.8.8"
|
|
@@ -47,8 +47,8 @@ from urllib.parse import quote
|
|
|
47
47
|
# Production defaults baked in. The publishable key is the anon/public key
|
|
48
48
|
# (RLS-protected, safe to ship — same one the frontend at meshcode.io uses
|
|
49
49
|
# in the browser). Override via env vars or ~/.meshcode/env if you self-host.
|
|
50
|
-
_DEFAULT_SUPABASE_URL = "https://
|
|
51
|
-
_DEFAULT_SUPABASE_KEY = "
|
|
50
|
+
_DEFAULT_SUPABASE_URL = "https://gjinagyyjttyxnaoavnz.supabase.co"
|
|
51
|
+
_DEFAULT_SUPABASE_KEY = "sb_publishable_qwN9PO1L7jUXhhbhhVk2CQ_z1FXG2Qf"
|
|
52
52
|
|
|
53
53
|
def _load_env_file():
|
|
54
54
|
"""Read SUPABASE_URL/KEY from ~/.meshcode/env if present (overrides defaults)."""
|
|
@@ -198,12 +198,61 @@ def ensure_sessions():
|
|
|
198
198
|
SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
|
|
199
199
|
|
|
200
200
|
|
|
201
|
+
def _load_api_key_for_cli() -> str:
|
|
202
|
+
"""Pull the user's api key from the keychain (or env fallback) so the
|
|
203
|
+
CLI can call SECURITY DEFINER RPCs that use api_key auth instead of
|
|
204
|
+
relying on the publishable anon key + RLS, which is what CLI verbs
|
|
205
|
+
used to do and which always failed because the CLI has no JWT context.
|
|
206
|
+
"""
|
|
207
|
+
# 1) explicit env override
|
|
208
|
+
k = os.environ.get("MESHCODE_API_KEY", "").strip()
|
|
209
|
+
if k:
|
|
210
|
+
return k
|
|
211
|
+
# 2) keychain via secrets module
|
|
212
|
+
try:
|
|
213
|
+
import importlib
|
|
214
|
+
secrets_mod = importlib.import_module("meshcode.secrets")
|
|
215
|
+
profile = os.environ.get("MESHCODE_KEYCHAIN_PROFILE") or secrets_mod.DEFAULT_PROFILE
|
|
216
|
+
key = secrets_mod.get_api_key(profile=profile) or ""
|
|
217
|
+
if key:
|
|
218
|
+
return key
|
|
219
|
+
except Exception:
|
|
220
|
+
pass
|
|
221
|
+
return ""
|
|
222
|
+
|
|
223
|
+
|
|
201
224
|
def get_project_id(project_name):
|
|
202
|
-
"""
|
|
225
|
+
"""Resolve a project's UUID for the authenticated CLI user.
|
|
226
|
+
|
|
227
|
+
Resolution order:
|
|
228
|
+
1. api_key + mc_resolve_project RPC (SECURITY DEFINER, the only
|
|
229
|
+
path that actually works for an authenticated CLI session)
|
|
230
|
+
2. legacy publishable-anon SELECT (only useful for shared/public
|
|
231
|
+
projects; will fail under RLS for owned projects)
|
|
232
|
+
3. legacy publishable-anon INSERT (will fail under RLS — kept as
|
|
233
|
+
last resort for backwards compat with very old test scripts)
|
|
234
|
+
"""
|
|
235
|
+
api_key = _load_api_key_for_cli()
|
|
236
|
+
if api_key:
|
|
237
|
+
try:
|
|
238
|
+
r = sb_rpc("mc_resolve_project", {
|
|
239
|
+
"p_api_key": api_key,
|
|
240
|
+
"p_project_name": project_name,
|
|
241
|
+
})
|
|
242
|
+
if isinstance(r, dict) and r.get("project_id"):
|
|
243
|
+
return r["project_id"]
|
|
244
|
+
# Some deployments return rows
|
|
245
|
+
if isinstance(r, list) and r and r[0].get("project_id"):
|
|
246
|
+
return r[0]["project_id"]
|
|
247
|
+
except Exception:
|
|
248
|
+
pass
|
|
249
|
+
|
|
203
250
|
rows = sb_select("mc_projects", f"name=eq.{quote(project_name)}")
|
|
204
251
|
if rows:
|
|
205
252
|
return rows[0]["id"]
|
|
206
|
-
|
|
253
|
+
|
|
254
|
+
# Last resort: try to create. Will fail under RLS for unauthenticated
|
|
255
|
+
# contexts, but kept for legacy callers + admin tooling.
|
|
207
256
|
result = sb_insert("mc_projects", {"name": project_name})
|
|
208
257
|
if result and len(result) > 0:
|
|
209
258
|
return result[0]["id"]
|
|
@@ -41,8 +41,8 @@ from urllib.request import Request, urlopen
|
|
|
41
41
|
# Supabase RPC helpers
|
|
42
42
|
# ============================================================
|
|
43
43
|
|
|
44
|
-
_DEFAULT_SUPABASE_URL = "https://
|
|
45
|
-
_DEFAULT_SUPABASE_KEY = "
|
|
44
|
+
_DEFAULT_SUPABASE_URL = "https://gjinagyyjttyxnaoavnz.supabase.co"
|
|
45
|
+
_DEFAULT_SUPABASE_KEY = "sb_publishable_qwN9PO1L7jUXhhbhhVk2CQ_z1FXG2Qf"
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
def _sb() -> Dict[str, str]:
|
|
@@ -13,8 +13,8 @@ from urllib.parse import quote
|
|
|
13
13
|
from urllib.request import Request, urlopen
|
|
14
14
|
|
|
15
15
|
# Bake in production defaults — RLS-protected publishable key, safe to ship.
|
|
16
|
-
_DEFAULT_SUPABASE_URL = "https://
|
|
17
|
-
_DEFAULT_SUPABASE_KEY = "
|
|
16
|
+
_DEFAULT_SUPABASE_URL = "https://gjinagyyjttyxnaoavnz.supabase.co"
|
|
17
|
+
_DEFAULT_SUPABASE_KEY = "sb_publishable_qwN9PO1L7jUXhhbhhVk2CQ_z1FXG2Qf"
|
|
18
18
|
|
|
19
19
|
def _load_env_file() -> Dict[str, str]:
|
|
20
20
|
env_path = Path.home() / ".meshcode" / "env"
|
|
@@ -112,6 +112,16 @@ def run(agent: str, project: Optional[str] = None, editor_override: Optional[str
|
|
|
112
112
|
except Exception:
|
|
113
113
|
pass
|
|
114
114
|
|
|
115
|
+
# Detect: are we already inside a Claude Code session? os.execvp(claude)
|
|
116
|
+
# from inside an existing claude won't work — claude needs a fresh
|
|
117
|
+
# interactive terminal it owns. Refuse with a clear message.
|
|
118
|
+
if os.environ.get("CLAUDECODE") == "1" or os.environ.get("CLAUDE_CODE_SESSION"):
|
|
119
|
+
print("[meshcode] ERROR: meshcode run cannot bootstrap a new agent from inside an", file=sys.stderr)
|
|
120
|
+
print("[meshcode] existing Claude Code session.", file=sys.stderr)
|
|
121
|
+
print("[meshcode] Open a fresh Terminal / iTerm window and run the command there.", file=sys.stderr)
|
|
122
|
+
print(f"[meshcode] (or copy this exact line into a new terminal: meshcode run {agent})", file=sys.stderr)
|
|
123
|
+
return 2
|
|
124
|
+
|
|
115
125
|
found = _find_agent_workspace(agent, project)
|
|
116
126
|
if not found:
|
|
117
127
|
return 2
|
|
@@ -93,9 +93,9 @@ def _load_supabase_env() -> Dict[str, str]:
|
|
|
93
93
|
elif k == "SUPABASE_KEY" and not key:
|
|
94
94
|
key = v
|
|
95
95
|
if not url:
|
|
96
|
-
url = "https://
|
|
96
|
+
url = "https://gjinagyyjttyxnaoavnz.supabase.co"
|
|
97
97
|
if not key:
|
|
98
|
-
key = "
|
|
98
|
+
key = "sb_publishable_qwN9PO1L7jUXhhbhhVk2CQ_z1FXG2Qf"
|
|
99
99
|
return {"SUPABASE_URL": url, "SUPABASE_KEY": key}
|
|
100
100
|
|
|
101
101
|
|
|
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
|