meshcode 2.0.4__tar.gz → 2.0.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.0.4 → meshcode-2.0.5}/PKG-INFO +1 -1
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/__init__.py +1 -1
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/comms_v4.py +25 -10
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/meshcode_mcp/backend.py +12 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/meshcode_mcp/server.py +26 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.0.4 → meshcode-2.0.5}/pyproject.toml +1 -1
- {meshcode-2.0.4 → meshcode-2.0.5}/README.md +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/cli.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/invites.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/launcher.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/launcher_install.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/preferences.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/run_agent.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/secrets.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/self_update.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode/setup_clients.py +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.0.4 → meshcode-2.0.5}/setup.cfg +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""MeshCode — Real-time communication between AI agents."""
|
|
2
|
-
__version__ = "2.0.
|
|
2
|
+
__version__ = "2.0.5"
|
|
@@ -1634,14 +1634,15 @@ STATUS:
|
|
|
1634
1634
|
HISTORY:
|
|
1635
1635
|
history <proj> [count] [agent1,agent2] Conversation log
|
|
1636
1636
|
|
|
1637
|
-
|
|
1638
|
-
|
|
1637
|
+
QUICK START:
|
|
1638
|
+
go <agent> [--project <name>] One command to connect (recommended)
|
|
1639
1639
|
login <api_key> Authenticate with API key
|
|
1640
1640
|
|
|
1641
|
-
|
|
1642
|
-
setup <
|
|
1643
|
-
|
|
1644
|
-
|
|
1641
|
+
SETUP (advanced):
|
|
1642
|
+
setup <proj> <name> [role] Create workspace (auto by 'go')
|
|
1643
|
+
run <agent> [--project <name>] Launch agent (auto by 'go')
|
|
1644
|
+
setup <client> <proj> <name> [role] Legacy: global MCP config
|
|
1645
|
+
Clients: claude-desktop
|
|
1645
1646
|
|
|
1646
1647
|
CLEANUP:
|
|
1647
1648
|
clear <proj> <name> Clear inbox
|
|
@@ -2042,10 +2043,11 @@ if __name__ == "__main__":
|
|
|
2042
2043
|
_setup_dispatcher = importlib.import_module("meshcode.setup_clients").setup
|
|
2043
2044
|
sys.exit(_setup_dispatcher(*sys.argv[2:]))
|
|
2044
2045
|
|
|
2045
|
-
elif cmd
|
|
2046
|
-
# meshcode
|
|
2046
|
+
elif cmd in ("run", "go"):
|
|
2047
|
+
# meshcode go <agent> [--project <name>] [--editor claude|cursor|code]
|
|
2048
|
+
# meshcode run <agent> (backwards compat, same as go)
|
|
2047
2049
|
if len(sys.argv) < 3:
|
|
2048
|
-
print("Usage: meshcode
|
|
2050
|
+
print(f"Usage: meshcode {cmd} <agent> [--project <name>] [--editor claude|cursor|code]")
|
|
2049
2051
|
sys.exit(1)
|
|
2050
2052
|
agent = sys.argv[2]
|
|
2051
2053
|
proj_override = flags.get("project")
|
|
@@ -2055,6 +2057,19 @@ if __name__ == "__main__":
|
|
|
2055
2057
|
perm_override = "bypass"
|
|
2056
2058
|
elif "--safe" in sys.argv:
|
|
2057
2059
|
perm_override = "safe"
|
|
2060
|
+
# Auth pre-check: if not logged in, prompt inline
|
|
2061
|
+
api_key = _load_api_key_for_cli()
|
|
2062
|
+
if not api_key:
|
|
2063
|
+
print("[meshcode] Not logged in. Get your API key at: https://meshcode.io/settings")
|
|
2064
|
+
try:
|
|
2065
|
+
api_key = input("[meshcode] Paste your API key (mc_...): ").strip()
|
|
2066
|
+
except (EOFError, KeyboardInterrupt):
|
|
2067
|
+
api_key = ""
|
|
2068
|
+
if api_key:
|
|
2069
|
+
login(api_key)
|
|
2070
|
+
else:
|
|
2071
|
+
print("[meshcode] Login required. Run: meshcode login <api_key>")
|
|
2072
|
+
sys.exit(1)
|
|
2058
2073
|
import importlib
|
|
2059
2074
|
_run = importlib.import_module("meshcode.run_agent").run
|
|
2060
2075
|
sys.exit(_run(agent, project=proj_override, editor_override=editor_override, permission_override=perm_override))
|
|
@@ -2198,7 +2213,7 @@ if __name__ == "__main__":
|
|
|
2198
2213
|
"register", "send", "broadcast", "read", "check", "watch",
|
|
2199
2214
|
"board", "update", "status", "projects", "list", "ls",
|
|
2200
2215
|
"history", "clear", "unregister", "connect", "disconnect",
|
|
2201
|
-
"setup", "run", "invite", "join", "invites", "members",
|
|
2216
|
+
"setup", "run", "go", "invite", "join", "invites", "members",
|
|
2202
2217
|
"revoke-invite", "revoke-member", "login", "prefs", "launcher",
|
|
2203
2218
|
"help", "profile", "validate-sessions", "wake-headless",
|
|
2204
2219
|
]
|
|
@@ -307,6 +307,18 @@ def task_complete(api_key, project_id, task_id, completing_agent, summary=""):
|
|
|
307
307
|
})
|
|
308
308
|
|
|
309
309
|
|
|
310
|
+
def record_event(api_key, project_id, agent_name, session_id, event_type, payload=None):
|
|
311
|
+
"""Fire-and-forget event recording for session replay."""
|
|
312
|
+
return sb_rpc("mc_record_event", {
|
|
313
|
+
"p_api_key": api_key,
|
|
314
|
+
"p_project_id": project_id,
|
|
315
|
+
"p_agent_name": agent_name,
|
|
316
|
+
"p_session_id": session_id,
|
|
317
|
+
"p_event_type": event_type,
|
|
318
|
+
"p_payload": payload or {},
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
|
|
310
322
|
def get_history(project_id: str, limit: int = 20) -> List[Dict]:
|
|
311
323
|
return sb_select(
|
|
312
324
|
"mc_messages",
|
|
@@ -145,6 +145,28 @@ def _split_messages(messages: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
|
145
145
|
from . import backend as be
|
|
146
146
|
from .realtime import RealtimeListener
|
|
147
147
|
|
|
148
|
+
# ============================================================
|
|
149
|
+
# Session Replay: unique session ID per MCP server boot.
|
|
150
|
+
# Events are recorded in background threads (fire-and-forget).
|
|
151
|
+
# ============================================================
|
|
152
|
+
import uuid as _uuid
|
|
153
|
+
_SESSION_ID = str(_uuid.uuid4())[:12]
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _record_event_bg(event_type: str, payload: dict = None) -> None:
|
|
157
|
+
"""Fire-and-forget: record a session event in background thread."""
|
|
158
|
+
try:
|
|
159
|
+
api_key = _get_api_key()
|
|
160
|
+
import threading
|
|
161
|
+
threading.Thread(
|
|
162
|
+
target=be.record_event,
|
|
163
|
+
args=(api_key, _PROJECT_ID, AGENT_NAME, _SESSION_ID, event_type, payload or {}),
|
|
164
|
+
daemon=True,
|
|
165
|
+
).start()
|
|
166
|
+
except Exception:
|
|
167
|
+
pass
|
|
168
|
+
|
|
169
|
+
|
|
148
170
|
# ============================================================
|
|
149
171
|
# Hot-reload: detect when backend.py changes on disk (e.g. after
|
|
150
172
|
# pip install --upgrade meshcode) and reload without restart.
|
|
@@ -349,6 +371,7 @@ def with_working_status(func):
|
|
|
349
371
|
_check_hot_reload()
|
|
350
372
|
if not skip:
|
|
351
373
|
_schedule_flip("working", name)
|
|
374
|
+
_record_event_bg("tool_call", {"tool": name, "args_keys": list(kwargs.keys())})
|
|
352
375
|
try:
|
|
353
376
|
return await func(*args, **kwargs)
|
|
354
377
|
finally:
|
|
@@ -361,6 +384,7 @@ def with_working_status(func):
|
|
|
361
384
|
_check_hot_reload()
|
|
362
385
|
if not skip:
|
|
363
386
|
_schedule_flip("working", name)
|
|
387
|
+
_record_event_bg("tool_call", {"tool": name, "args_keys": list(kwargs.keys())})
|
|
364
388
|
try:
|
|
365
389
|
return func(*args, **kwargs)
|
|
366
390
|
finally:
|
|
@@ -694,9 +718,11 @@ async def lifespan(_app):
|
|
|
694
718
|
hb_thread = _threading.Thread(target=_heartbeat_thread_fn, daemon=True, name="meshcode-heartbeat")
|
|
695
719
|
hb_thread.start()
|
|
696
720
|
log.info(f"lifespan started — Realtime + heartbeat thread active for {AGENT_NAME}")
|
|
721
|
+
_record_event_bg("boot", {"agent": AGENT_NAME, "project": PROJECT_NAME, "session_id": _SESSION_ID})
|
|
697
722
|
try:
|
|
698
723
|
yield {"realtime": _REALTIME}
|
|
699
724
|
finally:
|
|
725
|
+
_record_event_bg("shutdown", {"agent": AGENT_NAME, "session_id": _SESSION_ID})
|
|
700
726
|
log.info("lifespan shutdown — stopping heartbeat + realtime + releasing lease")
|
|
701
727
|
_heartbeat_stop.set()
|
|
702
728
|
hb_thread.join(timeout=5)
|
|
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
|