meshcode 2.10.59__tar.gz → 2.10.61__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 (48) hide show
  1. {meshcode-2.10.59 → meshcode-2.10.61}/PKG-INFO +1 -1
  2. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/__init__.py +1 -1
  3. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/comms_v4.py +10 -1
  4. meshcode-2.10.61/meshcode/error_hints.py +74 -0
  5. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/meshcode_mcp/server.py +10 -0
  6. meshcode-2.10.61/meshcode/upload.py +125 -0
  7. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode.egg-info/PKG-INFO +1 -1
  8. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode.egg-info/SOURCES.txt +2 -0
  9. {meshcode-2.10.59 → meshcode-2.10.61}/pyproject.toml +1 -1
  10. {meshcode-2.10.59 → meshcode-2.10.61}/README.md +0 -0
  11. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/ascii_art.py +0 -0
  12. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/cli.py +0 -0
  13. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/compat.py +0 -0
  14. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/exceptions.py +0 -0
  15. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/invites.py +0 -0
  16. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/launcher.py +0 -0
  17. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/launcher_install.py +0 -0
  18. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/meshcode_mcp/__init__.py +0 -0
  19. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/meshcode_mcp/__main__.py +0 -0
  20. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/meshcode_mcp/backend.py +0 -0
  21. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/meshcode_mcp/realtime.py +0 -0
  22. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/meshcode_mcp/test_backend.py +0 -0
  23. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  24. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  25. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/preferences.py +0 -0
  26. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/protocol_v2.py +0 -0
  27. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/run_agent.py +0 -0
  28. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/secrets.py +0 -0
  29. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/self_update.py +0 -0
  30. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/setup_clients.py +0 -0
  31. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode/supervisor.py +0 -0
  32. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode.egg-info/dependency_links.txt +0 -0
  33. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode.egg-info/entry_points.txt +0 -0
  34. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode.egg-info/requires.txt +0 -0
  35. {meshcode-2.10.59 → meshcode-2.10.61}/meshcode.egg-info/top_level.txt +0 -0
  36. {meshcode-2.10.59 → meshcode-2.10.61}/setup.cfg +0 -0
  37. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_core.py +0 -0
  38. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_cross_agent_messaging.py +0 -0
  39. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_esc_deaf_state.py +0 -0
  40. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_exceptions.py +0 -0
  41. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_mark_read_batch.py +0 -0
  42. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_migration_integrity.py +0 -0
  43. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_realtime_event_freshness.py +0 -0
  44. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_rls_cross_tenant.py +0 -0
  45. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_rpc_migrations.py +0 -0
  46. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_security_regressions.py +0 -0
  47. {meshcode-2.10.59 → meshcode-2.10.61}/tests/test_sentinel.py +0 -0
  48. {meshcode-2.10.59 → meshcode-2.10.61}/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.10.59
3
+ Version: 2.10.61
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,5 +1,5 @@
1
1
  """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.10.59"
2
+ __version__ = "2.10.61"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -3324,6 +3324,15 @@ if __name__ == "__main__":
3324
3324
  from meshcode.launcher_install import main as _launcher_main # type: ignore
3325
3325
  sys.exit(_launcher_main(sys.argv[2:]))
3326
3326
 
3327
+ elif cmd == "upload":
3328
+ # meshcode upload <file>
3329
+ if len(pos) < 1:
3330
+ print("Usage: meshcode upload <file>")
3331
+ sys.exit(1)
3332
+ import importlib
3333
+ _upl = importlib.import_module("meshcode.upload")
3334
+ sys.exit(_upl.cmd_upload(pos[0]))
3335
+
3327
3336
  elif cmd in ("help", "--help", "-h"):
3328
3337
  show_help()
3329
3338
 
@@ -3360,7 +3369,7 @@ if __name__ == "__main__":
3360
3369
  "setup", "run", "go", "invite", "join", "invites", "members",
3361
3370
  "revoke-invite", "revoke-member", "login", "prefs", "launcher",
3362
3371
  "help", "init", "doctor", "compat", "upgrade", "profile", "validate-sessions", "wake-headless",
3363
- "supervisor",
3372
+ "supervisor", "upload",
3364
3373
  ]
3365
3374
  # Simple fuzzy: prefix match + Levenshtein-like best match
3366
3375
  suggestions = [c for c in known_cmds if c.startswith(cmd)]
@@ -0,0 +1,74 @@
1
+ """Smart error messages — maps common error patterns to actionable fix commands.
2
+
3
+ Usage:
4
+ from meshcode.error_hints import hint_for_error
5
+ print(hint_for_error("agent not found"))
6
+ # → "Run: meshcode register <project> <agent> <role>"
7
+ """
8
+
9
+ _HINTS = [
10
+ # Auth errors
11
+ ("invalid api_key", "Run: meshcode login <api_key> to set your credentials"),
12
+ ("api key", "Run: meshcode login <api_key> to refresh credentials"),
13
+ ("auth_failed", "Run: meshcode login to re-authenticate"),
14
+ ("forbidden", "You don't have permission. Check: meshcode doctor"),
15
+ ("not authenticated", "Run: meshcode login <api_key>"),
16
+
17
+ # Agent errors
18
+ ("agent not found", "Run: meshcode register <project> <agent_name> <role>"),
19
+ ("agent.*not registered", "Run: meshcode register <project> <agent_name> <role>"),
20
+
21
+ # Project errors
22
+ ("project.*not found", "Check project name with: meshcode projects"),
23
+ ("no projects found", "Create one at meshcode.io/dashboard or: meshcode init <project_name>"),
24
+
25
+ # Network errors
26
+ ("circuit breaker open", "Supabase is temporarily unavailable. Wait 30s and retry. Details: meshcode doctor"),
27
+ ("connection refused", "Check internet connection. If persists: meshcode doctor"),
28
+ ("network error", "Check internet connection. If persists: meshcode doctor"),
29
+ ("timeout", "Request timed out. Check connection: meshcode doctor"),
30
+
31
+ # MCP errors
32
+ ("MCP server crashed", "Restart: meshcode run <agent>"),
33
+ ("stdin EOF", "MCP pipe closed. Restart the MCP server or Claude Code session"),
34
+ ("mcp.*failed", "Check MCP config: meshcode doctor"),
35
+
36
+ # Task errors
37
+ ("task.*already claimed", "This task is being worked on. Try: meshcode tasks to see available tasks"),
38
+ ("task not found", "Check task ID. List tasks: meshcode tasks"),
39
+
40
+ # Config errors
41
+ ("comms_v4.py not found", "Reinstall: pip install --upgrade meshcode"),
42
+ ("\.mcp\.json", "Run: meshcode setup <project> <agent> to create config"),
43
+
44
+ # Token errors
45
+ ("token expired", "Generate a new token from the dashboard"),
46
+ ("token already used", "Generate a new token from the dashboard"),
47
+ ]
48
+
49
+
50
+ def hint_for_error(error_msg: str) -> str:
51
+ """Return an actionable fix suggestion for a given error message.
52
+
53
+ Returns empty string if no hint matches.
54
+ """
55
+ import re
56
+ lower = error_msg.lower()
57
+ for pattern, hint in _HINTS:
58
+ if re.search(pattern, lower):
59
+ return hint
60
+ return ""
61
+
62
+
63
+ def format_error(error_msg: str, prefix: str = "[meshcode]") -> str:
64
+ """Format an error with an actionable hint if available.
65
+
66
+ Example output:
67
+ [meshcode] ERROR: agent not found
68
+ [meshcode] Fix: Run: meshcode register <project> <agent_name> <role>
69
+ """
70
+ lines = [f"{prefix} ERROR: {error_msg}"]
71
+ hint = hint_for_error(error_msg)
72
+ if hint:
73
+ lines.append(f"{prefix} Fix: {hint}")
74
+ return "\n".join(lines)
@@ -2183,6 +2183,16 @@ def _mark_realtime_msgs_read_in_db(messages: List[Dict[str, Any]]) -> None:
2183
2183
  except Exception as e:
2184
2184
  log.debug(f"mark_read failed for msg {mid}: {e}")
2185
2185
 
2186
+ # Confirm delivery (best-effort, background) — completes the
2187
+ # delivery pipeline: sent → read → confirmed.
2188
+ try:
2189
+ be.sb_rpc("mc_confirm_delivery", {
2190
+ "p_api_key": api_key,
2191
+ "p_message_ids": msg_ids,
2192
+ })
2193
+ except Exception:
2194
+ pass # Non-critical: messages still work without confirmation
2195
+
2186
2196
 
2187
2197
  async def _meshcode_wait_inner(actual_timeout: int, include_acks: bool) -> Dict[str, Any]:
2188
2198
 
@@ -0,0 +1,125 @@
1
+ """MeshCode file upload — register metadata + upload to Supabase Storage."""
2
+ import os
3
+ import sys
4
+ import json
5
+ import mimetypes
6
+ from pathlib import Path
7
+ from urllib.request import Request, urlopen
8
+ from urllib.error import HTTPError
9
+
10
+
11
+ def upload_file(file_path: str, api_key: str, supabase_url: str, supabase_key: str) -> dict:
12
+ """Upload a file to MeshCode via Supabase Storage.
13
+
14
+ 1. Register file metadata via mc_register_file RPC
15
+ 2. Upload binary to Supabase Storage bucket
16
+ 3. Return file_id for task attachment
17
+
18
+ Returns: {"ok": True, "file_id": "...", "storage_path": "..."}
19
+ """
20
+ path = Path(file_path)
21
+ if not path.exists():
22
+ return {"error": f"file not found: {file_path}"}
23
+
24
+ file_name = path.name
25
+ mime_type = mimetypes.guess_type(file_name)[0] or "application/octet-stream"
26
+ size_bytes = path.stat().st_size
27
+
28
+ if size_bytes > 52428800:
29
+ return {"error": "file too large (max 50MB)"}
30
+
31
+ # 1. Register metadata
32
+ rpc_url = f"{supabase_url}/rest/v1/rpc/mc_register_file"
33
+ payload = json.dumps({
34
+ "p_api_key": api_key,
35
+ "p_file_name": file_name,
36
+ "p_mime_type": mime_type,
37
+ "p_size_bytes": size_bytes,
38
+ }).encode("utf-8")
39
+
40
+ req = Request(rpc_url, data=payload, method="POST")
41
+ req.add_header("apikey", supabase_key)
42
+ req.add_header("Content-Type", "application/json")
43
+
44
+ try:
45
+ with urlopen(req) as resp:
46
+ result = json.loads(resp.read())
47
+ except HTTPError as e:
48
+ body = e.read().decode("utf-8", errors="replace")
49
+ return {"error": f"register failed: {body[:200]}"}
50
+
51
+ if not result or result.get("error"):
52
+ return {"error": f"register failed: {result}"}
53
+
54
+ storage_path = result["storage_path"]
55
+ bucket = result.get("bucket", "meshcode-files")
56
+ file_id = result["file_id"]
57
+
58
+ # 2. Upload to Supabase Storage
59
+ storage_url = f"{supabase_url}/storage/v1/object/{bucket}/{storage_path}"
60
+ with open(path, "rb") as f:
61
+ file_data = f.read()
62
+
63
+ upload_req = Request(storage_url, data=file_data, method="POST")
64
+ upload_req.add_header("apikey", supabase_key)
65
+ upload_req.add_header("Authorization", f"Bearer {supabase_key}")
66
+ upload_req.add_header("Content-Type", mime_type)
67
+
68
+ try:
69
+ with urlopen(upload_req) as resp:
70
+ upload_result = json.loads(resp.read())
71
+ except HTTPError as e:
72
+ body = e.read().decode("utf-8", errors="replace")
73
+ return {"error": f"upload failed: {body[:200]}", "file_id": file_id, "note": "metadata registered but upload failed"}
74
+
75
+ return {
76
+ "ok": True,
77
+ "file_id": file_id,
78
+ "file_name": file_name,
79
+ "size_bytes": size_bytes,
80
+ "storage_path": storage_path,
81
+ "mime_type": mime_type,
82
+ }
83
+
84
+
85
+ def cmd_upload(file_path: str, project: str = None) -> int:
86
+ """CLI entry point for meshcode upload <file>."""
87
+ from meshcode.meshcode_mcp import backend as be
88
+
89
+ api_key = None
90
+ # Try to get API key from environment or config
91
+ env_key = os.environ.get("MESHCODE_API_KEY")
92
+ if env_key:
93
+ api_key = env_key
94
+ else:
95
+ # Try keychain profile
96
+ try:
97
+ profile_path = Path.home() / ".meshcode" / "profile_meta.json"
98
+ if profile_path.exists():
99
+ meta = json.loads(profile_path.read_text())
100
+ api_key = meta.get("api_key")
101
+ except Exception:
102
+ pass
103
+
104
+ if not api_key:
105
+ print("[meshcode upload] ERROR: No API key. Set MESHCODE_API_KEY or run meshcode login.")
106
+ return 1
107
+
108
+ print(f"[meshcode upload] Uploading {file_path}...")
109
+ result = upload_file(
110
+ file_path=file_path,
111
+ api_key=api_key,
112
+ supabase_url=be.SUPABASE_URL,
113
+ supabase_key=be.SUPABASE_KEY,
114
+ )
115
+
116
+ if result.get("ok"):
117
+ print(f"[meshcode upload] Success!")
118
+ print(f" file_id: {result['file_id']}")
119
+ print(f" file_name: {result['file_name']}")
120
+ print(f" size: {result['size_bytes']} bytes")
121
+ print(f" path: {result['storage_path']}")
122
+ return 0
123
+ else:
124
+ print(f"[meshcode upload] ERROR: {result.get('error', 'unknown error')}")
125
+ return 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.10.59
3
+ Version: 2.10.61
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -5,6 +5,7 @@ meshcode/ascii_art.py
5
5
  meshcode/cli.py
6
6
  meshcode/comms_v4.py
7
7
  meshcode/compat.py
8
+ meshcode/error_hints.py
8
9
  meshcode/exceptions.py
9
10
  meshcode/invites.py
10
11
  meshcode/launcher.py
@@ -16,6 +17,7 @@ meshcode/secrets.py
16
17
  meshcode/self_update.py
17
18
  meshcode/setup_clients.py
18
19
  meshcode/supervisor.py
20
+ meshcode/upload.py
19
21
  meshcode.egg-info/PKG-INFO
20
22
  meshcode.egg-info/SOURCES.txt
21
23
  meshcode.egg-info/dependency_links.txt
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meshcode"
7
- version = "2.10.59"
7
+ version = "2.10.61"
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