swarph-cli 0.69.0__tar.gz → 0.69.1__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 (445) hide show
  1. {swarph_cli-0.69.0/src/swarph_cli.egg-info → swarph_cli-0.69.1}/PKG-INFO +1 -1
  2. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/pyproject.toml +1 -1
  3. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/__init__.py +1 -1
  4. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/mesh.py +180 -11
  5. {swarph_cli-0.69.0 → swarph_cli-0.69.1/src/swarph_cli.egg-info}/PKG-INFO +1 -1
  6. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_mesh_sidecar.py +1 -0
  7. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_tmux_wake_runstate_defer.py +2 -0
  8. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_tmux_wake_submit_verify.py +197 -4
  9. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/LICENSE +0 -0
  10. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/README.md +0 -0
  11. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/setup.cfg +0 -0
  12. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/__main__.py +0 -0
  13. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/bench/__init__.py +0 -0
  14. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/bench/backends.py +0 -0
  15. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/bench/pack.py +0 -0
  16. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/bench/prices.py +0 -0
  17. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/bench/providers.py +0 -0
  18. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/bench/quality.py +0 -0
  19. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/bench/refresh_prices.py +0 -0
  20. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/bench/rules.py +0 -0
  21. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/bench/runner.py +0 -0
  22. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/bench/validate.py +0 -0
  23. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/caller.py +0 -0
  24. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/capture/__init__.py +0 -0
  25. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/capture/harden.py +0 -0
  26. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/capture/lineage.py +0 -0
  27. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/capture/liveness.py +0 -0
  28. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/capture/manifest.py +0 -0
  29. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/capture/paths.py +0 -0
  30. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/capture/verify.py +0 -0
  31. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/cell.py +0 -0
  32. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/chain_token.py +0 -0
  33. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/channel.py +0 -0
  34. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/__init__.py +0 -0
  35. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/_content.py +0 -0
  36. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/_display.py +0 -0
  37. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/_gateway_client.py +0 -0
  38. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/add.py +0 -0
  39. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/bench.py +0 -0
  40. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/board.py +0 -0
  41. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/board_merge_check.py +0 -0
  42. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/brain.py +0 -0
  43. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/brain_ask.py +0 -0
  44. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/cell.py +0 -0
  45. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/cell_probe.py +0 -0
  46. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  47. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/channel.py +0 -0
  48. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/chat.py +0 -0
  49. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/codegraph.py +0 -0
  50. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/codegraph_hook.py +0 -0
  51. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  52. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/codex_waker.py +0 -0
  53. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/compress.py +0 -0
  54. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/daemon.py +0 -0
  55. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/dreaming.py +0 -0
  56. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/event.py +0 -0
  57. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/gateway.py +0 -0
  58. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/gh_route.py +0 -0
  59. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/group.py +0 -0
  60. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/guide.py +0 -0
  61. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/highlight.py +0 -0
  62. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/hook_interpreter.py +0 -0
  63. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/hook_output.py +0 -0
  64. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/hooks.py +0 -0
  65. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/import_session.py +0 -0
  66. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/init.py +0 -0
  67. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  68. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/install_hook.py +0 -0
  69. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  70. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
  71. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
  72. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  73. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/lane.py +0 -0
  74. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/mcp_server.py +0 -0
  75. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/memory.py +0 -0
  76. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
  77. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/memory_sync.py +0 -0
  78. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/monitor.py +0 -0
  79. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/okf_links.py +0 -0
  80. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/onboard.py +0 -0
  81. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  82. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  83. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/protocol_handler.py +0 -0
  84. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/ratify.py +0 -0
  85. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/schedule.py +0 -0
  86. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/security.py +0 -0
  87. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/service.py +0 -0
  88. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/spawn.py +0 -0
  89. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/timeline.py +0 -0
  90. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/version.py +0 -0
  91. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/wake_hook_output.py +0 -0
  92. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/commands/watchdog.py +0 -0
  93. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/compress/__init__.py +0 -0
  94. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/compress/levers.py +0 -0
  95. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/compress/marker.py +0 -0
  96. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/compress/verify.py +0 -0
  97. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/console_safe.py +0 -0
  98. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/delivery_queue.py +0 -0
  99. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dm_frame.py +0 -0
  100. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/__init__.py +0 -0
  101. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/candidates.py +0 -0
  102. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/clone.py +0 -0
  103. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/enrich.py +0 -0
  104. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/index_check.py +0 -0
  105. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/notify.py +0 -0
  106. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/organize.py +0 -0
  107. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/probes.py +0 -0
  108. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/report.py +0 -0
  109. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/run.py +0 -0
  110. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/slm.py +0 -0
  111. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/transcripts.py +0 -0
  112. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/dreaming/verify.py +0 -0
  113. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/gateway/__init__.py +0 -0
  114. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/gateway/feature_registry.py +0 -0
  115. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/gateway/lanes_control.py +0 -0
  116. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/gateway/schema.sql +0 -0
  117. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/gateway/server.py +0 -0
  118. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/gateway/services_control.py +0 -0
  119. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/gateway_default.py +0 -0
  120. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/gh_identity.py +0 -0
  121. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/guide/GUIDE.md +0 -0
  122. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/identity.py +0 -0
  123. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/main.py +0 -0
  124. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/multiplexer.py +0 -0
  125. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/orphan_daemons.py +0 -0
  126. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/pane_probe.py +0 -0
  127. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/parsers/__init__.py +0 -0
  128. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/parsers/claude.py +0 -0
  129. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
  130. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  131. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  132. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  133. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  134. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  135. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  136. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  137. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  138. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  139. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  140. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  141. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/peer_executor.py +0 -0
  142. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/peer_executor_windows.py +0 -0
  143. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/peer_reconciliation.py +0 -0
  144. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/peer_reply_outbox.py +0 -0
  145. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/peer_service_host.py +0 -0
  146. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/peer_service_payload.py +0 -0
  147. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/peer_service_reply.py +0 -0
  148. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/peer_staging.py +0 -0
  149. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/query_filters.py +0 -0
  150. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/scripts/__init__.py +0 -0
  151. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  152. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  153. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  154. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  155. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
  156. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/service/__init__.py +0 -0
  157. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/service/app.py +0 -0
  158. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/service/providers.py +0 -0
  159. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/session_bridge.py +0 -0
  160. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  161. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  162. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/source_text.py +0 -0
  163. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/stall_alert.py +0 -0
  164. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/codex-waker.default +0 -0
  165. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  166. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  167. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  168. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  169. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  170. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
  171. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
  172. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  173. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  174. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  175. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  176. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  177. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  178. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/timeline_paths.py +0 -0
  179. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli/tokens.py +0 -0
  180. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli.egg-info/SOURCES.txt +0 -0
  181. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  182. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  183. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli.egg-info/requires.txt +0 -0
  184. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/src/swarph_cli.egg-info/top_level.txt +0 -0
  185. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_124_register_merge.py +0 -0
  186. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_126_pending_from_complete.py +0 -0
  187. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  188. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_138_memory_navigate.py +0 -0
  189. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_139_tool_probe.py +0 -0
  190. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_183_card_anchor.py +0 -0
  191. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_184_notify_honesty.py +0 -0
  192. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_201_win32_bash_refusal.py +0 -0
  193. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_243_onboard_per_peer_token.py +0 -0
  194. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_307_task4_ask_reply.py +0 -0
  195. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  196. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_319_refusal_exit_codes.py +0 -0
  197. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_323_mistral_backend.py +0 -0
  198. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_332_report_organize_findings.py +0 -0
  199. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_356_query_filters.py +0 -0
  200. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_397_gh_identity_router.py +0 -0
  201. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_397_router_preflight.py +0 -0
  202. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_402_one_identity_resolver.py +0 -0
  203. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_467b_onboard_operator_credential.py +0 -0
  204. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_472_register_caller_binding.py +0 -0
  205. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_523_guide.py +0 -0
  206. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_524_conftest_hermeticity.py +0 -0
  207. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_532_accept_flag.py +0 -0
  208. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_535_version_capability.py +0 -0
  209. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_546_default_gateway.py +0 -0
  210. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_547_verbs_from_registry.py +0 -0
  211. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_548_gateway_remainder.py +0 -0
  212. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_552_codegraph_gateway.py +0 -0
  213. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_555_relay_row_shape.py +0 -0
  214. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_556_relay_freshness.py +0 -0
  215. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_559_edges_truncated.py +0 -0
  216. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_564_bootstrap_first_peer.py +0 -0
  217. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  218. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_579_register_bootstrap_message.py +0 -0
  219. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_591_cli_step_graph.py +0 -0
  220. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_644_monitor_supervision.py +0 -0
  221. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_648_install_unit.py +0 -0
  222. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_654_reexec.py +0 -0
  223. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_656_owned_slm.py +0 -0
  224. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_684_dreaming_verb.py +0 -0
  225. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_689_pkg_version_order.py +0 -0
  226. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_716_timeline_one_path.py +0 -0
  227. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_724_ps1_ascii_or_bom.py +0 -0
  228. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_725_stdio_reconfigure.py +0 -0
  229. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_729_dm_once.py +0 -0
  230. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_729_wake_watchdog.py +0 -0
  231. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_734_dreaming_enrich_degrade.py +0 -0
  232. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_735_dm_mcp_tools.py +0 -0
  233. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_740_edit_project.py +0 -0
  234. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_762_cards_edit_priority.py +0 -0
  235. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_764_enrich_collapse.py +0 -0
  236. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_801_confirm_flow_cli.py +0 -0
  237. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_802_stage_history.py +0 -0
  238. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_825_codegraph_hook_noise.py +0 -0
  239. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_825_install_posttooluse_only.py +0 -0
  240. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_825_remaining_cap_shred_bind.py +0 -0
  241. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_829_counterfactual_column.py +0 -0
  242. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_830_hook_binding_version.py +0 -0
  243. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_84_cli_labels.py +0 -0
  244. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_866_doctrine_guide.py +0 -0
  245. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_872_identity_refuses_not_warns.py +0 -0
  246. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_874_source_text.py +0 -0
  247. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
  248. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_937_dreaming_notify.py +0 -0
  249. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_938_organize_line_limit.py +0 -0
  250. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_941_bench_backends.py +0 -0
  251. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_941_harness_342.py +0 -0
  252. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_945_same_line_pairing.py +0 -0
  253. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_955_prompt_audit.py +0 -0
  254. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_957_auth_http.py +0 -0
  255. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_959_venv_interpreter.py +0 -0
  256. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_960_channel.py +0 -0
  257. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_963_plugin_manifest.py +0 -0
  258. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_964_channel_cell.py +0 -0
  259. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_965_mesh_wait.py +0 -0
  260. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_975_channel_hop.py +0 -0
  261. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_add_security_gate.py +0 -0
  262. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_artifact_add.py +0 -0
  263. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_artifact_hash.py +0 -0
  264. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_artifact_lib.py +0 -0
  265. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_artifact_mcp.py +0 -0
  266. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_artifact_skill.py +0 -0
  267. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_artifact_tool.py +0 -0
  268. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_artifact_uri.py +0 -0
  269. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_bench_backends.py +0 -0
  270. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_bench_command.py +0 -0
  271. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_bench_pack.py +0 -0
  272. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_bench_prices.py +0 -0
  273. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_bench_quality.py +0 -0
  274. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_bench_runner.py +0 -0
  275. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_bench_validate.py +0 -0
  276. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_board_card_thread.py +0 -0
  277. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_board_command.py +0 -0
  278. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_board_merge_check.py +0 -0
  279. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_board_obligation_close.py +0 -0
  280. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_brain_ask_command.py +0 -0
  281. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_brain_ask_env_diagnosis.py +0 -0
  282. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_brain_ask_identity_explicitness.py +0 -0
  283. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_brain_command.py +0 -0
  284. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_caller_meta_guard.py +0 -0
  285. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_capture_lineage.py +0 -0
  286. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_capture_liveness.py +0 -0
  287. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_capture_manifest.py +0 -0
  288. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_capture_paths.py +0 -0
  289. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_capture_security.py +0 -0
  290. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_cell_command_dispatch.py +0 -0
  291. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_cell_harden.py +0 -0
  292. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_cell_loader.py +0 -0
  293. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_cell_selfcheck.py +0 -0
  294. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_cell_verify.py +0 -0
  295. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_chain_token.py +0 -0
  296. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_channel_command.py +0 -0
  297. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  298. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_channel_post.py +0 -0
  299. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_channel_wake_policy_filter.py +0 -0
  300. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_chat_command.py +0 -0
  301. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_claude_parser.py +0 -0
  302. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_claude_tmux_template.py +0 -0
  303. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_codegraph_caller_scope.py +0 -0
  304. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_codegraph_command.py +0 -0
  305. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_codegraph_hook.py +0 -0
  306. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_codegraph_mcp.py +0 -0
  307. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_codex_waker.py +0 -0
  308. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_compress_caller_convention.py +0 -0
  309. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_compress_command.py +0 -0
  310. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_compress_levers.py +0 -0
  311. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_compress_marker.py +0 -0
  312. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_compress_verify.py +0 -0
  313. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_console_encoding_e2e.py +0 -0
  314. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_content_composition.py +0 -0
  315. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_cursor_membrane.py +0 -0
  316. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_daemon_command.py +0 -0
  317. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_daemon_console_encoding.py +0 -0
  318. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_daemon_delivery.py +0 -0
  319. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_delivery_queue.py +0 -0
  320. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_display_sanitize.py +0 -0
  321. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  322. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_event_emit.py +0 -0
  323. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_feature_to_uri.py +0 -0
  324. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_gateway_brain.py +0 -0
  325. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_gateway_client.py +0 -0
  326. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_gateway_command.py +0 -0
  327. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_gateway_message_idempotency.py +0 -0
  328. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  329. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_group_command.py +0 -0
  330. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_guide_commands_parse.py +0 -0
  331. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_guide_selfcheck.py +0 -0
  332. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_heartbeat_check.py +0 -0
  333. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_highlight_command.py +0 -0
  334. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hook_output.py +0 -0
  335. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hooks_activity_marker.py +0 -0
  336. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hooks_add.py +0 -0
  337. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hooks_bundle.py +0 -0
  338. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hooks_init.py +0 -0
  339. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hooks_legacy_generation_removal.py +0 -0
  340. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hooks_lifecycle.py +0 -0
  341. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hooks_merge.py +0 -0
  342. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hooks_verify.py +0 -0
  343. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  344. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_hooks_win32_command_path.py +0 -0
  345. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_import_command.py +0 -0
  346. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_inbox_identity_provenance.py +0 -0
  347. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_init_command.py +0 -0
  348. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_init_provider_menu.py +0 -0
  349. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_install_codex_hooks.py +0 -0
  350. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_install_hook.py +0 -0
  351. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_install_multiplexer_command.py +0 -0
  352. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_install_postcompact_hook.py +0 -0
  353. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_install_wake_hook.py +0 -0
  354. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_lane_command.py +0 -0
  355. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_main.py +0 -0
  356. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_main_unknown_verb_guard.py +0 -0
  357. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_mcp_missing_hint.py +0 -0
  358. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_mcp_server.py +0 -0
  359. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_memory_command.py +0 -0
  360. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_memory_emit_snippet.py +0 -0
  361. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_memory_gateway.py +0 -0
  362. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_memory_sync.py +0 -0
  363. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_memory_sync_membrane.py +0 -0
  364. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_mesh_command.py +0 -0
  365. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_mesh_inbox_mark_read.py +0 -0
  366. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_mesh_inbox_sanitize.py +0 -0
  367. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_mesh_originate_thread_623.py +0 -0
  368. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_mesh_send_unknown_peer.py +0 -0
  369. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  370. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  371. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_meta_edge_identity.py +0 -0
  372. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_monitor_channel_poll.py +0 -0
  373. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_monitor_cli.py +0 -0
  374. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_monitor_daemon_collision.py +0 -0
  375. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_monitor_self_name_verification.py +0 -0
  376. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_monitor_state_split.py +0 -0
  377. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_multiplexer.py +0 -0
  378. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_muse_membrane.py +0 -0
  379. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_muse_own_cli.py +0 -0
  380. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_obligation_close_is_surfaced.py +0 -0
  381. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_okf_links.py +0 -0
  382. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_onboard_command.py +0 -0
  383. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_opencode_membrane.py +0 -0
  384. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_opencode_plugin.py +0 -0
  385. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_orphan_daemons.py +0 -0
  386. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_packaged_artifacts_exist.py +0 -0
  387. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_packaged_skills.py +0 -0
  388. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_peer_executor.py +0 -0
  389. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_peer_executor_windows.py +0 -0
  390. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_peer_reply_drain_command.py +0 -0
  391. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_peer_reply_drain_supervisor.py +0 -0
  392. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_peer_reply_outbox.py +0 -0
  393. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_peer_reply_transport.py +0 -0
  394. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_peer_service_e2e.py +0 -0
  395. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_peer_service_host.py +0 -0
  396. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_peer_service_payload.py +0 -0
  397. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_peer_service_reply.py +0 -0
  398. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_postcompact_recall.py +0 -0
  399. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_process_liveness.py +0 -0
  400. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_protocol_handler.py +0 -0
  401. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_providers_isolation.py +0 -0
  402. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_ratify_command.py +0 -0
  403. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_readme_claims_no_gateway_default.py +0 -0
  404. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_repl_caller_convention.py +0 -0
  405. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_schedule_command.py +0 -0
  406. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_schedule_create_contract.py +0 -0
  407. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_security.py +0 -0
  408. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_service_app.py +0 -0
  409. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_service_command.py +0 -0
  410. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_service_providers.py +0 -0
  411. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_session_bridge_inject.py +0 -0
  412. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_session_bridge_probe.py +0 -0
  413. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_session_bridge_resolve.py +0 -0
  414. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_session_path_role_gate.py +0 -0
  415. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_shipped_units_match_the_cli.py +0 -0
  416. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_smoke_chat.py +0 -0
  417. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_smoke_one_shot.py +0 -0
  418. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_smoke_phase_5_5.py +0 -0
  419. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_spawn_base_hoist.py +0 -0
  420. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_spawn_command.py +0 -0
  421. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_spawn_identity_stamp.py +0 -0
  422. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_spawn_live_pin.py +0 -0
  423. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_spawn_mitosis_lineage.py +0 -0
  424. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_spawn_tmux_session.py +0 -0
  425. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_spawn_windows_relaunch.py +0 -0
  426. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_stall_alert.py +0 -0
  427. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_subprocess_decode_encoding.py +0 -0
  428. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_timeline_command.py +0 -0
  429. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_tmux_wake_session_reanchor.py +0 -0
  430. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_tmux_wake_stale.py +0 -0
  431. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_token_file_one_parser.py +0 -0
  432. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_token_precedence_explicit_first.py +0 -0
  433. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_unified_token_resolver.py +0 -0
  434. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_version_command.py +0 -0
  435. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_version_consistency.py +0 -0
  436. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_vibe_membrane.py +0 -0
  437. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_watchdog.py +0 -0
  438. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_watchdog_dm_wake.py +0 -0
  439. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  440. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  441. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_watchdog_emit_health.py +0 -0
  442. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_watchdog_install_flags.py +0 -0
  443. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_watchdog_model_rung.py +0 -0
  444. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_watchdog_stale_peers.py +0 -0
  445. {swarph_cli-0.69.0 → swarph_cli-0.69.1}/tests/test_windows_waker_installer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swarph-cli
3
- Version: 0.69.0
3
+ Version: 0.69.1
4
4
  Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
5
5
  Author: Pierre Samson, Claude Opus
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swarph-cli"
7
- version = "0.69.0"
7
+ version = "0.69.1"
8
8
  description = "The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -16,6 +16,6 @@ The architecture splits CLI from substrate so:
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
- __version__ = "0.69.0"
19
+ __version__ = "0.69.1"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -1474,6 +1474,11 @@ class TmuxSink(Sink):
1474
1474
  # observation and let the fresh path take over — it defers while
1475
1475
  # running (#619) and injects at the first idle poll.
1476
1476
  if led.get("wake_outstanding") and _agent_running(self.target):
1477
+ # Opencode keeps the finished ▣ header on screen, so a deferral
1478
+ # during the turn must not clear the flag: the next idle poll
1479
+ # still owes a wake. Cursor's #620 clear stays.
1480
+ if _opencode_in_progress(self.target):
1481
+ return None
1477
1482
  led["wake_outstanding"] = False
1478
1483
  if led.get("wake_outstanding"):
1479
1484
  # Lazy: watchdog imports mesh module-level, so the reverse must
@@ -1496,6 +1501,17 @@ class TmuxSink(Sink):
1496
1501
  _tmux_enter(self.target) # one verified nudge, no new text
1497
1502
  return True
1498
1503
  if composer == "clear":
1504
+ # A finished opencode turn leaves a ▣ header with a
1505
+ # trailing duration and a clear box. The standing-wake
1506
+ # claim would swallow every later DM. Inject again.
1507
+ if _opencode_turn_finished_target(self.target):
1508
+ ok = _tmux_wake(self.target)
1509
+ if ok:
1510
+ _stamp_wake(led)
1511
+ return True
1512
+ if ok is None:
1513
+ return None
1514
+ return False
1499
1515
  # #611: a clear composer proves the wake SUBMITTED only if
1500
1516
  # the pane it was injected into is still the pane we are
1501
1517
  # reading. The ledger flag survives a respawn; the wake
@@ -1979,6 +1995,15 @@ def _log_dm(state: MonitorState, dm: dict) -> None:
1979
1995
 
1980
1996
 
1981
1997
  _WAKE_PROMPT = "check mesh"
1998
+ # Opencode has no push channel (#601). The wake is one line that names the
1999
+ # pull tool and carries no DM body, so the turn cannot answer mail it was
2000
+ # not shown. Longer than _WAKE_PROMPT, so wake-text detection strips this
2001
+ # one first.
2002
+ _OPENCODE_WAKE_PROMPT = "check mesh: swarph_dm_unread"
2003
+ # A finished turn keeps its ▣ header and adds a trailing duration
2004
+ # (`· 3.3s`). An in-progress header has no such suffix. Measured by
2005
+ # drop-on-meta-edge on 1.18.33 (card #961, post 54557).
2006
+ _OPENCODE_DONE = re.compile(r"·\s*\d+(?:\.\d+)?s\s*$")
1982
2007
  # Submit-verify bounds (#533): the settle pause lets the -l literal LAND in
1983
2008
  # the composer before Enter can submit it (the blind gesture raced this), and
1984
2009
  # the attempt bound keeps a never-submitting pane from being Enter-spammed
@@ -2072,20 +2097,155 @@ _COMPOSER_PLACEHOLDERS = ("Add a follow-up", "Ask Codex to do anything")
2072
2097
  _CURSOR_RUN_HINT = "ctrl+c to stop"
2073
2098
 
2074
2099
 
2100
+ def _only_wake_text(content: str) -> bool:
2101
+ """True when the composer holds wake text and nothing else.
2102
+
2103
+ The opencode prompt contains the cursor/claude prompt as a prefix, so
2104
+ the longer string is removed first. A stack of either prompt still
2105
+ counts as wake text (one Enter drains it). Anything left over is a
2106
+ human's line.
2107
+ """
2108
+ rest = content
2109
+ for prompt in (_OPENCODE_WAKE_PROMPT, _WAKE_PROMPT):
2110
+ rest = rest.replace(prompt, "")
2111
+ return rest.strip() == ""
2112
+
2113
+
2114
+ def _opencode_mode_row(line: str) -> bool:
2115
+ """The mode row under the input. ``--auto`` inserts a word, so the row
2116
+ is ``Build ·`` or ``Build auto ·`` (measured 1.18.33, both shapes).
2117
+ """
2118
+ s = line.strip()
2119
+ if not s.startswith("┃") or "·" not in s:
2120
+ return False
2121
+ body = s[1:].strip()
2122
+ return body.startswith("Build") or body.startswith("Plan")
2123
+
2124
+
2125
+ def _opencode_permission_row(line: str) -> bool:
2126
+ """The 1.18.33 dialog, drawn inside the box.
2127
+
2128
+ The row is ``┃ △ Permission required``. The mode row and the ``╹▀``
2129
+ border are gone on that screen, so this row is the whole signal.
2130
+ """
2131
+ s = line.strip()
2132
+ return s.startswith("┃") and "△" in s and "Permission required" in s
2133
+
2134
+
2135
+ def _is_opencode_pane(lines: list[str]) -> bool:
2136
+ """The opencode composer box, measured on 1.18.33.
2137
+
2138
+ The input row is a ``┃`` line. The mode row under it names Build or
2139
+ Plan and a ``·``. The bottom of the box is ``╹▀``. The permission
2140
+ dialog keeps the ``┃`` row and drops the mode row and the border.
2141
+ Cursor and claude do not draw any of these.
2142
+ """
2143
+ for ln in lines:
2144
+ s = ln.strip()
2145
+ if s.startswith("╹▀") or _opencode_mode_row(ln) or _opencode_permission_row(ln):
2146
+ return True
2147
+ return False
2148
+
2149
+
2150
+ def _opencode_running(lines: list[str]) -> bool:
2151
+ """True only while a turn is in progress.
2152
+
2153
+ The footer shows ``esc interrupt``, and the ▣ header has no trailing
2154
+ duration. A finished turn keeps the ▣ header and adds ``· <n>s``,
2155
+ with no interrupt hint. That pane is idle. The permission dialog is
2156
+ not a turn; it has its own branch.
2157
+ """
2158
+ if any("esc interrupt" in ln for ln in lines):
2159
+ return True
2160
+ for ln in lines:
2161
+ s = ln.strip()
2162
+ if s.startswith("▣") and not _OPENCODE_DONE.search(s):
2163
+ return True
2164
+ return False
2165
+
2166
+
2167
+ def _opencode_turn_finished(lines: list[str]) -> bool:
2168
+ """The ▣ header carried a duration and the interrupt hint is gone."""
2169
+ if _opencode_running(lines):
2170
+ return False
2171
+ return any(
2172
+ ln.strip().startswith("▣") and _OPENCODE_DONE.search(ln.strip())
2173
+ for ln in lines
2174
+ )
2175
+
2176
+
2177
+ def _opencode_in_progress(target: str) -> bool:
2178
+ """In-progress opencode turn. A deferral here keeps wake_outstanding."""
2179
+ lines = _capture_pane_lines(target)
2180
+ if not lines or not _is_opencode_pane(lines):
2181
+ return False
2182
+ return _opencode_running(lines)
2183
+
2184
+
2185
+ def _opencode_turn_finished_target(target: str) -> bool:
2186
+ lines = _capture_pane_lines(target)
2187
+ if not lines or not _is_opencode_pane(lines):
2188
+ return False
2189
+ return _opencode_turn_finished(lines)
2190
+
2191
+
2192
+ def _opencode_input(lines: list[str]) -> Optional[str]:
2193
+ """The composer input row's text, '' when that row is empty, None if no box.
2194
+
2195
+ Walk up from the mode row. Blank ``┃`` lines are the box padding. A
2196
+ ``▣`` spinner sits between the transcript and the box, and the walk
2197
+ stops there so a submitted prompt in the transcript is not read as
2198
+ text still sitting in the composer.
2199
+ """
2200
+ mode_at = None
2201
+ for i, ln in enumerate(lines):
2202
+ if _opencode_mode_row(ln):
2203
+ mode_at = i
2204
+ if mode_at is None:
2205
+ return None
2206
+ for ln in reversed(lines[:mode_at]):
2207
+ s = ln.strip()
2208
+ if s.startswith("▣"):
2209
+ return ""
2210
+ if not s.startswith("┃"):
2211
+ continue
2212
+ body = s[1:].strip()
2213
+ if body:
2214
+ return body
2215
+ return ""
2216
+
2217
+
2218
+ def _opencode_composer_state(lines: list[str]) -> Optional[str]:
2219
+ if any(_opencode_permission_row(ln) for ln in lines):
2220
+ return "busy"
2221
+ text = _opencode_input(lines)
2222
+ if text is None:
2223
+ return None
2224
+ if not text or text.startswith("Ask anything"):
2225
+ return "clear"
2226
+ if _only_wake_text(text):
2227
+ return "wake"
2228
+ return "busy"
2229
+
2230
+
2075
2231
  def _agent_running(target: str) -> Optional[bool]:
2076
- """True if the pane's composer row carries cursor's run-state hint.
2077
-
2078
- The #619 deferral signal: a keystroke into a RUNNING TUI lands in the
2079
- follow-up queue, and the queue is input-gated (measured live 2026-08-26,
2080
- twice: queued wakes fired only when the human next typed — 10:00 and
2081
- 10:09Z). On an unattended cell a queued wake never fires, so no wake
2082
- keystroke may be sent while this returns True. None = pane or composer
2083
- unreadable; callers treat unknown as NOT-running (the composer state was
2084
- already established by then — this guard only vets the timing).
2232
+ """True while a keystroke would miss the idle composer.
2233
+
2234
+ Cursor: the composer row carries 'ctrl+c to stop' (measured live on
2235
+ cursor-lin 2026-08-24). A keystroke into that TUI lands in the
2236
+ follow-up queue, and the queue is input-gated (measured live
2237
+ 2026-08-26, twice: queued wakes fired only when the human next typed).
2238
+ Opencode: ``esc interrupt`` or a ▣ header with no trailing duration.
2239
+ A finished ``· <n>s`` header is idle. None =
2240
+ pane or composer unreadable; callers treat unknown as NOT-running
2241
+ (the composer state was already established by then — this guard
2242
+ only vets the timing).
2085
2243
  """
2086
2244
  lines = _capture_pane_lines(target)
2087
2245
  if lines is None:
2088
2246
  return None
2247
+ if _is_opencode_pane(lines):
2248
+ return _opencode_running(lines)
2089
2249
  composer = _composer_line(lines)
2090
2250
  if composer is None:
2091
2251
  return None
@@ -2112,6 +2272,8 @@ def _composer_state(target: str) -> Optional[str]:
2112
2272
  lines = _capture_pane_lines(target)
2113
2273
  if lines is None:
2114
2274
  return None
2275
+ if _is_opencode_pane(lines):
2276
+ return _opencode_composer_state(lines)
2115
2277
  composer = _composer_line(lines)
2116
2278
  if composer is None:
2117
2279
  return None
@@ -2126,7 +2288,7 @@ def _composer_state(target: str) -> Optional[str]:
2126
2288
  # A human who types exactly 'check mesh' by hand is indistinguishable
2127
2289
  # from our own unsubmitted wake — and submitting it runs the same
2128
2290
  # command, so the collision is harmless in that direction only.
2129
- if content.replace(_WAKE_PROMPT, "").strip() == "":
2291
+ if _only_wake_text(content):
2130
2292
  return "wake"
2131
2293
  return "busy"
2132
2294
 
@@ -2199,8 +2361,11 @@ def _tmux_wake(target: str) -> Optional[bool]:
2199
2361
  wake stays owed and the ledger retries the whole wake later.
2200
2362
  """
2201
2363
  try:
2364
+ seen = _capture_pane_lines(target)
2365
+ prompt = (_OPENCODE_WAKE_PROMPT
2366
+ if seen and _is_opencode_pane(seen) else _WAKE_PROMPT)
2202
2367
  subprocess.run(
2203
- ["tmux", "send-keys", "-t", target, "-l", _WAKE_PROMPT],
2368
+ ["tmux", "send-keys", "-t", target, "-l", prompt],
2204
2369
  check=True,
2205
2370
  stdout=subprocess.DEVNULL,
2206
2371
  stderr=subprocess.PIPE,
@@ -2234,6 +2399,10 @@ def _tmux_wake(target: str) -> Optional[bool]:
2234
2399
  # sink DEFER, keeping the cursor back so a later poll
2235
2400
  # retries the wake when the composer clears.
2236
2401
  return None
2402
+ # "wake" while a turn is already on screen: another Enter stacks
2403
+ # a follow-up. Defer; the sink does not advance.
2404
+ if _agent_running(target):
2405
+ return None
2237
2406
  # "wake": still sitting unsubmitted — loop another Enter.
2238
2407
  print(
2239
2408
  f"[monitor] tmux wake still unsubmitted after "
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swarph-cli
3
- Version: 0.69.0
3
+ Version: 0.69.1
4
4
  Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
5
5
  Author: Pierre Samson, Claude Opus
6
6
  License: MIT
@@ -60,6 +60,7 @@ def test_tmux_wake_sends_literal_prompt_then_submits_and_verifies(monkeypatch):
60
60
  assert mesh._tmux_wake("gpt-lc:0.0") is True
61
61
  assert seen == ["gpt-lc:0.0"] # verified through the composer gate
62
62
  assert [command for command, _ in calls] == [
63
+ ["tmux", "capture-pane", "-p", "-t", "gpt-lc:0.0"],
63
64
  ["tmux", "send-keys", "-t", "gpt-lc:0.0", "-l", "check mesh"],
64
65
  ["tmux", "send-keys", "-t", "gpt-lc:0.0", "Enter"],
65
66
  ]
@@ -44,6 +44,8 @@ def _rig(monkeypatch, *, composer="clear", unread=3, session_created=None,
44
44
  monkeypatch.setattr(mesh, "_composer_state", lambda t: composer)
45
45
  monkeypatch.setattr(mesh, "_tmux_session_created", lambda t: session_created)
46
46
  monkeypatch.setattr(mesh, "_agent_running", lambda t: running)
47
+ monkeypatch.setattr(mesh, "_opencode_in_progress", lambda t: False)
48
+ monkeypatch.setattr(mesh, "_opencode_turn_finished_target", lambda t: False)
47
49
  monkeypatch.setattr(watchdog, "_gateway_unread_count",
48
50
  lambda *a, **k: unread)
49
51
 
@@ -53,7 +53,9 @@ def test_second_enter_fires_only_when_the_first_did_not_submit(tmux):
53
53
  """The Codex shape, now verified instead of blind: first Enter leaves the
54
54
  prompt in the composer, second clears it."""
55
55
  calls, state = tmux
56
- state["captures"] = ["> check mesh", "> "]
56
+ # First frame is the pre-inject look (prompt choice). The pending frame
57
+ # is what the first Enter left behind.
58
+ state["captures"] = ["> ", "> check mesh", "> "]
57
59
  assert mesh._tmux_wake("pane") is True
58
60
  assert enters(calls) == 2
59
61
 
@@ -62,7 +64,7 @@ def test_concatenated_backlog_is_detected_and_drained(tmux):
62
64
  """The observed defect shape: two wakes stacked unsubmitted. The substring
63
65
  check catches the concatenation and the retry Enter drains it."""
64
66
  calls, state = tmux
65
- state["captures"] = ["> check meshcheck mesh", "> "]
67
+ state["captures"] = ["> ", "> check meshcheck mesh", "> "]
66
68
  assert mesh._tmux_wake("pane") is True
67
69
  assert enters(calls) == 2
68
70
 
@@ -101,7 +103,7 @@ def test_capture_failure_mid_loop_stops_the_loop(tmux, monkeypatch):
101
103
  state["captures"] = ["> check mesh"] # first capture: still pending
102
104
 
103
105
  def flaky(argv, **kw):
104
- if argv[1] == "capture-pane" and state["i"] > 0:
106
+ if argv[1] == "capture-pane" and state["i"] > 1:
105
107
  raise OSError("tmux socket vanished")
106
108
  if argv[1] == "capture-pane":
107
109
  i = min(state["i"], len(state["captures"]) - 1)
@@ -161,7 +163,7 @@ def test_codex_composer_marker_counts_as_recognizable(tmux):
161
163
 
162
164
  def test_cursor_composer_holding_the_wake_is_pending(tmux):
163
165
  calls, state = tmux
164
- state["captures"] = ["→ check mesh", "→ Add a follow-up"]
166
+ state["captures"] = ["→ Add a follow-up", "→ check mesh", "→ Add a follow-up"]
165
167
  assert mesh._tmux_wake("pane") is True
166
168
  assert enters(calls) == 2
167
169
 
@@ -199,6 +201,8 @@ def gate(monkeypatch):
199
201
  lambda t: calls.__setitem__("enter", calls["enter"] + 1) or True)
200
202
  monkeypatch.setattr(mesh, "_wake_still_pending", lambda t: box["pending"])
201
203
  monkeypatch.setattr(mesh, "_composer_state", lambda t: box["composer"])
204
+ monkeypatch.setattr(mesh, "_opencode_in_progress", lambda t: False)
205
+ monkeypatch.setattr(mesh, "_opencode_turn_finished_target", lambda t: False)
202
206
  import swarph_cli.commands.watchdog as wd
203
207
  monkeypatch.setattr(wd, "_gateway_unread_count",
204
208
  lambda g, p, t: box["unread"])
@@ -540,3 +544,192 @@ def test_engine_defers_on_adopted_mid_settle_with_real_tmux_sink(tmp_path, tmux,
540
544
  out = capsys.readouterr()
541
545
  assert "DEFERRED" in out.out
542
546
  assert "DELIVERY FAILED" not in out.err
547
+
548
+
549
+ # ── opencode 1.18.33, measured on a sacrificial pane (card #961) ──────────
550
+ #
551
+ # The composer is a ┃ box, not a > / › / → line. A ▣ spinner sits between
552
+ # the transcript and the box; lines above it are history. `esc interrupt`
553
+ # and `Permission required` mean a keystroke is the wrong key.
554
+
555
+ _OPENCODE_IDLE = """\
556
+ ┃
557
+ ┃ Ask anything… "What is the tech stack of this project?"
558
+ ┃
559
+ ┃ Build · DeepSeek V4 Pro (New) OpenCode Go
560
+ ╹▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
561
+ tab agents
562
+ ctrl+p commands
563
+ """
564
+
565
+ _OPENCODE_HOLDING = """\
566
+ ┃
567
+ ┃ check mesh: swarph_dm_unread
568
+ ┃
569
+ ┃ Build · DeepSeek V4 Pro (New) OpenCode Go
570
+ ╹▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
571
+ """
572
+
573
+ _OPENCODE_RUNNING = """\
574
+ ┃ check mesh: swarph_dm_unread
575
+ ┃ Click to expand
576
+ ▣ Build · DeepSeek V4 Pro (New)
577
+ ┃
578
+ ┃
579
+ ┃ Build · DeepSeek V4 Pro (New) OpenCode Go
580
+ esc interrupt
581
+ """
582
+
583
+ # 1.18.33 draws the dialog inside the box. The mode row and the bottom
584
+ # border are not on this screen (drop-on-meta-edge, card #961 post 54557).
585
+ _OPENCODE_PERMISSION = """\
586
+ ┃
587
+ ┃ △ Permission required
588
+ ┃
589
+ Allow once
590
+ Allow always
591
+ Reject
592
+ """
593
+
594
+ _OPENCODE_FINISHED = """\
595
+ ▣ Build · DeepSeek V4 Pro (New) · 3.3s
596
+ ┃
597
+ ┃ Ask anything… "What is the tech stack of this project?"
598
+ ┃
599
+ ┃ Build · DeepSeek V4 Pro (New) OpenCode Go
600
+ ╹▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
601
+ tab agents ctrl+p commands
602
+ """
603
+
604
+
605
+ def test_opencode_idle_box_is_a_clear_composer(tmux):
606
+ calls, state = tmux
607
+ state["captures"] = [_OPENCODE_IDLE]
608
+ assert mesh._composer_state("sac") == "clear"
609
+ assert mesh._agent_running("sac") is False
610
+ # `--auto` rewrites the mode row to "Build auto ·" (1.18.33).
611
+ state["captures"] = [_OPENCODE_IDLE.replace("Build ·", "Build auto ·")]
612
+ state["i"] = 0
613
+ assert mesh._composer_state("sac") == "clear"
614
+
615
+
616
+ def test_opencode_unsubmitted_pointer_is_wake_not_unknown(tmux):
617
+ """Main reads this pane as no composer at all, so the sink fails closed
618
+ and the text stays typed. The box is a composer, and this line is wake."""
619
+ calls, state = tmux
620
+ state["captures"] = [_OPENCODE_HOLDING]
621
+ assert mesh._composer_state("sac") == "wake"
622
+
623
+
624
+ def test_opencode_human_text_in_the_box_is_busy(tmux):
625
+ calls, state = tmux
626
+ state["captures"] = [_OPENCODE_HOLDING.replace(
627
+ "check mesh: swarph_dm_unread", "look at the diff")]
628
+ assert mesh._composer_state("sac") == "busy"
629
+
630
+
631
+ def test_opencode_transcript_above_the_spinner_is_not_the_composer(tmux):
632
+ """The submitted prompt stays on screen above ▣. Reading it as the
633
+ composer would send another Enter into the running turn."""
634
+ calls, state = tmux
635
+ state["captures"] = [_OPENCODE_RUNNING]
636
+ assert mesh._composer_state("sac") == "clear"
637
+ assert mesh._agent_running("sac") is True
638
+
639
+
640
+ def test_opencode_permission_modal_is_not_typed_into(tmux):
641
+ """The dialog is a ┃ row. deliver returns None from the busy branch.
642
+ False would be the unrecognised-pane fallthrough, which also sends no
643
+ keys and is the wrong outcome."""
644
+ calls, state = tmux
645
+ assert "┃ △ Permission required" in _OPENCODE_PERMISSION
646
+ assert "╹▀" not in _OPENCODE_PERMISSION
647
+ assert "Build ·" not in _OPENCODE_PERMISSION
648
+ state["captures"] = [_OPENCODE_PERMISSION]
649
+ assert mesh._composer_state("sac") == "busy"
650
+ sink = mesh.TmuxSink("sac")
651
+ assert sink.deliver(_State(), [], 1) is None
652
+ assert enters(calls) == 0
653
+ assert not any("-l" in c for c in calls)
654
+
655
+
656
+ def test_opencode_finished_header_is_not_a_running_turn(tmux):
657
+ calls, state = tmux
658
+ state["captures"] = [_OPENCODE_FINISHED]
659
+ assert mesh._agent_running("sac") is False
660
+ assert mesh._opencode_turn_finished_target("sac") is True
661
+ assert mesh._composer_state("sac") == "clear"
662
+
663
+
664
+ def test_opencode_deferral_keeps_wake_outstanding(tmux):
665
+ calls, state = tmux
666
+ state["captures"] = [_OPENCODE_RUNNING]
667
+ st = _State()
668
+ st.ledger("x")["wake_outstanding"] = True
669
+ assert mesh.TmuxSink("sac").deliver(st, [], 2) is None
670
+ assert st.ledger("x")["wake_outstanding"] is True
671
+ assert enters(calls) == 0
672
+ assert not any("-l" in c for c in calls)
673
+
674
+
675
+ def test_opencode_finished_turn_earns_another_wake(tmux, monkeypatch):
676
+ """Inside the trust window a standing wake would report delivery with
677
+ no keystroke. A finished header means the cell is idle again."""
678
+ import time
679
+ import swarph_cli.commands.watchdog as wd
680
+ monkeypatch.setattr(wd, "_gateway_unread_count", lambda *a, **k: 1)
681
+ calls, state = tmux
682
+ state["captures"] = [_OPENCODE_FINISHED]
683
+ st = _State()
684
+ st.ledger("x")["wake_outstanding"] = True
685
+ st.ledger("x")["last_wake_injected_at"] = time.time()
686
+ assert mesh.TmuxSink("sac").deliver(st, [], 3) is True
687
+ literals = [c for c in calls if "-l" in c]
688
+ assert literals == [[
689
+ "tmux", "send-keys", "-t", "sac", "-l", mesh._OPENCODE_WAKE_PROMPT]]
690
+ assert enters(calls) == 1
691
+ assert st.ledger("x")["wake_outstanding"] is True
692
+
693
+
694
+ def test_opencode_running_turn_gets_no_second_prompt(tmux):
695
+ calls, state = tmux
696
+ state["captures"] = [_OPENCODE_RUNNING]
697
+ sink = mesh.TmuxSink("sac")
698
+ assert sink.deliver(_State(), [], 1) is None
699
+ assert enters(calls) == 0
700
+ assert not any("-l" in c for c in calls)
701
+
702
+
703
+ def test_opencode_idle_injects_the_pointer_then_one_enter(tmux):
704
+ calls, state = tmux
705
+ state["captures"] = [_OPENCODE_IDLE, _OPENCODE_RUNNING]
706
+ assert mesh._tmux_wake("sac") is True
707
+ literals = [c for c in calls if "-l" in c]
708
+ assert literals == [[
709
+ "tmux", "send-keys", "-t", "sac", "-l", mesh._OPENCODE_WAKE_PROMPT]]
710
+ assert enters(calls) == 1
711
+
712
+
713
+ def test_opencode_holding_wake_is_nudged_not_retyped(tmux):
714
+ calls, state = tmux
715
+ state["captures"] = [_OPENCODE_HOLDING]
716
+ sink = mesh.TmuxSink("sac")
717
+ assert sink.deliver(_State(), [], 1) is True
718
+ assert enters(calls) == 1
719
+ assert not any("-l" in c for c in calls)
720
+
721
+
722
+ def test_opencode_dropin_names_the_tmux_sink_and_is_not_the_template():
723
+ """install-unit renders swarph-monitor@.service only. This file is the
724
+ review copy of the opencode drop-in; nothing in this test installs it."""
725
+ from pathlib import Path
726
+ root = Path(__file__).resolve().parents[1]
727
+ dropin = root / "deploy" / "monitor" / "swarph-monitor@opencode.conf"
728
+ text = dropin.read_text(encoding="utf-8")
729
+ assert "ExecStart=" in text
730
+ assert "--deliver tmux:opencode" in text
731
+ assert "--deliver pull" in text
732
+ assert "--as opencode" in text
733
+ template = (root / "src" / "swarph_cli" / "systemd"
734
+ / "swarph-monitor@.service").read_text(encoding="utf-8")
735
+ assert "tmux:opencode" not in template
File without changes
File without changes
File without changes