meshcode 2.10.62__tar.gz → 2.10.64__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.10.62 → meshcode-2.10.64}/PKG-INFO +1 -1
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/__init__.py +1 -1
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/comms_v4.py +30 -2
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/meshcode_mcp/server.py +40 -5
- meshcode-2.10.64/meshcode/quickstart.py +148 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode.egg-info/SOURCES.txt +1 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/pyproject.toml +1 -1
- {meshcode-2.10.62 → meshcode-2.10.64}/README.md +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/ascii_art.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/cli.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/compat.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/error_hints.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/exceptions.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/invites.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/launcher.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/launcher_install.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/preferences.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/run_agent.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/secrets.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/self_update.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/setup_clients.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/supervisor.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode/upload.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/setup.cfg +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_core.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_exceptions.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_migration_integrity.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_security_regressions.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_sentinel.py +0 -0
- {meshcode-2.10.62 → meshcode-2.10.64}/tests/test_status_enum_coverage.py +0 -0
|
@@ -2024,8 +2024,31 @@ def cmd_doctor(flags, pos):
|
|
|
2024
2024
|
except Exception as e:
|
|
2025
2025
|
fail("Supabase API", f"unreachable: {e}")
|
|
2026
2026
|
|
|
2027
|
-
#
|
|
2027
|
+
# 4b. API key validity
|
|
2028
2028
|
api_key = _load_api_key_for_cli()
|
|
2029
|
+
if api_key:
|
|
2030
|
+
try:
|
|
2031
|
+
result = sb_rpc("mc_validate_api_key", {"p_api_key": api_key})
|
|
2032
|
+
if isinstance(result, dict) and result.get("ok"):
|
|
2033
|
+
ok("API key", "valid")
|
|
2034
|
+
elif isinstance(result, dict) and result.get("error"):
|
|
2035
|
+
fail("API key", f"invalid: {result.get('error')}. Run: meshcode login <new_key>")
|
|
2036
|
+
else:
|
|
2037
|
+
ok("API key", "accepted (validation RPC may not exist)")
|
|
2038
|
+
except Exception:
|
|
2039
|
+
ok("API key", "present (could not validate)")
|
|
2040
|
+
else:
|
|
2041
|
+
fail("API key", "not found. Run: meshcode login <api_key>")
|
|
2042
|
+
|
|
2043
|
+
# 4c. MCP server import test
|
|
2044
|
+
try:
|
|
2045
|
+
import importlib
|
|
2046
|
+
_mod = importlib.import_module("meshcode.meshcode_mcp.server")
|
|
2047
|
+
ok("MCP server", "module imports cleanly")
|
|
2048
|
+
except Exception as e:
|
|
2049
|
+
fail("MCP server", f"import error: {e}. Run: pip install --upgrade meshcode")
|
|
2050
|
+
|
|
2051
|
+
# 5. Stale agents check (requires auth)
|
|
2029
2052
|
if api_key:
|
|
2030
2053
|
try:
|
|
2031
2054
|
# Try listing all projects for this user
|
|
@@ -3314,6 +3337,11 @@ if __name__ == "__main__":
|
|
|
3314
3337
|
elif cmd == "doctor":
|
|
3315
3338
|
cmd_doctor(flags, pos)
|
|
3316
3339
|
|
|
3340
|
+
elif cmd == "quickstart":
|
|
3341
|
+
import importlib
|
|
3342
|
+
_qs = importlib.import_module("meshcode.quickstart")
|
|
3343
|
+
sys.exit(_qs.cmd_quickstart())
|
|
3344
|
+
|
|
3317
3345
|
elif cmd == "launcher":
|
|
3318
3346
|
# meshcode launcher {install|uninstall|start|stop|restart|status|logs|test}
|
|
3319
3347
|
try:
|
|
@@ -3369,7 +3397,7 @@ if __name__ == "__main__":
|
|
|
3369
3397
|
"setup", "run", "go", "invite", "join", "invites", "members",
|
|
3370
3398
|
"revoke-invite", "revoke-member", "login", "prefs", "launcher",
|
|
3371
3399
|
"help", "init", "doctor", "compat", "upgrade", "profile", "validate-sessions", "wake-headless",
|
|
3372
|
-
"supervisor", "upload",
|
|
3400
|
+
"supervisor", "upload", "quickstart",
|
|
3373
3401
|
]
|
|
3374
3402
|
# Simple fuzzy: prefix match + Levenshtein-like best match
|
|
3375
3403
|
suggestions = [c for c in known_cmds if c.startswith(cmd)]
|
|
@@ -684,6 +684,33 @@ def _auto_learn_error(tool_name: str, error: Exception, args_keys: list) -> None
|
|
|
684
684
|
pass # Never let error-learning itself cause failures
|
|
685
685
|
|
|
686
686
|
|
|
687
|
+
# ── Activity feed auto-logger ──────────────────────────────────
|
|
688
|
+
# Logs tool calls to mc_activity for the live dashboard feed.
|
|
689
|
+
# Background thread, fire-and-forget — never blocks tool execution.
|
|
690
|
+
_ACTIVITY_LOG_SKIP = {"meshcode_wait", "meshcode_check", "meshcode_set_status",
|
|
691
|
+
"meshcode_recall", "meshcode_recall_keys", "meshcode_recall_search",
|
|
692
|
+
"meshcode_health", "meshcode_status", "meshcode_debug_sleep"}
|
|
693
|
+
|
|
694
|
+
def _log_activity_bg(event_type: str, summary: str) -> None:
|
|
695
|
+
"""Fire-and-forget activity logging in background thread."""
|
|
696
|
+
try:
|
|
697
|
+
import threading
|
|
698
|
+
def _do():
|
|
699
|
+
try:
|
|
700
|
+
api_key = _get_api_key()
|
|
701
|
+
if api_key:
|
|
702
|
+
be.sb_rpc("mc_log_activity", {
|
|
703
|
+
"p_api_key": api_key,
|
|
704
|
+
"p_event_type": event_type,
|
|
705
|
+
"p_summary": summary[:200],
|
|
706
|
+
})
|
|
707
|
+
except Exception:
|
|
708
|
+
pass
|
|
709
|
+
threading.Thread(target=_do, daemon=True).start()
|
|
710
|
+
except Exception:
|
|
711
|
+
pass
|
|
712
|
+
|
|
713
|
+
|
|
687
714
|
def with_working_status(func):
|
|
688
715
|
name = func.__name__
|
|
689
716
|
skip = (name == "meshcode_wait")
|
|
@@ -700,11 +727,12 @@ def with_working_status(func):
|
|
|
700
727
|
_est_tokens = sum(len(str(v)) for v in kwargs.values()) // 4
|
|
701
728
|
_record_event_bg("tool_call", {"tool": name, "args_keys": list(kwargs.keys()), "estimated_tokens": _est_tokens})
|
|
702
729
|
try:
|
|
703
|
-
|
|
730
|
+
result = await func(*args, **kwargs)
|
|
731
|
+
# Auto-log to activity feed (skip noisy read-only tools)
|
|
732
|
+
if not skip and name not in _ACTIVITY_LOG_SKIP:
|
|
733
|
+
_log_activity_bg("tool_call", f"{AGENT_NAME}: {name}")
|
|
734
|
+
return result
|
|
704
735
|
except asyncio.CancelledError:
|
|
705
|
-
# ESC in Claude Code cancels the in-flight task. Catch here
|
|
706
|
-
# to prevent cascade through FastMCP into the event loop.
|
|
707
|
-
# Return an error dict instead of propagating BaseException.
|
|
708
736
|
log.debug(f"[meshcode] tool {name} cancelled by client (ESC)")
|
|
709
737
|
return {"error": "cancelled_by_client", "tool": name}
|
|
710
738
|
except Exception as e:
|
|
@@ -728,7 +756,10 @@ def with_working_status(func):
|
|
|
728
756
|
_est_tokens = sum(len(str(v)) for v in kwargs.values()) // 4
|
|
729
757
|
_record_event_bg("tool_call", {"tool": name, "args_keys": list(kwargs.keys()), "estimated_tokens": _est_tokens})
|
|
730
758
|
try:
|
|
731
|
-
|
|
759
|
+
result = func(*args, **kwargs)
|
|
760
|
+
if not skip and name not in _ACTIVITY_LOG_SKIP:
|
|
761
|
+
_log_activity_bg("tool_call", f"{AGENT_NAME}: {name}")
|
|
762
|
+
return result
|
|
732
763
|
except Exception as e:
|
|
733
764
|
if not skip:
|
|
734
765
|
_auto_learn_error(name, e, list(kwargs.keys()))
|
|
@@ -1506,6 +1537,7 @@ async def lifespan(_app):
|
|
|
1506
1537
|
be.sb_rpc("mc_heartbeat", {"p_project_id": _PROJECT_ID, "p_agent_name": AGENT_NAME, "p_version": _SDK_VERSION})
|
|
1507
1538
|
be.set_status(_PROJECT_ID, AGENT_NAME, "idle", "MCP session active", api_key=_get_api_key())
|
|
1508
1539
|
log.info(f"[meshcode] Agent {AGENT_NAME} online — initial heartbeat sent")
|
|
1540
|
+
_log_activity_bg("agent_online", f"{AGENT_NAME} came online")
|
|
1509
1541
|
break
|
|
1510
1542
|
except Exception as e:
|
|
1511
1543
|
log.warning(f"initial heartbeat attempt {_attempt+1} failed: {e}")
|
|
@@ -2072,6 +2104,9 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
|
|
|
2072
2104
|
# Real message arrived — return to agent for processing
|
|
2073
2105
|
_set_state("online", "")
|
|
2074
2106
|
_CONSECUTIVE_IDLE_SECONDS = 0
|
|
2107
|
+
_msg_count = len(result.get("messages", []))
|
|
2108
|
+
if _msg_count:
|
|
2109
|
+
_log_activity_bg("message_delivered", f"{AGENT_NAME} received {_msg_count} message(s)")
|
|
2075
2110
|
break
|
|
2076
2111
|
|
|
2077
2112
|
if result.get("timed_out"):
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""MeshCode Quickstart Wizard — one command to go from zero to running agent.
|
|
2
|
+
|
|
3
|
+
Usage: meshcode quickstart
|
|
4
|
+
|
|
5
|
+
Flow:
|
|
6
|
+
1. Ask for API key (or detect from config)
|
|
7
|
+
2. Ask for project name (or create new)
|
|
8
|
+
3. Ask for agent name + role
|
|
9
|
+
4. Auto-run: register → setup → run
|
|
10
|
+
"""
|
|
11
|
+
import sys
|
|
12
|
+
import os
|
|
13
|
+
import json
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _input_with_default(prompt: str, default: str = "") -> str:
|
|
18
|
+
"""Input with default value shown in brackets."""
|
|
19
|
+
if default:
|
|
20
|
+
raw = input(f"{prompt} [{default}]: ").strip()
|
|
21
|
+
return raw if raw else default
|
|
22
|
+
return input(f"{prompt}: ").strip()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def cmd_quickstart() -> int:
|
|
26
|
+
"""Interactive quickstart wizard."""
|
|
27
|
+
print()
|
|
28
|
+
print(" ╔══════════════════════════════════════╗")
|
|
29
|
+
print(" ║ MeshCode Quickstart Wizard ║")
|
|
30
|
+
print(" ║ From zero to running agent in 60s ║")
|
|
31
|
+
print(" ╚══════════════════════════════════════╝")
|
|
32
|
+
print()
|
|
33
|
+
|
|
34
|
+
# Step 1: API key
|
|
35
|
+
config_dir = Path.home() / ".meshcode"
|
|
36
|
+
existing_key = None
|
|
37
|
+
try:
|
|
38
|
+
profile = config_dir / "profile_meta.json"
|
|
39
|
+
if profile.exists():
|
|
40
|
+
meta = json.loads(profile.read_text())
|
|
41
|
+
existing_key = meta.get("api_key")
|
|
42
|
+
email = meta.get("email", "unknown")
|
|
43
|
+
print(f" [+] Already logged in as {email}")
|
|
44
|
+
except Exception:
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
if not existing_key:
|
|
48
|
+
print(" Step 1: Enter your API key")
|
|
49
|
+
print(" (Get one at meshcode.io/dashboard → Settings → API Keys)")
|
|
50
|
+
print()
|
|
51
|
+
api_key = input(" API key: ").strip()
|
|
52
|
+
if not api_key:
|
|
53
|
+
print(" [!] API key required. Get one at meshcode.io/dashboard")
|
|
54
|
+
return 1
|
|
55
|
+
# Login
|
|
56
|
+
try:
|
|
57
|
+
from meshcode.meshcode_mcp import backend as be
|
|
58
|
+
# Validate key
|
|
59
|
+
result = be.sb_rpc("mc_validate_api_key", {"p_api_key": api_key})
|
|
60
|
+
if isinstance(result, dict) and result.get("error"):
|
|
61
|
+
print(f" [x] Invalid API key: {result.get('error')}")
|
|
62
|
+
return 1
|
|
63
|
+
print(" [+] API key valid!")
|
|
64
|
+
# Save
|
|
65
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
66
|
+
(config_dir / "profile_meta.json").write_text(json.dumps({
|
|
67
|
+
"api_key": api_key,
|
|
68
|
+
"email": result.get("email", "unknown"),
|
|
69
|
+
}))
|
|
70
|
+
except Exception as e:
|
|
71
|
+
print(f" [x] Could not validate: {e}")
|
|
72
|
+
print(" Continuing anyway — key will be verified on run.")
|
|
73
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
74
|
+
(config_dir / "profile_meta.json").write_text(json.dumps({"api_key": api_key}))
|
|
75
|
+
else:
|
|
76
|
+
api_key = existing_key
|
|
77
|
+
|
|
78
|
+
print()
|
|
79
|
+
|
|
80
|
+
# Step 2: Project
|
|
81
|
+
print(" Step 2: Choose your meshwork (project)")
|
|
82
|
+
try:
|
|
83
|
+
from meshcode.meshcode_mcp import backend as be
|
|
84
|
+
projects = be.sb_rpc("mc_list_user_projects", {"p_api_key": api_key})
|
|
85
|
+
if isinstance(projects, dict) and projects.get("projects"):
|
|
86
|
+
proj_list = projects["projects"]
|
|
87
|
+
print(f" Your meshworks: {', '.join(p['name'] for p in proj_list[:5])}")
|
|
88
|
+
project = _input_with_default(" Meshwork name", proj_list[0]["name"])
|
|
89
|
+
else:
|
|
90
|
+
project = _input_with_default(" New meshwork name", "my-team")
|
|
91
|
+
except Exception:
|
|
92
|
+
project = _input_with_default(" Meshwork name", "my-team")
|
|
93
|
+
|
|
94
|
+
print()
|
|
95
|
+
|
|
96
|
+
# Step 3: Agent
|
|
97
|
+
print(" Step 3: Create your agent")
|
|
98
|
+
agent_name = _input_with_default(" Agent name", "assistant")
|
|
99
|
+
role = _input_with_default(" Agent role", "General-purpose AI assistant")
|
|
100
|
+
|
|
101
|
+
print()
|
|
102
|
+
print(f" Creating {agent_name} in {project}...")
|
|
103
|
+
print()
|
|
104
|
+
|
|
105
|
+
# Step 4: Setup + Run
|
|
106
|
+
try:
|
|
107
|
+
# Register agent
|
|
108
|
+
from meshcode.meshcode_mcp import backend as be
|
|
109
|
+
result = be.register_agent(project, agent_name, role, api_key=api_key)
|
|
110
|
+
if isinstance(result, dict) and result.get("error"):
|
|
111
|
+
if "already registered" in str(result.get("error", "")).lower():
|
|
112
|
+
print(f" [+] Agent {agent_name} already exists — reusing")
|
|
113
|
+
else:
|
|
114
|
+
print(f" [!] Registration: {result.get('error')}")
|
|
115
|
+
else:
|
|
116
|
+
print(f" [+] Agent {agent_name} registered!")
|
|
117
|
+
except Exception as e:
|
|
118
|
+
print(f" [!] Registration note: {e}")
|
|
119
|
+
|
|
120
|
+
# Run setup
|
|
121
|
+
print(f" [+] Setting up MCP connection...")
|
|
122
|
+
try:
|
|
123
|
+
import subprocess
|
|
124
|
+
subprocess.run(
|
|
125
|
+
[sys.executable, "-m", "meshcode", "setup", "claude", project, agent_name, role],
|
|
126
|
+
check=False
|
|
127
|
+
)
|
|
128
|
+
except Exception as e:
|
|
129
|
+
print(f" [!] Setup: {e}")
|
|
130
|
+
|
|
131
|
+
print()
|
|
132
|
+
print(" ╔══════════════════════════════════════╗")
|
|
133
|
+
print(f" ║ Agent '{agent_name}' is ready! ")
|
|
134
|
+
print(" ╚══════════════════════════════════════╝")
|
|
135
|
+
print()
|
|
136
|
+
print(" Next steps:")
|
|
137
|
+
print(f" 1. Open Claude Code and start chatting")
|
|
138
|
+
print(f" 2. Your agent will auto-connect via MCP")
|
|
139
|
+
print(f" 3. Or run manually: meshcode run {project} {agent_name}")
|
|
140
|
+
print()
|
|
141
|
+
|
|
142
|
+
# Ask if they want to run now
|
|
143
|
+
run_now = input(" Start agent now? [Y/n]: ").strip().lower()
|
|
144
|
+
if run_now in ("", "y", "yes"):
|
|
145
|
+
print(f"\n Starting {agent_name}...")
|
|
146
|
+
os.execvp(sys.executable, [sys.executable, "-m", "meshcode", "run", project, agent_name])
|
|
147
|
+
|
|
148
|
+
return 0
|
|
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
|
|
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
|