meshcode 2.11.112__tar.gz → 2.11.114__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.112 → meshcode-2.11.114}/PKG-INFO +1 -1
  2. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/server.py +6 -0
  4. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/protocol_handler.py +34 -1
  5. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode.egg-info/PKG-INFO +1 -1
  6. {meshcode-2.11.112 → meshcode-2.11.114}/pyproject.toml +1 -1
  7. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_security_regressions.py +57 -0
  8. {meshcode-2.11.112 → meshcode-2.11.114}/README.md +0 -0
  9. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/__main__.py +0 -0
  10. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/_session_handoff_template.py +0 -0
  11. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/_stop_hook_template.py +0 -0
  12. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/ascii_art.py +0 -0
  13. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/atomic_push.py +0 -0
  14. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/claude_update.py +0 -0
  15. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/cli.py +0 -0
  16. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/comms_v4.py +0 -0
  17. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/compat.py +0 -0
  18. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/daemon.py +0 -0
  19. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/date_parse.py +0 -0
  20. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/doctor.py +0 -0
  21. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/error_hints.py +0 -0
  22. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/exceptions.py +0 -0
  23. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/hooks/__init__.py +0 -0
  24. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/hooks/repo_path_lock.py +0 -0
  25. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/hostd.py +0 -0
  26. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/invites.py +0 -0
  27. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/launcher.py +0 -0
  28. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/launcher_install.py +0 -0
  29. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/__init__.py +0 -0
  30. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/__main__.py +0 -0
  31. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/backend.py +0 -0
  32. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/realtime.py +0 -0
  33. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  34. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/test_backend.py +0 -0
  35. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  36. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  37. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  38. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  39. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  40. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/preferences.py +0 -0
  41. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/protocol_v2.py +0 -0
  42. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/quickstart.py +0 -0
  43. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/rpc_allowlist.py +0 -0
  44. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/run_agent.py +0 -0
  45. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/scripts/check_secrets.py +0 -0
  46. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/scripts/race_rate_harness.py +0 -0
  47. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/secrets.py +0 -0
  48. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/self_update.py +0 -0
  49. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/setup_clients.py +0 -0
  50. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/supervisor.py +0 -0
  51. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/up.py +0 -0
  52. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode/upload.py +0 -0
  53. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode.egg-info/SOURCES.txt +0 -0
  54. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode.egg-info/dependency_links.txt +0 -0
  55. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode.egg-info/entry_points.txt +0 -0
  56. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode.egg-info/requires.txt +0 -0
  57. {meshcode-2.11.112 → meshcode-2.11.114}/meshcode.egg-info/top_level.txt +0 -0
  58. {meshcode-2.11.112 → meshcode-2.11.114}/setup.cfg +0 -0
  59. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_auto_update_hardening.py +0 -0
  60. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_autonomous_closegap_1.py +0 -0
  61. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_autonomous_closegap_2.py +0 -0
  62. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_autonomous_closegap_3.py +0 -0
  63. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_autonomous_prompt_inject.py +0 -0
  64. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_boot_bug_regression.py +0 -0
  65. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_color_truecolor.py +0 -0
  66. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_core.py +0 -0
  67. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_cross_agent_messaging.py +0 -0
  68. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_date_parse.py +0 -0
  69. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_doctor.py +0 -0
  70. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_epistemic_v1_python_sdk.py +0 -0
  71. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  72. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_esc_deaf_state.py +0 -0
  73. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_exceptions.py +0 -0
  74. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_file_upload.py +0 -0
  75. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_init_device_code.py +0 -0
  76. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_install_guard.py +0 -0
  77. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_lease_sigterm_release.py +0 -0
  78. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_mark_read_batch.py +0 -0
  79. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_marketplace_ratings.py +0 -0
  80. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_migration_integrity.py +0 -0
  81. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_realtime_event_freshness.py +0 -0
  82. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_rls_cross_tenant.py +0 -0
  83. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_rpc_grants.py +0 -0
  84. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_rpc_migrations.py +0 -0
  85. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_run_agent_dry_run.py +0 -0
  86. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_run_agent_no_server_import.py +0 -0
  87. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_self_update_user_site.py +0 -0
  88. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_sentinel.py +0 -0
  89. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_setup_path.py +0 -0
  90. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_sleep_signals.py +0 -0
  91. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_status_enum_coverage.py +0 -0
  92. {meshcode-2.11.112 → meshcode-2.11.114}/tests/test_stay_on_loop_hook.py +0 -0
  93. {meshcode-2.11.112 → meshcode-2.11.114}/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.112
3
+ Version: 2.11.114
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.112"
2
+ __version__ = "2.11.114"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -3598,7 +3598,9 @@ def _try_auto_claim_self_assigned_tasks(max_claims: int = 20) -> List[Dict[str,
3598
3598
  for target in candidates[:max_claims]:
3599
3599
  claim_result = be.sb_rpc("mc_task_claim", {
3600
3600
  "p_api_key": api_key,
3601
+ "p_project_id": _PROJECT_ID,
3601
3602
  "p_task_id": target["id"],
3603
+ "p_claiming_agent": AGENT_NAME,
3602
3604
  })
3603
3605
  if isinstance(claim_result, dict) and claim_result.get("ok"):
3604
3606
  log.info(f"[meshcode] auto-claimed self-assigned task: {target['title'][:60]}")
@@ -3643,7 +3645,9 @@ def _try_auto_claim_task() -> Optional[Dict[str, str]]:
3643
3645
  # Claim it
3644
3646
  claim_result = be.sb_rpc("mc_task_claim", {
3645
3647
  "p_api_key": api_key,
3648
+ "p_project_id": _PROJECT_ID,
3646
3649
  "p_task_id": target["id"],
3650
+ "p_claiming_agent": AGENT_NAME,
3647
3651
  })
3648
3652
  if isinstance(claim_result, dict) and claim_result.get("ok"):
3649
3653
  log.info(f"[meshcode] auto-claimed task: {target['title'][:60]}")
@@ -3758,7 +3762,9 @@ def _try_auto_claim_open_by_heuristic(max_load: int = 2) -> Optional[Dict[str, A
3758
3762
  score, target = scored[0]
3759
3763
  claim_result = be.sb_rpc("mc_task_claim", {
3760
3764
  "p_api_key": api_key,
3765
+ "p_project_id": _PROJECT_ID,
3761
3766
  "p_task_id": target["id"],
3767
+ "p_claiming_agent": AGENT_NAME,
3762
3768
  })
3763
3769
  if not (isinstance(claim_result, dict) and claim_result.get("ok")):
3764
3770
  log.debug(f"[meshcode] heuristic claim lost race on {target['id'][:8]}: {claim_result}")
@@ -207,7 +207,40 @@ def _spawn_terminal_macos(cmd: str) -> tuple[bool, str]:
207
207
  'cd "$HOME" 2>/dev/null || cd /'] # neutral, non-TCC-protected cwd
208
208
  if venv_bin:
209
209
  lines.append(f'export PATH={shlex.quote(venv_bin)}:"$PATH"')
210
- lines.append(cmd) # ends in `exec meshcode run …`
210
+ # RECYCLE-KILL-OLD-TERMINAL (task 2094ff3d, Samuel "que se cierre la terminal
211
+ # pasada"). A recycle/stop ends the agent cleanly but macOS Terminal leaves the
212
+ # window open as "[Process completed]" — an orphan. Run the agent WITHOUT `exec`
213
+ # so bash survives its exit and can close THIS window. `cmd` ends in
214
+ # `exec … meshcode run …`; strip the leading `exec ` so the agent runs as a child
215
+ # (it still execvp's claude internally — that becomes the window's foreground proc).
216
+ lines.append('MC_TTY="$(tty 2>/dev/null)"')
217
+ # `cmd` is a compound line (`unset …; export PATH=…; exec <py> -m meshcode run …`),
218
+ # so the `exec` is NOT leading. Drop the LAST `exec ` token (the one before the
219
+ # interpreter) so the agent runs as a CHILD and bash survives to close the window.
220
+ if "exec " in cmd:
221
+ _head, _, _tail = cmd.rpartition("exec ")
222
+ _run = _head + _tail
223
+ else:
224
+ _run = cmd
225
+ lines.append(_run)
226
+ lines.append('MC_RC=$?')
227
+ # Close THIS Terminal window ONLY on a clean exit (recycle/stop => 0). On a CRASH
228
+ # (non-zero) leave it OPEN so the scrollback is available for debugging (commander
229
+ # condition: debugging > clean window). The own-$MC_TTY filter closes ONLY this
230
+ # window — never another agent's. saving no => no "close?" prompt. macOS-only path.
231
+ lines.append('if [ "$MC_RC" = "0" ] && [ -n "$MC_TTY" ]; then')
232
+ lines.append(
233
+ " /usr/bin/osascript"
234
+ " -e 'tell application \"Terminal\"'"
235
+ " -e 'repeat with w in windows'"
236
+ " -e 'try'"
237
+ " -e \"if (tty of selected tab of w) is \\\"$MC_TTY\\\" then\""
238
+ " -e 'close w saving no'"
239
+ " -e 'end if'"
240
+ " -e 'end try'"
241
+ " -e 'end repeat'"
242
+ " -e 'end tell' >/dev/null 2>&1")
243
+ lines.append('fi')
211
244
  try:
212
245
  launch_dir.mkdir(parents=True, exist_ok=True)
213
246
  script_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.112
3
+ Version: 2.11.114
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.112"
7
+ version = "2.11.114"
8
8
  description = "Real-time communication between AI agents — Supabase-backed CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -169,3 +169,60 @@ class TestRLSPoliciesExist:
169
169
  def test_mc_api_keys_has_rls(self):
170
170
  all_sql = _read_all_migrations()
171
171
  assert "mc_api_keys ENABLE ROW LEVEL SECURITY" in all_sql
172
+
173
+
174
+ class TestP1_4_LaunchBatchAgentNameRCE:
175
+ """P1-4: cmd_launch_batch interpolates the agent name into the platform launch
176
+ string (Windows `cmd /k`, POSIX shell). The name MUST be allowlisted + hard-
177
+ rejected at the loop boundary BEFORE it reaches the shell, or a crafted name like
178
+ `x" & calc & "` breaks out of the quoting and executes arbitrary code (and a leading
179
+ `-` could be read as a flag / a 300-char name is a DoS). Landed v2.11.109; these
180
+ tests lock the allowlist + its wiring so the fix can't silently regress."""
181
+
182
+ # Real RCE / arg-injection / DoS payloads that MUST be rejected.
183
+ MALICIOUS = [
184
+ 'x"&calc', # cmd.exe quote-break + chain
185
+ 'x" & calc & "', # the canonical P1-4 payload
186
+ ';rm -rf', # POSIX command chain
187
+ '$(id)', # POSIX command substitution
188
+ '`id`', # POSIX backtick substitution
189
+ '|nc', # pipe to netcat
190
+ '&& curl evil', # chain
191
+ 'a b', # whitespace (token split)
192
+ '-rf', # leading dash -> flag/arg injection
193
+ '--version', # leading dashes -> flag injection
194
+ 'a' * 65, # length cap (DoS via 300-char names)
195
+ '', # empty
196
+ 'x\n', # trailing newline (\Z anchor, not $)
197
+ '../etc', # path traversal chars
198
+ ]
199
+ # Plain, real agent identifiers that MUST be allowed (no false-rejects).
200
+ LEGIT = ['back', 'qa', 'front-2', 'mesh_dev', 'commander', 'a', 'Agent_1', 'x' * 64]
201
+
202
+ def test_allowlist_blocks_malicious_names(self):
203
+ from meshcode.protocol_handler import is_valid_agent_name
204
+ for payload in self.MALICIOUS:
205
+ assert not is_valid_agent_name(payload), \
206
+ f"SECURITY: malicious agent name was NOT rejected: {payload!r}"
207
+
208
+ def test_allowlist_allows_legit_names(self):
209
+ from meshcode.protocol_handler import is_valid_agent_name
210
+ for name in self.LEGIT:
211
+ assert is_valid_agent_name(name), \
212
+ f"REGRESSION: legitimate agent name was wrongly rejected: {name!r}"
213
+
214
+ def test_cmd_launch_batch_validates_before_shell(self):
215
+ """Wiring guard: cmd_launch_batch MUST call is_valid_agent_name BEFORE it
216
+ builds the `... run "<name>"` shell string — else the allowlist exists but
217
+ isn't enforced. Catches a removed/moved call site, not just a missing regex."""
218
+ src = (Path(__file__).parent.parent / "meshcode" / "protocol_handler.py").read_text()
219
+ start = src.index("def cmd_launch_batch")
220
+ body = src[start:src.find("\ndef ", start + 1)]
221
+ assert "is_valid_agent_name" in body, \
222
+ "SECURITY: cmd_launch_batch does not call is_valid_agent_name at all"
223
+ # The validation must come BEFORE the name is interpolated into the launch cmd.
224
+ guard_pos = body.index("is_valid_agent_name")
225
+ sink = re.search(r'run\s+"?\{name\}|run\s+\{shlex\.quote\(name\)', body)
226
+ assert sink is not None, "cmd_launch_batch shell-interpolation sink not found (test stale?)"
227
+ assert guard_pos < sink.start(), \
228
+ "SECURITY: is_valid_agent_name is checked AFTER the shell interpolation — RCE boundary broken"
File without changes
File without changes
File without changes
File without changes