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.
Files changed (32) hide show
  1. {meshcode-2.10.21 → meshcode-2.10.25}/PKG-INFO +1 -1
  2. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/__init__.py +1 -1
  3. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/server.py +170 -15
  4. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.10.21 → meshcode-2.10.25}/pyproject.toml +1 -1
  6. {meshcode-2.10.21 → meshcode-2.10.25}/README.md +0 -0
  7. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/ascii_art.py +0 -0
  8. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/cli.py +0 -0
  9. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/comms_v4.py +0 -0
  10. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/invites.py +0 -0
  11. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/launcher.py +0 -0
  12. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/launcher_install.py +0 -0
  13. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/__init__.py +0 -0
  14. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/__main__.py +0 -0
  15. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/backend.py +0 -0
  16. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/realtime.py +0 -0
  17. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/test_backend.py +0 -0
  18. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  19. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  20. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/preferences.py +0 -0
  21. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/protocol_v2.py +0 -0
  22. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/run_agent.py +0 -0
  23. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/secrets.py +0 -0
  24. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/self_update.py +0 -0
  25. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode/setup_clients.py +0 -0
  26. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/SOURCES.txt +0 -0
  27. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/dependency_links.txt +0 -0
  28. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/entry_points.txt +0 -0
  29. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/requires.txt +0 -0
  30. {meshcode-2.10.21 → meshcode-2.10.25}/meshcode.egg-info/top_level.txt +0 -0
  31. {meshcode-2.10.21 → meshcode-2.10.25}/setup.cfg +0 -0
  32. {meshcode-2.10.21 → meshcode-2.10.25}/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.21
3
+ Version: 2.10.25
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,2 +1,2 @@
1
1
  """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.10.21"
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
- agents = be.get_board(_PROJECT_ID)
1342
- sent = 0
1343
- for a in agents:
1344
- if a["name"] != AGENT_NAME:
1345
- be.send_message(_PROJECT_ID, AGENT_NAME, a["name"], payload, msg_type="broadcast",
1346
- api_key=_get_api_key())
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 = 120, include_acks: bool = False) -> Dict[str, Any]:
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 120, hard cap 120).
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)), 120)
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
- return be.task_list(api_key, _PROJECT_ID, AGENT_NAME, status_filter=status_filter, include_done=include_done)
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]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.10.21
3
+ Version: 2.10.25
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meshcode"
7
- version = "2.10.21"
7
+ version = "2.10.25"
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