meshcode 2.11.114__tar.gz → 2.11.115__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 (93) hide show
  1. {meshcode-2.11.114 → meshcode-2.11.115}/PKG-INFO +1 -1
  2. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/server.py +105 -7
  4. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.11.114 → meshcode-2.11.115}/pyproject.toml +1 -1
  6. {meshcode-2.11.114 → meshcode-2.11.115}/README.md +0 -0
  7. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/__main__.py +0 -0
  8. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/_session_handoff_template.py +0 -0
  9. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/_stop_hook_template.py +0 -0
  10. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/ascii_art.py +0 -0
  11. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/atomic_push.py +0 -0
  12. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/claude_update.py +0 -0
  13. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/cli.py +0 -0
  14. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/comms_v4.py +0 -0
  15. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/compat.py +0 -0
  16. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/daemon.py +0 -0
  17. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/date_parse.py +0 -0
  18. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/doctor.py +0 -0
  19. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/error_hints.py +0 -0
  20. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/exceptions.py +0 -0
  21. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/hooks/__init__.py +0 -0
  22. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/hooks/repo_path_lock.py +0 -0
  23. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/hostd.py +0 -0
  24. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/invites.py +0 -0
  25. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/launcher.py +0 -0
  26. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/launcher_install.py +0 -0
  27. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/__init__.py +0 -0
  28. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/__main__.py +0 -0
  29. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/backend.py +0 -0
  30. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/realtime.py +0 -0
  31. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  32. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/test_backend.py +0 -0
  33. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  34. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  35. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  36. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  37. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  38. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/preferences.py +0 -0
  39. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/protocol_handler.py +0 -0
  40. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/protocol_v2.py +0 -0
  41. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/quickstart.py +0 -0
  42. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/rpc_allowlist.py +0 -0
  43. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/run_agent.py +0 -0
  44. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/scripts/check_secrets.py +0 -0
  45. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/scripts/race_rate_harness.py +0 -0
  46. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/secrets.py +0 -0
  47. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/self_update.py +0 -0
  48. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/setup_clients.py +0 -0
  49. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/supervisor.py +0 -0
  50. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/up.py +0 -0
  51. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode/upload.py +0 -0
  52. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode.egg-info/SOURCES.txt +0 -0
  53. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode.egg-info/dependency_links.txt +0 -0
  54. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode.egg-info/entry_points.txt +0 -0
  55. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode.egg-info/requires.txt +0 -0
  56. {meshcode-2.11.114 → meshcode-2.11.115}/meshcode.egg-info/top_level.txt +0 -0
  57. {meshcode-2.11.114 → meshcode-2.11.115}/setup.cfg +0 -0
  58. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_auto_update_hardening.py +0 -0
  59. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_autonomous_closegap_1.py +0 -0
  60. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_autonomous_closegap_2.py +0 -0
  61. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_autonomous_closegap_3.py +0 -0
  62. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_autonomous_prompt_inject.py +0 -0
  63. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_boot_bug_regression.py +0 -0
  64. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_color_truecolor.py +0 -0
  65. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_core.py +0 -0
  66. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_cross_agent_messaging.py +0 -0
  67. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_date_parse.py +0 -0
  68. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_doctor.py +0 -0
  69. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_epistemic_v1_python_sdk.py +0 -0
  70. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  71. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_esc_deaf_state.py +0 -0
  72. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_exceptions.py +0 -0
  73. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_file_upload.py +0 -0
  74. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_init_device_code.py +0 -0
  75. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_install_guard.py +0 -0
  76. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_lease_sigterm_release.py +0 -0
  77. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_mark_read_batch.py +0 -0
  78. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_marketplace_ratings.py +0 -0
  79. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_migration_integrity.py +0 -0
  80. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_realtime_event_freshness.py +0 -0
  81. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_rls_cross_tenant.py +0 -0
  82. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_rpc_grants.py +0 -0
  83. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_rpc_migrations.py +0 -0
  84. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_run_agent_dry_run.py +0 -0
  85. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_run_agent_no_server_import.py +0 -0
  86. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_security_regressions.py +0 -0
  87. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_self_update_user_site.py +0 -0
  88. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_sentinel.py +0 -0
  89. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_setup_path.py +0 -0
  90. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_sleep_signals.py +0 -0
  91. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_status_enum_coverage.py +0 -0
  92. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_stay_on_loop_hook.py +0 -0
  93. {meshcode-2.11.114 → meshcode-2.11.115}/tests/test_wait_open_tasks_contradiction.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.114
3
+ Version: 2.11.115
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.11.114"
2
+ __version__ = "2.11.115"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -2898,6 +2898,13 @@ def meshcode_send(to: Union[str, List[str]], message: Any, in_reply_to: Optional
2898
2898
  msg_ids[], count}. Cross-mesh '@' is single-recipient only (mixed lists rejected v1).
2899
2899
  sensitive=True hides from exports. encrypted=True for secrets (AES-256-GCM, cross-mesh only).
2900
2900
  type= optional typed-catalog tag; soft-validates, never refuses."""
2901
+ # mode-2 soft-fail (R2-3): a malformed in_reply_to (not a valid uuid) would hit
2902
+ # the uuid cast at the RPC boundary and reject the WHOLE message. Drop it so the
2903
+ # message still sends (pairs with mig463's nonexistent-but-valid-uuid soft-fail).
2904
+ if in_reply_to is not None and not re.fullmatch(
2905
+ r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}",
2906
+ str(in_reply_to)):
2907
+ in_reply_to = None
2901
2908
  # ── Normalize `to` into a recipients list ──────────────────────────────
2902
2909
  if isinstance(to, list):
2903
2910
  recipients: List[str] = [str(t).strip() for t in to if str(t).strip()]
@@ -3514,6 +3521,58 @@ def _get_pending_tasks_summary() -> Optional[List[Dict[str, str]]]:
3514
3521
  return None
3515
3522
 
3516
3523
 
3524
+ def _pending_filter(tasks: List[Dict[str, Any]]) -> Optional[List[Dict[str, str]]]:
3525
+ """The _get_pending_tasks_summary filter, applied to a task list we already
3526
+ have (e.g. from mc_wait_poll) so we don't re-fetch. Identical output shape."""
3527
+ pending = [
3528
+ {"id": t["id"][:8], "title": t["title"][:80], "priority": t.get("priority", "normal"), "status": t["status"]}
3529
+ for t in tasks
3530
+ if t.get("status") in ("open", "in_progress")
3531
+ and (t.get("claimed_by") == AGENT_NAME or t.get("assignee") == AGENT_NAME)
3532
+ ]
3533
+ if _is_leader_agent():
3534
+ pending.extend([
3535
+ {"id": t["id"][:8], "title": t["title"][:80], "priority": t.get("priority", "normal"), "status": t["status"]}
3536
+ for t in tasks
3537
+ if t.get("status") == "open" and t.get("assignee") == "*" and not t.get("claimed_by")
3538
+ ])
3539
+ _PRIORITY_ORDER = {"urgent": 0, "high": 1, "normal": 2, "low": 3}
3540
+ pending.sort(key=lambda t: _PRIORITY_ORDER.get(t.get("priority", "normal"), 2))
3541
+ return pending if pending else None
3542
+
3543
+
3544
+ def _wait_poll_or_legacy() -> Dict[str, Any]:
3545
+ """R2-1: ONE mc_wait_poll replaces _check_recycle_request + _check_stop_request
3546
+ + _get_pending_tasks_summary (3 RPCs + 3 api_key resolves -> 1). Semantics are
3547
+ identical (recycle = mig446 guard, stop = desired_state, tasks via the same
3548
+ filter). Falls back to the 3 legacy RPCs on ANY error so a mixed old-SDK/new-RPC
3549
+ fleet never breaks. recycle-first order is preserved by the caller."""
3550
+ try:
3551
+ api_key = _get_api_key()
3552
+ if api_key:
3553
+ resp = be.sb_rpc("mc_wait_poll", {
3554
+ "p_api_key": api_key,
3555
+ "p_project_id": _PROJECT_ID,
3556
+ "p_agent_name": AGENT_NAME,
3557
+ })
3558
+ if isinstance(resp, dict) and resp.get("ok"):
3559
+ return {
3560
+ "recycle": bool(resp.get("recycle")),
3561
+ "stop": bool(resp.get("stop")),
3562
+ "tasks": _pending_filter(resp.get("tasks") or []),
3563
+ "_via": "mc_wait_poll",
3564
+ }
3565
+ except Exception as e:
3566
+ log.debug(f"[meshcode] mc_wait_poll failed; legacy fallback: {e}")
3567
+ # Legacy fallback — the 3 separate RPCs (old behavior, never breaks).
3568
+ return {
3569
+ "recycle": _check_recycle_request(),
3570
+ "stop": _check_stop_request(),
3571
+ "tasks": _get_pending_tasks_summary(),
3572
+ "_via": "legacy",
3573
+ }
3574
+
3575
+
3517
3576
  def _check_recycle_request() -> bool:
3518
3577
  """Server-authorized recycle (task 548c863e, mig 364).
3519
3578
 
@@ -4202,11 +4261,11 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
4202
4261
  "count": len(pending_tasks),
4203
4262
  "you_are_autonomous": _get_autonomous_mode(),
4204
4263
  "task_pull_active": True,
4205
- "hint": "Work the highest-priority task with meshcode_task_start, then meshcode_task_complete. Wait will surface the next one automatically.",
4264
+ "hint": "Work highest-priority task; wait surfaces the next one.",
4206
4265
  }
4207
4266
  if _auto_started:
4208
4267
  out["auto_started_task"] = _auto_started
4209
- out["hint"] = f"Task '{_auto_started['title'][:60]}' auto-started (in_progress). Work it NOW, then meshcode_task_complete when done."
4268
+ out["hint"] = f"Task '{_auto_started['title'][:60]}' auto-started work it, then task_complete."
4210
4269
  if _wait_entry_auto_claimed:
4211
4270
  out["auto_claimed_at_wait_entry"] = _wait_entry_auto_claimed
4212
4271
  return out
@@ -4229,6 +4288,11 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
4229
4288
  pass # All messages already seen — fall through to wait loop
4230
4289
  else:
4231
4290
  split = _split_messages(deduped)
4291
+ # L5-P3 (task 96d5f2e9): honor include_acks on the refused path too —
4292
+ # this was the only delivery path that leaked acks into the payload,
4293
+ # billing a turn's worth of "X read your message" noise to every agent.
4294
+ if not include_acks:
4295
+ split["acks"] = []
4232
4296
  # Only refuse for real messages — ack-only batches should not block wait
4233
4297
  if split["messages"] or split["done_signals"]:
4234
4298
  resp = {
@@ -4305,7 +4369,8 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
4305
4369
  # us fresh. Checked BEFORE pending_tasks: the fresh session
4306
4370
  # re-attacks any open tasks on boot, so an outstanding backlog
4307
4371
  # must not pin a stale, context-heavy session alive.
4308
- if _check_recycle_request():
4372
+ _wp = _wait_poll_or_legacy() # R2-1: 3 RPCs -> 1 (legacy fallback inside)
4373
+ if _wp["recycle"]:
4309
4374
  _set_state("sleeping", "recycle")
4310
4375
  result["must_exit"] = True
4311
4376
  result["exit_reason"] = (
@@ -4318,7 +4383,7 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
4318
4383
  # toggled this agent OFF (desired_state='stopped'). Exit CLEAN — sticky
4319
4384
  # 'stopped' means hostd will NOT respawn us (unlike recycle). Checked
4320
4385
  # right after recycle so a power-off wins over auto-claim/pending-tasks.
4321
- if _check_stop_request():
4386
+ if _wp["stop"]:
4322
4387
  _set_state("sleeping", "stopped")
4323
4388
  result["must_exit"] = True
4324
4389
  result["exit_reason"] = (
@@ -4328,8 +4393,8 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
4328
4393
  result["stopped"] = True
4329
4394
  break
4330
4395
 
4331
- # Check if new tasks appeared while we waited
4332
- pending_tasks = _get_pending_tasks_summary()
4396
+ # New tasks that appeared while we waited (from the same poll)
4397
+ pending_tasks = _wp["tasks"]
4333
4398
  if pending_tasks:
4334
4399
  result["pending_tasks"] = pending_tasks
4335
4400
  break # Return so agent can work tasks
@@ -4411,7 +4476,8 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
4411
4476
  # `you_are_autonomous` is the canonical field per commander memo
4412
4477
  # decisions msg 29cae7f9; `autonomous_mode` retained for back-compat.
4413
4478
  if isinstance(result, dict):
4414
- result["autonomous_mode"] = _autonomous
4479
+ # L5-P4: `you_are_autonomous` is canonical (commander memo 29cae7f9);
4480
+ # the duplicate `autonomous_mode` alias was dropped from the envelope.
4415
4481
  result["you_are_autonomous"] = _autonomous
4416
4482
  return result
4417
4483
  finally:
@@ -6062,6 +6128,19 @@ def meshcode_boot() -> Dict[str, Any]:
6062
6128
  # Non-fatal: surface that the hints are unavailable but boot succeeds.
6063
6129
  resp.setdefault("time_context_available", False)
6064
6130
 
6131
+ # L5-P4 (task 96d5f2e9): offline agents' mc_agents.task often holds their
6132
+ # FULL registration role text (150+ tokens each), re-billed on every boot.
6133
+ # The peer roster only needs a glanceable line.
6134
+ try:
6135
+ _mesh = resp.get("mesh_status")
6136
+ if isinstance(_mesh, list):
6137
+ for _row in _mesh:
6138
+ _ct = _row.get("current_task") if isinstance(_row, dict) else None
6139
+ if isinstance(_ct, str) and len(_ct) > 120:
6140
+ _row["current_task"] = _ct[:117] + "..."
6141
+ except Exception:
6142
+ pass
6143
+
6065
6144
  # c0ab14c1 Phase 2: open-promise time-awareness (what I owe / what I'm
6066
6145
  # waiting on, with overdue/elapsed minutes). Soft-fail; only added when
6067
6146
  # there's something open.
@@ -7253,6 +7332,25 @@ def meshcode_recall_search(query: str) -> Dict[str, Any]:
7253
7332
  query: Plain English search query.
7254
7333
  """
7255
7334
  api_key = _get_api_key()
7335
+ # L6 M4 (task 84c426d4): hybrid semantic+FTS recall via the mc-embed edge
7336
+ # function (embeds the query with gte-small, then calls mc_memory_search v2
7337
+ # with p_query_embedding — RRF fusion server-side). Soft-fail to the direct
7338
+ # RPC (FTS+substring arms of the same v2 fn) if the edge fn is unreachable.
7339
+ try:
7340
+ import urllib.request as _url
7341
+ _req = _url.Request(
7342
+ f"{be.SUPABASE_URL}/functions/v1/mc-embed",
7343
+ data=json.dumps({"search": {
7344
+ "api_key": api_key, "agent_name": AGENT_NAME,
7345
+ "query": query, "project_name": PROJECT_NAME, "limit": 20,
7346
+ }}).encode(),
7347
+ headers={"Content-Type": "application/json"}, method="POST")
7348
+ with _url.urlopen(_req, timeout=8) as _resp:
7349
+ _out = json.loads(_resp.read().decode())
7350
+ if isinstance(_out, dict) and _out.get("ok"):
7351
+ return _out
7352
+ except Exception as _e:
7353
+ log.debug(f"mc-embed search fallback to direct RPC: {_e}")
7256
7354
  return be.sb_rpc("mc_memory_search", {
7257
7355
  "p_api_key": api_key,
7258
7356
  "p_agent_name": AGENT_NAME,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.114
3
+ Version: 2.11.115
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.11.114"
7
+ version = "2.11.115"
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
File without changes