meshcode 2.11.132__tar.gz → 2.11.133__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 (101) hide show
  1. {meshcode-2.11.132 → meshcode-2.11.133}/PKG-INFO +1 -1
  2. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/protocol_handler.py +414 -20
  4. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.11.132 → meshcode-2.11.133}/pyproject.toml +1 -1
  6. {meshcode-2.11.132 → meshcode-2.11.133}/README.md +0 -0
  7. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/__main__.py +0 -0
  8. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/_session_handoff_template.py +0 -0
  9. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/_stop_hook_template.py +0 -0
  10. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/ascii_art.py +0 -0
  11. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/atomic_push.py +0 -0
  12. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/claude_update.py +0 -0
  13. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/cli.py +0 -0
  14. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/comms_v4.py +0 -0
  15. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/compat.py +0 -0
  16. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/daemon.py +0 -0
  17. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/date_parse.py +0 -0
  18. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/doctor.py +0 -0
  19. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/error_hints.py +0 -0
  20. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/exceptions.py +0 -0
  21. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/hooks/__init__.py +0 -0
  22. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/hooks/repo_path_lock.py +0 -0
  23. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/hostd.py +0 -0
  24. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/invites.py +0 -0
  25. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/launcher.py +0 -0
  26. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/launcher_install.py +0 -0
  27. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/__init__.py +0 -0
  28. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/__main__.py +0 -0
  29. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/backend.py +0 -0
  30. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/realtime.py +0 -0
  31. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/server.py +0 -0
  32. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  33. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/swarm.py +0 -0
  34. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/test_backend.py +0 -0
  35. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  36. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  37. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  38. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  39. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  40. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/meshcode_mcp/test_swarm.py +0 -0
  41. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/preferences.py +0 -0
  42. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/protocol_v2.py +0 -0
  43. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/quickstart.py +0 -0
  44. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/rpc_allowlist.py +0 -0
  45. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/run_agent.py +0 -0
  46. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/scripts/check_secrets.py +0 -0
  47. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/scripts/race_rate_harness.py +0 -0
  48. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/secrets.py +0 -0
  49. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/self_update.py +0 -0
  50. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/setup_clients.py +0 -0
  51. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/supervisor.py +0 -0
  52. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/up.py +0 -0
  53. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode/upload.py +0 -0
  54. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode.egg-info/SOURCES.txt +0 -0
  55. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode.egg-info/dependency_links.txt +0 -0
  56. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode.egg-info/entry_points.txt +0 -0
  57. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode.egg-info/requires.txt +0 -0
  58. {meshcode-2.11.132 → meshcode-2.11.133}/meshcode.egg-info/top_level.txt +0 -0
  59. {meshcode-2.11.132 → meshcode-2.11.133}/setup.cfg +0 -0
  60. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_auto_update_hardening.py +0 -0
  61. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_autonomous_closegap_1.py +0 -0
  62. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_autonomous_closegap_2.py +0 -0
  63. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_autonomous_closegap_3.py +0 -0
  64. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_autonomous_prompt_inject.py +0 -0
  65. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_boot_bug_regression.py +0 -0
  66. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_color_truecolor.py +0 -0
  67. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_core.py +0 -0
  68. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_cross_agent_messaging.py +0 -0
  69. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_date_parse.py +0 -0
  70. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_doctor.py +0 -0
  71. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_epistemic_v1_python_sdk.py +0 -0
  72. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  73. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_esc_deaf_state.py +0 -0
  74. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_exceptions.py +0 -0
  75. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_file_upload.py +0 -0
  76. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_hostd_zombie_sessions.py +0 -0
  77. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_init_device_code.py +0 -0
  78. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_install_guard.py +0 -0
  79. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_lease_sigterm_release.py +0 -0
  80. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_live_mesh_guard.py +0 -0
  81. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_mark_read_batch.py +0 -0
  82. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_marketplace_ratings.py +0 -0
  83. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_migration_integrity.py +0 -0
  84. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_realtime_event_freshness.py +0 -0
  85. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_rls_cross_tenant.py +0 -0
  86. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_rpc_grants.py +0 -0
  87. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_rpc_migrations.py +0 -0
  88. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_run_agent_dry_run.py +0 -0
  89. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_run_agent_no_server_import.py +0 -0
  90. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_security_regressions.py +0 -0
  91. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_self_update_user_site.py +0 -0
  92. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_sentinel.py +0 -0
  93. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_session_replay_gate.py +0 -0
  94. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_setup_path.py +0 -0
  95. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_sleep_signals.py +0 -0
  96. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_status_enum_coverage.py +0 -0
  97. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_stay_on_loop_hook.py +0 -0
  98. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_stop_ghost_terminal.py +0 -0
  99. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_swarm_events.py +0 -0
  100. {meshcode-2.11.132 → meshcode-2.11.133}/tests/test_terminal_lifecycle.py +0 -0
  101. {meshcode-2.11.132 → meshcode-2.11.133}/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.132
3
+ Version: 2.11.133
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.132"
2
+ __version__ = "2.11.133"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -175,16 +175,28 @@ def _launcher_label(cmd: str) -> str:
175
175
  # Samuel 22c9f31d: "Launch All de N agentes = 1 ventana con N tabs, NO N
176
176
  # ventanas sueltas")
177
177
  # ============================================================
178
- # macOS Terminal.app has NO reliable programmatic tab API — all four native
179
- # routes were tested live on the target box 2026-06-11 and fail:
178
+ # macOS Terminal.app has NO reliable programmatic tab API — SEVEN native
179
+ # routes were tested live on the target box (macOS 26.4.1, 2026-06-11) and
180
+ # ALL fail (task 2ac3f111 first four; task 4df5a126 the last three):
180
181
  # - AppleScript `do script ... in window id N` reuses the selected tab
181
182
  # (never creates one)
182
183
  # - AppleScript `make new tab` errors -10000 (unsupported by Terminal)
183
184
  # - `defaults write com.apple.Terminal AppleWindowTabbingMode always` is
184
185
  # ignored (Terminal's tab model predates NSWindow tabbing)
186
+ # - `defaults write -g AppleWindowTabbingMode always` (global domain) is
187
+ # ALSO ignored for `open -a Terminal x.command` — still N windows
185
188
  # - System Events Cmd+T opened a NEW WINDOW even with Accessibility
186
189
  # granted, the target window raised AND frontmost (flaky beyond repair;
187
190
  # also needs Accessibility + steals focus = two extra failure modes)
191
+ # - System Events click of menu item Shell > New Tab > <profile> (the
192
+ # deterministic cousin of Cmd+T) ALSO creates a NEW WINDOW, with the
193
+ # target window verified frontmost at click time
194
+ # - AppleScript bare `do script` (new-window form) with tabbing=always
195
+ # set in either domain still creates separate windows
196
+ # (Window > Merge All Windows would coerce tabs but swallows the user's
197
+ # PERSONAL Terminal windows — prohibited.) Native tabs on Terminal.app can
198
+ # only be created by a human gesture; if true native tabs are required, the
199
+ # supported path is a terminal with a real tab API (e.g. iTerm2).
188
200
  # So the fleet window is a tmux session inside ONE Terminal window: each
189
201
  # agent = a named tmux window = a clickable tab in the status bar. This buys
190
202
  # exactly the spec, with zero Apple Events from the daemon (the TCC
@@ -202,6 +214,43 @@ def _launcher_label(cmd: str) -> str:
202
214
  _FLEET_SESSION = "meshcode-fleet"
203
215
 
204
216
 
217
+ def _fleet_tab_name(cmd: str) -> str:
218
+ """Short per-agent tab name for the fleet bar (task 4df5a126).
219
+
220
+ hostd targets are `<project>/<agent>` so _launcher_label yields
221
+ `meshcode-self-improve_backend` — at 3+ agents those long names overflow
222
+ the status bar and Samuel sees ONE truncated tab ("la barra verde
223
+ truncada"). The tab must read like a native Terminal tab: just the agent.
224
+ Take the part after the LAST '/' of the raw `meshcode run` target
225
+ (project names can't contain '/'; launch-batch passes bare agent names,
226
+ which are unchanged). Falls back to the full launcher label.
227
+ """
228
+ m = re.search(r"meshcode\s+run\s+(?:'([^']*)'|\"([^\"]*)\"|(\S+))", cmd)
229
+ raw = ((m.group(1) or m.group(2) or m.group(3)) if m else "") or ""
230
+ agent = raw.rsplit("/", 1)[-1].strip()
231
+ safe = re.sub(r"[^A-Za-z0-9_.-]", "_", agent).strip("_")
232
+ return safe[:24] or _launcher_label(cmd)
233
+
234
+
235
+ # Native-looking tab bar (task 4df5a126: Samuel rejected the default tmux
236
+ # status line — invisible/truncated). Top-positioned (where Terminal tabs
237
+ # live), one padded block per agent, active tab high-contrast, all
238
+ # mouse-clickable (mouse on). Plain ASCII, no emojis (Samuel rule 52b291b9).
239
+ # Applied idempotently on EVERY spawn so an already-running fleet session
240
+ # picks the style up the next time any agent launches.
241
+ _FLEET_STYLE: tuple = (
242
+ ("status-position", "top"),
243
+ ("status-style", "bg=#16161e,fg=#a9b1d6"),
244
+ ("status-left", "#[bg=#3d59a1,fg=#ffffff,bold] MESHCODE #[default] "),
245
+ ("status-left-length", "14"),
246
+ ("status-right", "#[fg=#565f89] #{session_windows} agents | click: switch | right-click: stop "),
247
+ ("status-right-length", "48"),
248
+ ("window-status-format", "#[bg=#24283b,fg=#a9b1d6] #W #[default]"),
249
+ ("window-status-current-format", "#[bg=#7aa2f7,fg=#16161e,bold] #W #[default]"),
250
+ ("window-status-separator", " "),
251
+ )
252
+
253
+
205
254
  def _find_tmux() -> Optional[str]:
206
255
  """tmux binary or None. The launchd daemon's PATH is minimal, so probe the
207
256
  common install prefixes + the daemon venv bin explicitly."""
@@ -227,11 +276,23 @@ def _fleet_wrap(cmd: str) -> str:
227
276
  Drop the LAST `exec ` (same trick as the .command launcher) so the shell
228
277
  survives the agent's exit and can translate rc 143 (SIGTERM = hostd
229
278
  stop/ghost-kill, task 91201315: that's the job FINISHING) to 0 — otherwise
230
- `remain-on-exit failed` would keep a dead pane for every plain Stop."""
279
+ `remain-on-exit failed` would keep a dead pane for every plain Stop.
280
+
281
+ CLOSE-TAB=STOP (task 4df5a126, Samuel 68b1c17b: "cierro su terminal y
282
+ ya"): export MESHCODE_CLOSE_STOP_SIGHUP=1 so the MCP server's gated POSIX
283
+ close=stop handler (b6da0d54, default OFF) arms INSIDE fleet tabs only.
284
+ In a tmux pane SIGHUP is unambiguous — only kill-window / kill-session /
285
+ tmux-server death close the pty (a window-close of the shared Terminal
286
+ just DETACHES; ESC never closes the pty) — so the false-stop risk that
287
+ kept the flag off for plain windows (task dfa17461) does not exist here.
288
+ Right-click a tab -> Kill => SIGHUP => agent flips desired_state=stopped
289
+ server-side and exits clean: offline, NO hostd ghost-respawn (mig 494
290
+ coherent). A real crash never runs the handler => crash-respawn intact."""
231
291
  if "exec " in cmd:
232
292
  head, _, tail = cmd.rpartition("exec ")
233
293
  cmd = head + tail
234
- return (f'{cmd}; MC_RC=$?; if [ "$MC_RC" = "143" ]; then exit 0; fi; '
294
+ return (f'export MESHCODE_CLOSE_STOP_SIGHUP=1; '
295
+ f'{cmd}; MC_RC=$?; if [ "$MC_RC" = "143" ]; then exit 0; fi; '
235
296
  f'echo "[meshcode] agent exited rc=$MC_RC — tab kept for debugging"; exit $MC_RC')
236
297
 
237
298
 
@@ -296,7 +357,7 @@ def _spawn_fleet_tab(cmd: str) -> tuple[bool, str]:
296
357
  tmux = _find_tmux()
297
358
  if not tmux:
298
359
  return False, "tmux not installed (brew install tmux -> tabbed fleet window)"
299
- label = _launcher_label(cmd)
360
+ label = _fleet_tab_name(cmd)
300
361
  wrapped = _fleet_wrap(cmd)
301
362
  try:
302
363
  fresh_session = _tmux(tmux, "has-session", "-t", f"={_FLEET_SESSION}").returncode != 0
@@ -317,13 +378,14 @@ def _spawn_fleet_tab(cmd: str) -> tuple[bool, str]:
317
378
  "-n", label, "-P", "-F", "#{window_id}", wrapped)
318
379
  if r.returncode != 0:
319
380
  return False, f"tmux new-window: {(r.stderr or '').strip()}"
320
- else:
321
- # Session bootstrap (once). mouse = click a tab name in the status
322
- # bar to switch; detach-on-destroy = when the last tab closes, the
323
- # attach client exits and the fleet.command closes its own window.
324
- for opt in (("mouse", "on"), ("detach-on-destroy", "on"),
325
- ("status-left", "[MeshCode Fleet] "), ("status-left-length", "20")):
326
- _tmux(tmux, "set-option", "-t", f"={_FLEET_SESSION}:", *opt)
381
+ # Session options, applied on EVERY spawn (idempotent): mouse = click a
382
+ # tab in the bar to switch; detach-on-destroy = when the last tab
383
+ # closes, the attach client exits and the fleet.command closes its own
384
+ # window; _FLEET_STYLE = the native-looking top tab bar. Always-apply
385
+ # (was bootstrap-only) so a session created by an OLDER wheel restyles
386
+ # the moment any agent launches through this code.
387
+ for opt in (("mouse", "on"), ("detach-on-destroy", "on"), *_FLEET_STYLE):
388
+ _tmux(tmux, "set-option", "-t", f"={_FLEET_SESSION}:", *opt)
327
389
  win_id = (r.stdout or "").strip()
328
390
  if win_id.startswith("@"):
329
391
  # Per-tab window options: a CRASHED agent's pane stays (rc!=0 ->
@@ -360,8 +422,11 @@ def _spawn_fleet_tab(cmd: str) -> tuple[bool, str]:
360
422
  ok, info = _fleet_attach_linux(tmux)
361
423
  if not ok:
362
424
  # Tab exists + agent runs, but invisibly — that breaks the
363
- # visibility contract. Kill the tab and let legacy spawn a window.
364
- _tmux(tmux, "kill-window", "-t", f"={_FLEET_SESSION}:{label}")
425
+ # visibility contract. Kill the tab and let legacy spawn a
426
+ # window. Target by @id when we have it (tab names are now
427
+ # short agent names and CAN collide across projects).
428
+ _tmux(tmux, "kill-window", "-t",
429
+ win_id if win_id.startswith("@") else f"={_FLEET_SESSION}:{label}")
365
430
  return False, f"fleet attach window failed: {info}"
366
431
  return True, f"{info}(fleet-window+tab)"
367
432
  return True, "fleet-tab"
@@ -369,6 +434,326 @@ def _spawn_fleet_tab(cmd: str) -> tuple[bool, str]:
369
434
  return False, f"tmux fleet failed: {e}"
370
435
 
371
436
 
437
+ # ============================================================
438
+ # fleet NATIVE Terminal.app tabs — macOS (task 4df5a126, Samuel GO 9a6e0f02)
439
+ # ============================================================
440
+ # Samuel visually CONFIRMED (screenshot 2026-06-11 11:47) that the System
441
+ # Events click of Shell > New Tab > <profile> creates a REAL native tab.
442
+ # Why every scripted probe said "window": macOS native tabs are SEPARATE
443
+ # NSWindows grouped into one frame — Terminal's AppleScript `windows`
444
+ # enumerates each grouped tab as its own window object with `tabs=1`, so
445
+ # AppleScript COUNTS CANNOT distinguish a grouped tab from a loose window.
446
+ # All earlier "FAIL: new window created" verdicts were this measurement
447
+ # blindness, not failures.
448
+ #
449
+ # Architecture (TCC-safe — the back-2 Mac poisoning note in
450
+ # _spawn_terminal_macos forbids Apple Events FROM THE DAEMON):
451
+ # - The FIRST agent launches via `open -a Terminal <agent>.fleet.command`
452
+ # (the blessed no-Apple-Events path) and becomes the ANCHOR: its shell
453
+ # starts the lock-gated fleet WATCHER in the background. The watcher
454
+ # runs INSIDE Terminal, so Terminal stays its own TCC responsible
455
+ # process for both Apple Events and the Accessibility click (verified
456
+ # granted + working live on the target box 2026-06-11).
457
+ # - Later agents are SPOOLED (~/.meshcode/launchers/fleet-spool/): the
458
+ # watcher runs the GREEN RECIPE per spool entry — raise anchor window,
459
+ # READ the New Tab submenu, click profile item 1, find what appeared
460
+ # (same-window tab OR new grouped NSWindow), `do script` the agent
461
+ # into it. hostd blocks on a .done marker; "fallback"/timeout cascades
462
+ # to the tmux fleet bar, then to legacy one-window-per-agent.
463
+ # - EVERY fleet agent shell offers to become watcher (lock-gated, stale
464
+ # lock stolen after 12s) so closing the anchor tab only moves the
465
+ # watcher to another tab within seconds.
466
+ # - close-tab=STOP (Samuel 68b1c17b): tabs export
467
+ # MESHCODE_CLOSE_STOP_SIGHUP=1 — closing a native tab closes its pty,
468
+ # SIGHUP arms the MCP close=stop handler (b6da0d54), agent flips
469
+ # desired_state=stopped and exits clean (no hostd ghost-respawn,
470
+ # mig 494 coherent). Clean exits (rc 0/143) self-close ONLY their tab;
471
+ # crashes keep the tab + scrollback for debugging.
472
+ # Known trade-off: each spooled spawn raises Terminal + the fleet frame
473
+ # (the menu click needs frontmost) — focus moves during a Launch All burst,
474
+ # which is the moment the spec wants focus anyway.
475
+
476
+ _FLEET_NATIVE_DISABLED_TTL_S = 1800 # back off after a watcher "fallback"
477
+
478
+
479
+ def _fleet_native_paths() -> dict:
480
+ d = Path.home() / ".meshcode" / "launchers"
481
+ return {
482
+ "dir": d,
483
+ "spool": d / "fleet-spool",
484
+ "alive": d / "fleet-native-alive",
485
+ "pending": d / "fleet-native-pending",
486
+ "disabled": d / "fleet-native-disabled",
487
+ "watcher": d / "meshcode-fleet-watcher.sh",
488
+ "log": d / "fleet-native.log",
489
+ }
490
+
491
+
492
+ _FLEET_NATIVE_DRIVER_AS = r'''on run argv
493
+ set myTTY to item 1 of argv
494
+ set agentCmd to item 2 of argv
495
+ tell application "Terminal"
496
+ set myWin to missing value
497
+ repeat with w in windows
498
+ repeat with t in tabs of w
499
+ try
500
+ if (tty of t) is myTTY then set myWin to w
501
+ end try
502
+ end repeat
503
+ end repeat
504
+ if myWin is missing value then error "anchor window not found"
505
+ set idsBefore to id of every window
506
+ set tabsBefore to count of tabs of myWin
507
+ activate
508
+ set index of myWin to 1
509
+ try
510
+ set frontmost of myWin to true
511
+ end try
512
+ end tell
513
+ delay 0.8
514
+ tell application "System Events"
515
+ tell process "Terminal"
516
+ set frontmost to true
517
+ delay 0.3
518
+ -- GREEN-RECIPE RC (commander 9a6e0f02, Samuel screenshot 11:47):
519
+ -- READ the New Tab submenu BEFORE clicking. The read forces AppKit to
520
+ -- populate the menu; the click on an unpopulated menu intermittently
521
+ -- degraded to a loose window. DO NOT REMOVE THIS LINE.
522
+ set subItems to name of menu items of menu 1 of menu item "New Tab" of menu "Shell" of menu bar 1
523
+ click menu item 1 of menu 1 of menu item "New Tab" of menu "Shell" of menu bar 1
524
+ end tell
525
+ end tell
526
+ set targetId to 0
527
+ set targetKind to ""
528
+ repeat with i from 1 to 12
529
+ delay 0.5
530
+ tell application "Terminal"
531
+ if (count of tabs of myWin) > tabsBefore then
532
+ set targetKind to "tab"
533
+ else
534
+ repeat with w in windows
535
+ if idsBefore does not contain (id of w) then
536
+ set targetId to id of w
537
+ set targetKind to "win"
538
+ end if
539
+ end repeat
540
+ end if
541
+ end tell
542
+ if targetKind is not "" then exit repeat
543
+ end repeat
544
+ if targetKind is "" then error "no new tab appeared after menu click"
545
+ tell application "Terminal"
546
+ if targetKind is "tab" then
547
+ do script agentCmd in tab (tabsBefore + 1) of myWin
548
+ else
549
+ -- grouped NSWindow tab: `do script in window id` reuses its fresh
550
+ -- selected shell (verified live 2026-06-11) — exactly what we want.
551
+ do script agentCmd in window id targetId
552
+ end if
553
+ end tell
554
+ return "ok"
555
+ end run'''
556
+
557
+
558
+ def _write_fleet_native_watcher() -> Path:
559
+ """Write (idempotently) the lock-gated spool watcher that creates native
560
+ tabs from INSIDE Terminal. See the architecture block above."""
561
+ p = _fleet_native_paths()
562
+ body = '''#!/bin/bash
563
+ # meshcode fleet native-tabs watcher — GENERATED by protocol_handler.py
564
+ # (task 4df5a126). Runs INSIDE a Terminal tab (TCC: Terminal stays its own
565
+ # responsible process). One holder at a time (lock dir, stale-steal 12s).
566
+ LAUNCH="$HOME/.meshcode/launchers"
567
+ SPOOL="$LAUNCH/fleet-spool"
568
+ LOCK="$LAUNCH/fleet-native-lock"
569
+ ALIVE="$LAUNCH/fleet-native-alive"
570
+ MYTTY="$1"
571
+ exec >>"$LAUNCH/fleet-native.log" 2>&1
572
+ mkdir -p "$SPOOL"
573
+ while :; do
574
+ if mkdir "$LOCK" 2>/dev/null; then
575
+ echo "$$ $MYTTY $(date)" > "$LOCK/owner"
576
+ break
577
+ fi
578
+ AGE=999
579
+ if [ -f "$ALIVE" ]; then
580
+ AGE=$(( $(date +%s) - $(stat -f %m "$ALIVE" 2>/dev/null || echo 0) ))
581
+ fi
582
+ if [ "$AGE" -gt 12 ]; then rm -rf "$LOCK"; continue; fi
583
+ sleep 3
584
+ done
585
+ trap 'rm -rf "$LOCK"; exit 0' EXIT HUP TERM INT
586
+ echo "[watcher] $$ holds lock (tty $MYTTY)"
587
+ N=0
588
+ while :; do
589
+ date +%s > "$ALIVE"
590
+ for f in "$SPOOL"/*.cmd; do
591
+ [ -e "$f" ] || continue
592
+ CMD="$(cat "$f")"
593
+ BASE="${f%.cmd}"
594
+ echo "[watcher] tab spawn: $CMD"
595
+ if /usr/bin/osascript "$LAUNCH/fleet-native-driver.applescript" "$MYTTY" "$CMD"
596
+ then
597
+ echo ok > "$BASE.done"
598
+ else
599
+ echo fallback > "$BASE.done"
600
+ fi
601
+ rm -f "$f"
602
+ done
603
+ N=$((N+1))
604
+ if [ $((N % 300)) -eq 0 ]; then
605
+ find "$SPOOL" -name '*.done' -mmin +60 -delete 2>/dev/null
606
+ fi
607
+ sleep 1
608
+ done
609
+ '''
610
+ p["dir"].mkdir(parents=True, exist_ok=True)
611
+ driver = p["dir"] / "fleet-native-driver.applescript"
612
+ driver.write_text(_FLEET_NATIVE_DRIVER_AS + "\n", encoding="utf-8")
613
+ p["watcher"].write_text(body, encoding="utf-8")
614
+ os.chmod(p["watcher"], 0o755)
615
+ return p["watcher"]
616
+
617
+
618
+ def _write_fleet_native_agent(cmd: str) -> Path:
619
+ """Write the per-agent fleet command file (runs the agent inside its
620
+ native tab; offers to become watcher; close-tab=stop; clean exits close
621
+ ONLY their own tab). Filename keyed by _launcher_label (unique per
622
+ project/agent target); the visible TAB TITLE is the short agent name."""
623
+ p = _fleet_native_paths()
624
+ title = _fleet_tab_name(cmd)
625
+ script_path = p["dir"] / f"{_launcher_label(cmd)}.fleet.command"
626
+ try:
627
+ venv_bin = str(Path(sys.executable).parent)
628
+ except Exception:
629
+ venv_bin = ""
630
+ if "exec " in cmd:
631
+ _head, _, _tail = cmd.rpartition("exec ")
632
+ run_line = _head + _tail # agent as CHILD so bash survives to close the tab
633
+ else:
634
+ run_line = cmd
635
+ lines = [
636
+ "#!/bin/bash",
637
+ 'cd "$HOME" 2>/dev/null || cd /',
638
+ rf"printf '\033]0;{title}\007\033]1;{title}\007'",
639
+ ]
640
+ if venv_bin:
641
+ lines.append(f'export PATH={shlex.quote(venv_bin)}:"$PATH"')
642
+ lines += [
643
+ # close-tab=STOP (Samuel 68b1c17b) — see architecture block.
644
+ "export MESHCODE_CLOSE_STOP_SIGHUP=1",
645
+ 'MC_TTY="$(tty 2>/dev/null)"',
646
+ # every fleet tab offers to run the watcher (lock-gated)
647
+ f'/bin/bash {shlex.quote(str(p["watcher"]))} "$MC_TTY" >/dev/null 2>&1 &',
648
+ "disown",
649
+ run_line,
650
+ "MC_RC=$?",
651
+ # clean exit (0, or 143 = hostd stop sweep): close ONLY this tab.
652
+ # Crash: keep tab + scrollback (debugging > clean window).
653
+ 'if { [ "$MC_RC" = "0" ] || [ "$MC_RC" = "143" ]; } && [ -n "$MC_TTY" ]; then',
654
+ " /usr/bin/osascript"
655
+ " -e 'on run argv'"
656
+ " -e 'tell application \"Terminal\"'"
657
+ " -e 'repeat with w in windows'"
658
+ " -e 'repeat with t in tabs of w'"
659
+ " -e 'try'"
660
+ " -e 'if (tty of t) is (item 1 of argv) then close t saving no'"
661
+ " -e 'end try'"
662
+ " -e 'end repeat'"
663
+ " -e 'end repeat'"
664
+ " -e 'end tell'"
665
+ " -e 'end run' \"$MC_TTY\" >/dev/null 2>&1",
666
+ "else",
667
+ ' echo "[meshcode] agent exited rc=$MC_RC — tab kept for debugging"',
668
+ "fi",
669
+ ]
670
+ p["dir"].mkdir(parents=True, exist_ok=True)
671
+ script_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
672
+ os.chmod(script_path, 0o755)
673
+ return script_path
674
+
675
+
676
+ def _spawn_fleet_native_macos(cmd: str) -> tuple[bool, str]:
677
+ """Spawn `cmd` as a NATIVE Terminal.app tab of the shared fleet window.
678
+
679
+ Returns (False, reason) on ANY failure — caller cascades to the tmux
680
+ fleet bar, then legacy windows, so this can never make launches worse."""
681
+ p = _fleet_native_paths()
682
+ # back-off marker: a recent watcher "fallback" (Accessibility revoked,
683
+ # menu shape changed, ...) disables the native path for a while instead
684
+ # of paying a focus-steal + multi-second failure on every launch.
685
+ try:
686
+ if time.time() - p["disabled"].stat().st_mtime < _FLEET_NATIVE_DISABLED_TTL_S:
687
+ return False, "fleet-native recently failed (back-off)"
688
+ except OSError:
689
+ pass
690
+ try:
691
+ p["spool"].mkdir(parents=True, exist_ok=True)
692
+ _write_fleet_native_watcher()
693
+ agent_file = _write_fleet_native_agent(cmd)
694
+ except Exception as e:
695
+ return False, f"could not write fleet-native scripts: {e}"
696
+
697
+ def _alive_age() -> float:
698
+ try:
699
+ return time.time() - p["alive"].stat().st_mtime
700
+ except OSError:
701
+ return 1e9
702
+
703
+ if _alive_age() > 8:
704
+ pend_fresh = False
705
+ try:
706
+ pend_fresh = (time.time() - p["pending"].stat().st_mtime) < 25
707
+ except OSError:
708
+ pass
709
+ if not pend_fresh:
710
+ # become the ANCHOR: first visible tab, watcher host
711
+ try:
712
+ p["pending"].touch()
713
+ except OSError:
714
+ pass
715
+ r = subprocess.run(["open", "-a", "Terminal", str(agent_file)],
716
+ capture_output=True, text=True)
717
+ if r.returncode == 0:
718
+ return True, "terminal(fleet-native-anchor)"
719
+ return False, (r.stderr or "open failed").strip()
720
+ # an anchor is booting — wait for its watcher before spooling
721
+ deadline = time.time() + 25
722
+ while time.time() < deadline and _alive_age() > 8:
723
+ time.sleep(0.5)
724
+ if _alive_age() > 8:
725
+ return False, "fleet-native anchor never came alive"
726
+
727
+ sp = p["spool"] / f"{time.time_ns()}-{_launcher_label(cmd)}.cmd"
728
+ done = sp.with_suffix(".done")
729
+ try:
730
+ sp.write_text(f"/bin/bash {shlex.quote(str(agent_file))}\n", encoding="utf-8")
731
+ except Exception as e:
732
+ return False, f"fleet-native spool write failed: {e}"
733
+ deadline = time.time() + 20
734
+ while time.time() < deadline:
735
+ if done.exists():
736
+ try:
737
+ verdict = done.read_text().strip()
738
+ done.unlink()
739
+ except OSError:
740
+ verdict = ""
741
+ if verdict == "ok":
742
+ return True, "fleet-native-tab"
743
+ try:
744
+ p["disabled"].touch()
745
+ except OSError:
746
+ pass
747
+ return False, f"fleet-native watcher reported {verdict or 'error'}"
748
+ time.sleep(0.4)
749
+ # timeout: pull the spool entry so a late watcher can't double-spawn
750
+ try:
751
+ sp.unlink()
752
+ except OSError:
753
+ pass
754
+ return False, "fleet-native spool timeout"
755
+
756
+
372
757
  def _spawn_terminal_macos(cmd: str) -> tuple[bool, str]:
373
758
  """Spawn `cmd` in a new VISIBLE Terminal/iTerm window (detached).
374
759
 
@@ -595,7 +980,10 @@ def _spawn_terminal_windows(cmd: str) -> tuple[bool, str]:
595
980
  # carries one → the cmdline splits and wt fails with 0x80070002.
596
981
  # Escape ONLY here; the cmd.exe fallback below stays unescaped
597
982
  # (cmd.exe does not split on ';').
598
- label = _launcher_label(cmd)
983
+ # Short agent-only tab title (task 4df5a126) — same readability fix
984
+ # as the macOS fleet bar; sanitized [A-Za-z0-9_.-] so it can't
985
+ # smuggle wt args.
986
+ label = _fleet_tab_name(cmd)
599
987
  subprocess.Popen([wt, "-w", "meshcode-fleet", "nt",
600
988
  "--title", label or "meshcode-agent",
601
989
  "--suppressApplicationTitle",
@@ -612,16 +1000,22 @@ def _spawn_terminal_windows(cmd: str) -> tuple[bool, str]:
612
1000
 
613
1001
  def _spawn_terminal(cmd: str) -> tuple[bool, str]:
614
1002
  p = platform.system()
615
- if p in ("Darwin", "Linux"):
616
- # Fleet tabs first (task 2ac3f111): one shared window, one tab per agent.
617
- # Any failure (tmux absent, session error, attach window failed) falls
618
- # back to the legacy one-window-per-agent spawn below — never worse.
1003
+ if p == "Darwin":
1004
+ # 1) NATIVE Terminal tabs (task 4df5a126, Samuel GO) one window,
1005
+ # one real tab per agent, close-tab=stop.
1006
+ ok, info = _spawn_fleet_native_macos(cmd)
1007
+ if ok:
1008
+ return True, info
1009
+ # 2) tmux fleet bar (task 2ac3f111) — shared window, styled tab bar.
619
1010
  ok, info = _spawn_fleet_tab(cmd)
620
1011
  if ok:
621
1012
  return True, info
622
- if p == "Darwin":
1013
+ # 3) legacy one-window-per-agent — never worse than before.
623
1014
  return _spawn_terminal_macos(cmd)
624
1015
  if p == "Linux":
1016
+ ok, info = _spawn_fleet_tab(cmd)
1017
+ if ok:
1018
+ return True, info
625
1019
  return _spawn_terminal_linux(cmd)
626
1020
  if p == "Windows":
627
1021
  # Windows Terminal tabs are native: _spawn_terminal_windows targets the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.132
3
+ Version: 2.11.133
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.132"
7
+ version = "2.11.133"
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