meshcode 2.10.21__tar.gz → 2.10.25__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.21 → meshcode-2.10.25}/PKG-INFO +1 -1
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/__init__.py +1 -1
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/server.py +170 -15
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.10.21 → meshcode-2.10.25}/pyproject.toml +1 -1
- {meshcode-2.10.21 → meshcode-2.10.25}/README.md +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/ascii_art.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/cli.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/comms_v4.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/invites.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/launcher.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/launcher_install.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/preferences.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/run_agent.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/secrets.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/self_update.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/setup_clients.py +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/setup.cfg +0 -0
- {meshcode-2.10.21 → meshcode-2.10.25}/tests/test_status_enum_coverage.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""MeshCode — Real-time communication between AI agents."""
|
|
2
|
-
__version__ = "2.10.
|
|
2
|
+
__version__ = "2.10.25"
|
|
@@ -866,6 +866,12 @@ RULES:
|
|
|
866
866
|
- sensitive=True for secrets/PII.
|
|
867
867
|
|
|
868
868
|
SESSION START (do these IMMEDIATELY — don't wait for user input):
|
|
869
|
+
The moment you see these instructions — whether the user said "boot", "hi",
|
|
870
|
+
nothing at all, or anything else — run the full protocol. Never reply with
|
|
871
|
+
only a memory summary and then idle. If your client defers MCP tool schemas
|
|
872
|
+
(shows tool names without parameters), your FIRST action is to load them:
|
|
873
|
+
ToolSearch(query="select:meshcode_set_status,meshcode_check,meshcode_tasks,meshcode_auto_wake,meshcode_status,meshcode_wait,meshcode_send,meshcode_task_claim,meshcode_task_complete,meshcode_remember,meshcode_recall")
|
|
874
|
+
Then execute:
|
|
869
875
|
1. meshcode_set_status(status="online", task="ready")
|
|
870
876
|
2. meshcode_check() — read NEW messages only (last_seen is auto-restored from mesh memory on boot, old messages are skipped automatically)
|
|
871
877
|
3. meshcode_tasks() — check for assigned/pending tasks and claim any unclaimed ones
|
|
@@ -873,6 +879,7 @@ SESSION START (do these IMMEDIATELY — don't wait for user input):
|
|
|
873
879
|
5. meshcode_status() — see who's online
|
|
874
880
|
6. If other agents are online → meshcode_send them a greeting
|
|
875
881
|
7. meshcode_wait() — enter the loop
|
|
882
|
+
DO NOT ASK THE USER "what do you want to work on" — the mesh tells you via tasks/messages.
|
|
876
883
|
|
|
877
884
|
CRITICAL: You communicate by CALLING TOOLS, not by thinking or writing text.
|
|
878
885
|
To talk to another agent → call meshcode_send(to="agent", message="...")
|
|
@@ -1338,14 +1345,12 @@ def meshcode_broadcast(payload: Any) -> Dict[str, Any]:
|
|
|
1338
1345
|
elif not isinstance(payload, dict):
|
|
1339
1346
|
return {"error": "payload must be a string or object", "got_type": type(payload).__name__}
|
|
1340
1347
|
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
sent += 1
|
|
1348
|
-
return {"broadcast": True, "agents_notified": sent}
|
|
1348
|
+
# Canonical broadcast: one row with to_agent='*'. Every agent's inbox
|
|
1349
|
+
# query includes `to_agent = '*'` so all recipients see it, without the
|
|
1350
|
+
# N-row fanout that caused duplicate-render bugs.
|
|
1351
|
+
be.send_message(_PROJECT_ID, AGENT_NAME, "*", payload, msg_type="broadcast",
|
|
1352
|
+
api_key=_get_api_key())
|
|
1353
|
+
return {"broadcast": True, "to": "*"}
|
|
1349
1354
|
|
|
1350
1355
|
|
|
1351
1356
|
@mcp.tool()
|
|
@@ -1481,7 +1486,7 @@ def _get_pending_tasks_summary() -> Optional[List[Dict[str, str]]]:
|
|
|
1481
1486
|
|
|
1482
1487
|
@mcp.tool()
|
|
1483
1488
|
@with_working_status
|
|
1484
|
-
async def meshcode_wait(timeout_seconds: int =
|
|
1489
|
+
async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -> Dict[str, Any]:
|
|
1485
1490
|
"""Block until a mesh message arrives or a task needs attention.
|
|
1486
1491
|
|
|
1487
1492
|
INTERNAL LOOP: This function loops internally and only returns when
|
|
@@ -1491,7 +1496,10 @@ async def meshcode_wait(timeout_seconds: int = 120, include_acks: bool = False)
|
|
|
1491
1496
|
accidentally using ScheduleWakeup or exiting the loop.
|
|
1492
1497
|
|
|
1493
1498
|
Args:
|
|
1494
|
-
timeout_seconds: Max wait time per poll cycle (default
|
|
1499
|
+
timeout_seconds: Max wait time per poll cycle (default 20, hard cap 20).
|
|
1500
|
+
Short cap keeps the outer tool call bounded so the user can press
|
|
1501
|
+
ESC in Claude Code without killing the MCP server — the inner
|
|
1502
|
+
loop continues polling across cycles at zero token cost.
|
|
1495
1503
|
"""
|
|
1496
1504
|
global _IN_WAIT, _CONSECUTIVE_IDLE_SECONDS, _LAST_SEEN_TS
|
|
1497
1505
|
|
|
@@ -1534,7 +1542,7 @@ async def meshcode_wait(timeout_seconds: int = 120, include_acks: bool = False)
|
|
|
1534
1542
|
|
|
1535
1543
|
_IN_WAIT = True
|
|
1536
1544
|
_set_state("waiting", "listening for messages")
|
|
1537
|
-
capped_timeout = min(max(1, int(timeout_seconds)),
|
|
1545
|
+
capped_timeout = min(max(1, int(timeout_seconds)), 20)
|
|
1538
1546
|
try:
|
|
1539
1547
|
# ── INTERNAL LOOP ──────────────────────────────────────────
|
|
1540
1548
|
# Keep polling until something actionable arrives.
|
|
@@ -1937,17 +1945,44 @@ def meshcode_task_create(title: str, description: str = "", assignee: str = "*",
|
|
|
1937
1945
|
|
|
1938
1946
|
@mcp.tool()
|
|
1939
1947
|
@with_working_status
|
|
1940
|
-
def meshcode_tasks(status_filter: Optional[str] = None) -> Dict[str, Any]:
|
|
1948
|
+
def meshcode_tasks(status_filter: Optional[str] = None, verbose: bool = False) -> Dict[str, Any]:
|
|
1941
1949
|
"""List tasks. Filter by status to find work.
|
|
1942
1950
|
|
|
1943
1951
|
Args:
|
|
1944
1952
|
status_filter: 'open' / 'in_progress' / 'done' / etc. None = all.
|
|
1953
|
+
verbose: When False (default), descriptions are truncated to 200 chars
|
|
1954
|
+
and null/empty fields are dropped to save tokens. Pass True for
|
|
1955
|
+
the full payload.
|
|
1945
1956
|
|
|
1946
1957
|
Returns: {"ok": true, "tasks": [...]}
|
|
1947
1958
|
"""
|
|
1948
1959
|
api_key = _get_api_key()
|
|
1949
1960
|
include_done = status_filter == "done"
|
|
1950
|
-
|
|
1961
|
+
result = be.task_list(api_key, _PROJECT_ID, AGENT_NAME, status_filter=status_filter, include_done=include_done)
|
|
1962
|
+
if verbose or not isinstance(result, dict) or not result.get("ok"):
|
|
1963
|
+
return result
|
|
1964
|
+
compact: List[Dict[str, Any]] = []
|
|
1965
|
+
for t in result.get("tasks", []):
|
|
1966
|
+
desc = t.get("description") or ""
|
|
1967
|
+
row: Dict[str, Any] = {
|
|
1968
|
+
"id": t.get("id"),
|
|
1969
|
+
"title": t.get("title"),
|
|
1970
|
+
"status": t.get("status"),
|
|
1971
|
+
"priority": t.get("priority"),
|
|
1972
|
+
"assignee": t.get("assignee"),
|
|
1973
|
+
}
|
|
1974
|
+
if t.get("claimed_by"):
|
|
1975
|
+
row["claimed_by"] = t["claimed_by"]
|
|
1976
|
+
if t.get("parent_task_id"):
|
|
1977
|
+
row["parent_task_id"] = t["parent_task_id"]
|
|
1978
|
+
if desc:
|
|
1979
|
+
if len(desc) > 200:
|
|
1980
|
+
row["description"] = desc[:200]
|
|
1981
|
+
row["_description_truncated"] = True
|
|
1982
|
+
else:
|
|
1983
|
+
row["description"] = desc
|
|
1984
|
+
compact.append(row)
|
|
1985
|
+
return {"ok": True, "tasks": compact}
|
|
1951
1986
|
|
|
1952
1987
|
|
|
1953
1988
|
@mcp.tool()
|
|
@@ -1960,9 +1995,32 @@ def meshcode_task_claim(task_id: str) -> Dict[str, Any]:
|
|
|
1960
1995
|
|
|
1961
1996
|
@mcp.tool()
|
|
1962
1997
|
@with_working_status
|
|
1963
|
-
def meshcode_task_complete(task_id: str, summary: str = "") -> Dict[str, Any]:
|
|
1964
|
-
"""Complete a claimed task with summary. Auto-remembers the task summary.
|
|
1998
|
+
def meshcode_task_complete(task_id: str, summary: str = "", force: bool = False) -> Dict[str, Any]:
|
|
1999
|
+
"""Complete a claimed task with summary. Auto-remembers the task summary.
|
|
2000
|
+
|
|
2001
|
+
Refuses if the task has open subtasks, unless force=True is passed with a
|
|
2002
|
+
reason in `summary`. This prevents closing a parent while lanes are still
|
|
2003
|
+
in flight.
|
|
2004
|
+
"""
|
|
1965
2005
|
api_key = _get_api_key()
|
|
2006
|
+
if not force:
|
|
2007
|
+
try:
|
|
2008
|
+
listing = be.task_list(api_key, _PROJECT_ID, AGENT_NAME, status_filter=None, include_done=False)
|
|
2009
|
+
if isinstance(listing, dict) and listing.get("ok"):
|
|
2010
|
+
open_subs = [
|
|
2011
|
+
{"id": t["id"][:8], "title": t["title"][:80], "status": t["status"]}
|
|
2012
|
+
for t in listing.get("tasks", [])
|
|
2013
|
+
if t.get("parent_task_id") == task_id
|
|
2014
|
+
and t.get("status") in ("open", "in_progress", "in_review")
|
|
2015
|
+
]
|
|
2016
|
+
if open_subs:
|
|
2017
|
+
return {
|
|
2018
|
+
"refused": True,
|
|
2019
|
+
"reason": f"Cannot complete — {len(open_subs)} open subtasks. Finish them or pass force=True with a reason in summary.",
|
|
2020
|
+
"open_subtasks": open_subs,
|
|
2021
|
+
}
|
|
2022
|
+
except Exception:
|
|
2023
|
+
pass # Best-effort check; don't block on listing failure.
|
|
1966
2024
|
result = be.task_complete(api_key, _PROJECT_ID, task_id, AGENT_NAME, summary=summary)
|
|
1967
2025
|
# Auto-remember task completion for future context
|
|
1968
2026
|
if isinstance(result, dict) and result.get("ok") and summary:
|
|
@@ -2013,6 +2071,62 @@ def meshcode_task_reject(task_id: str, feedback: str = "") -> Dict[str, Any]:
|
|
|
2013
2071
|
})
|
|
2014
2072
|
|
|
2015
2073
|
|
|
2074
|
+
@mcp.tool()
|
|
2075
|
+
@with_working_status
|
|
2076
|
+
def meshcode_task_search(title_contains: Optional[str] = None,
|
|
2077
|
+
status: Optional[str] = None,
|
|
2078
|
+
assignee: Optional[str] = None,
|
|
2079
|
+
limit: int = 20) -> Dict[str, Any]:
|
|
2080
|
+
"""Search tasks by title/status/assignee. Use before task_create to dedupe."""
|
|
2081
|
+
return be.sb_rpc("mc_search_tasks", {
|
|
2082
|
+
"p_api_key": _get_api_key(),
|
|
2083
|
+
"p_project_id": _PROJECT_ID,
|
|
2084
|
+
"p_caller_agent": AGENT_NAME,
|
|
2085
|
+
"p_title_contains": title_contains,
|
|
2086
|
+
"p_status": status,
|
|
2087
|
+
"p_assignee": assignee,
|
|
2088
|
+
"p_limit": limit,
|
|
2089
|
+
})
|
|
2090
|
+
|
|
2091
|
+
|
|
2092
|
+
@mcp.tool()
|
|
2093
|
+
@with_working_status
|
|
2094
|
+
def meshcode_agent_list() -> Dict[str, Any]:
|
|
2095
|
+
"""Roster of agents in this meshwork with status + last_heartbeat."""
|
|
2096
|
+
return be.sb_rpc("mc_list_agents", {
|
|
2097
|
+
"p_api_key": _get_api_key(),
|
|
2098
|
+
"p_project_id": _PROJECT_ID,
|
|
2099
|
+
})
|
|
2100
|
+
|
|
2101
|
+
|
|
2102
|
+
@mcp.tool()
|
|
2103
|
+
@with_working_status
|
|
2104
|
+
def meshcode_task_cancel(task_id: str, reason: str = "") -> Dict[str, Any]:
|
|
2105
|
+
"""Cancel a task. Creator or commander only. Works on open/in_progress/in_review."""
|
|
2106
|
+
api_key = _get_api_key()
|
|
2107
|
+
return be.sb_rpc("mc_task_cancel", {
|
|
2108
|
+
"p_api_key": api_key,
|
|
2109
|
+
"p_project_id": _PROJECT_ID,
|
|
2110
|
+
"p_task_id": task_id,
|
|
2111
|
+
"p_cancelling_agent": AGENT_NAME,
|
|
2112
|
+
"p_reason": reason,
|
|
2113
|
+
})
|
|
2114
|
+
|
|
2115
|
+
|
|
2116
|
+
@mcp.tool()
|
|
2117
|
+
@with_working_status
|
|
2118
|
+
def meshcode_task_reassign(task_id: str, new_assignee: str) -> Dict[str, Any]:
|
|
2119
|
+
"""Reassign an unclaimed open task to a different agent. Creator or commander only."""
|
|
2120
|
+
api_key = _get_api_key()
|
|
2121
|
+
return be.sb_rpc("mc_task_reassign", {
|
|
2122
|
+
"p_api_key": api_key,
|
|
2123
|
+
"p_project_id": _PROJECT_ID,
|
|
2124
|
+
"p_task_id": task_id,
|
|
2125
|
+
"p_reassigning_agent": AGENT_NAME,
|
|
2126
|
+
"p_new_assignee": new_assignee,
|
|
2127
|
+
})
|
|
2128
|
+
|
|
2129
|
+
|
|
2016
2130
|
# ----------------- PROACTIVE HEALTH SCAN -----------------
|
|
2017
2131
|
|
|
2018
2132
|
@mcp.tool()
|
|
@@ -2142,6 +2256,47 @@ def meshcode_links() -> Dict[str, Any]:
|
|
|
2142
2256
|
})
|
|
2143
2257
|
|
|
2144
2258
|
|
|
2259
|
+
@mcp.tool()
|
|
2260
|
+
@with_working_status
|
|
2261
|
+
def meshcode_link_invite(source_project: str, note: str = "") -> Dict[str, Any]:
|
|
2262
|
+
"""Generate a one-time invite token for another meshwork to link in.
|
|
2263
|
+
|
|
2264
|
+
Returns {token, expires_at}. Share the token out-of-band. The recipient
|
|
2265
|
+
calls meshcode_link_redeem(token, their_meshwork) to auto-link
|
|
2266
|
+
(no separate accept step).
|
|
2267
|
+
"""
|
|
2268
|
+
return be.sb_rpc("mc_create_link_invite", {
|
|
2269
|
+
"p_source_project": source_project,
|
|
2270
|
+
"p_note": note,
|
|
2271
|
+
})
|
|
2272
|
+
|
|
2273
|
+
|
|
2274
|
+
@mcp.tool()
|
|
2275
|
+
@with_working_status
|
|
2276
|
+
def meshcode_link_redeem(token: str, target_meshwork: str) -> Dict[str, Any]:
|
|
2277
|
+
"""Redeem an invite token — creates an ACTIVE mesh link in one step."""
|
|
2278
|
+
return be.sb_rpc("mc_redeem_link_invite", {
|
|
2279
|
+
"p_token": token,
|
|
2280
|
+
"p_target_project": target_meshwork,
|
|
2281
|
+
})
|
|
2282
|
+
|
|
2283
|
+
|
|
2284
|
+
@mcp.tool()
|
|
2285
|
+
@with_working_status
|
|
2286
|
+
def meshcode_link_invites(source_project: Optional[str] = None) -> Dict[str, Any]:
|
|
2287
|
+
"""List link invites this user has created (active/redeemed/expired/revoked)."""
|
|
2288
|
+
return be.sb_rpc("mc_list_my_link_invites", {
|
|
2289
|
+
"p_source_project": source_project,
|
|
2290
|
+
})
|
|
2291
|
+
|
|
2292
|
+
|
|
2293
|
+
@mcp.tool()
|
|
2294
|
+
@with_working_status
|
|
2295
|
+
def meshcode_link_invite_revoke(token: str) -> Dict[str, Any]:
|
|
2296
|
+
"""Revoke an outstanding (unredeemed) invite token."""
|
|
2297
|
+
return be.sb_rpc("mc_revoke_link_invite", {"p_token": token})
|
|
2298
|
+
|
|
2299
|
+
|
|
2145
2300
|
@mcp.tool()
|
|
2146
2301
|
@with_working_status
|
|
2147
2302
|
def meshcode_expand_link(link_id: str, agents: str) -> Dict[str, Any]:
|
|
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
|