swarph-cli 0.72.41__tar.gz → 0.72.42__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 (571) hide show
  1. {swarph_cli-0.72.41/src/swarph_cli.egg-info → swarph_cli-0.72.42}/PKG-INFO +1 -1
  2. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/pyproject.toml +1 -1
  3. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/__init__.py +1 -1
  4. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/mesh.py +391 -31
  5. {swarph_cli-0.72.41 → swarph_cli-0.72.42/src/swarph_cli.egg-info}/PKG-INFO +1 -1
  6. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli.egg-info/SOURCES.txt +4 -0
  7. swarph_cli-0.72.42/tests/test_1452_rework1_engine.py +300 -0
  8. swarph_cli-0.72.42/tests/test_1452_rework2_engine.py +283 -0
  9. swarph_cli-0.72.42/tests/test_1452_rework3_engine.py +264 -0
  10. swarph_cli-0.72.42/tests/test_1452_standing_wake_expiry.py +145 -0
  11. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_484_codex_queue_sink.py +1 -1
  12. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mesh_sidecar_muse_sink.py +3 -2
  13. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_tmux_wake_runstate_defer.py +4 -0
  14. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/LICENSE +0 -0
  15. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/README.md +0 -0
  16. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/setup.cfg +0 -0
  17. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/__main__.py +0 -0
  18. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/__init__.py +0 -0
  19. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/backends.py +0 -0
  20. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/claude_cli.py +0 -0
  21. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/codex_cli.py +0 -0
  22. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/pack.py +0 -0
  23. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/prices.py +0 -0
  24. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/providers.py +0 -0
  25. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/quality.py +0 -0
  26. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/refresh_prices.py +0 -0
  27. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/rules.py +0 -0
  28. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/runner.py +0 -0
  29. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/signal_score.py +0 -0
  30. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/bench/validate.py +0 -0
  31. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/caller.py +0 -0
  32. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/capture/__init__.py +0 -0
  33. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/capture/harden.py +0 -0
  34. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/capture/lineage.py +0 -0
  35. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/capture/liveness.py +0 -0
  36. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/capture/manifest.py +0 -0
  37. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/capture/paths.py +0 -0
  38. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/capture/verify.py +0 -0
  39. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/cell.py +0 -0
  40. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/chain_token.py +0 -0
  41. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/channel.py +0 -0
  42. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/__init__.py +0 -0
  43. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/_content.py +0 -0
  44. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/_display.py +0 -0
  45. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/_gateway_client.py +0 -0
  46. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/add.py +0 -0
  47. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/bench.py +0 -0
  48. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/board.py +0 -0
  49. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/board_cost.py +0 -0
  50. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/board_merge_check.py +0 -0
  51. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/board_usage.py +0 -0
  52. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/brain.py +0 -0
  53. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/brain_ask.py +0 -0
  54. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/cell.py +0 -0
  55. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/cell_probe.py +0 -0
  56. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  57. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/channel.py +0 -0
  58. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/chat.py +0 -0
  59. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/codegraph.py +0 -0
  60. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/codegraph_hook.py +0 -0
  61. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  62. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/codex_waker.py +0 -0
  63. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/commander.py +0 -0
  64. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/committee.py +0 -0
  65. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/compress.py +0 -0
  66. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/daemon.py +0 -0
  67. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/dev_extract.py +0 -0
  68. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/dreaming.py +0 -0
  69. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/event.py +0 -0
  70. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/gateway.py +0 -0
  71. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/gh_route.py +0 -0
  72. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/group.py +0 -0
  73. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/guide.py +0 -0
  74. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/highlight.py +0 -0
  75. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/hook_interpreter.py +0 -0
  76. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/hook_output.py +0 -0
  77. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/hooks.py +0 -0
  78. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/import_session.py +0 -0
  79. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/init.py +0 -0
  80. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  81. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/install_hook.py +0 -0
  82. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  83. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
  84. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
  85. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  86. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/lane.py +0 -0
  87. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/mcp_server.py +0 -0
  88. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/memory.py +0 -0
  89. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
  90. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/memory_sync.py +0 -0
  91. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/monitor.py +0 -0
  92. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/okf_links.py +0 -0
  93. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/onboard.py +0 -0
  94. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  95. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  96. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/protocol_handler.py +0 -0
  97. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/ratify.py +0 -0
  98. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/roster.py +0 -0
  99. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/rowclear_hook.py +0 -0
  100. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/schedule.py +0 -0
  101. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/security.py +0 -0
  102. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/service.py +0 -0
  103. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/skunkworks.py +0 -0
  104. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/spawn.py +0 -0
  105. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/sweep.py +0 -0
  106. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/timeline.py +0 -0
  107. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/triage.py +0 -0
  108. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/version.py +0 -0
  109. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/wake_hook_output.py +0 -0
  110. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commands/watchdog.py +0 -0
  111. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/commit_trailers.py +0 -0
  112. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/compress/__init__.py +0 -0
  113. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/compress/levers.py +0 -0
  114. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/compress/marker.py +0 -0
  115. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/compress/verify.py +0 -0
  116. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/console_safe.py +0 -0
  117. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/delivery_queue.py +0 -0
  118. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dm_frame.py +0 -0
  119. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/__init__.py +0 -0
  120. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/candidates.py +0 -0
  121. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/clone.py +0 -0
  122. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/enrich.py +0 -0
  123. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/index_check.py +0 -0
  124. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/notify.py +0 -0
  125. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/organize.py +0 -0
  126. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/probes.py +0 -0
  127. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/report.py +0 -0
  128. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/run.py +0 -0
  129. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/slm.py +0 -0
  130. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/transcripts.py +0 -0
  131. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/dreaming/verify.py +0 -0
  132. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/duplicate_session.py +0 -0
  133. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/gateway/__init__.py +0 -0
  134. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/gateway/feature_registry.py +0 -0
  135. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/gateway/lanes_control.py +0 -0
  136. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/gateway/schema.sql +0 -0
  137. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/gateway/server.py +0 -0
  138. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/gateway/services_control.py +0 -0
  139. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/gateway_default.py +0 -0
  140. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/gh_identity.py +0 -0
  141. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/guide/GUIDE.md +0 -0
  142. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/identity.py +0 -0
  143. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/launchd/swarph-codex-outbox.plist +0 -0
  144. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/launchd/swarph-codex-outbox.timer.plist +0 -0
  145. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/launchd/swarph-monitor.plist +0 -0
  146. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/launchd/swarph-watchdog.plist +0 -0
  147. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/launchd/swarph-watchdog.timer.plist +0 -0
  148. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/launchd_render.py +0 -0
  149. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/main.py +0 -0
  150. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/multiplexer.py +0 -0
  151. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/operator/__init__.py +0 -0
  152. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/operator/__main__.py +0 -0
  153. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/operator/api.py +0 -0
  154. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/operator/cli.py +0 -0
  155. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/operator/config.py +0 -0
  156. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/operator/fmt.py +0 -0
  157. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/orphan_daemons.py +0 -0
  158. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/pane_probe.py +0 -0
  159. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/parsers/__init__.py +0 -0
  160. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/parsers/claude.py +0 -0
  161. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
  162. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  163. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  164. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  165. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  166. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  167. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  168. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  169. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  170. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  171. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  172. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  173. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/peer_executor.py +0 -0
  174. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/peer_executor_windows.py +0 -0
  175. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/peer_reconciliation.py +0 -0
  176. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/peer_reply_outbox.py +0 -0
  177. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/peer_service_host.py +0 -0
  178. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/peer_service_payload.py +0 -0
  179. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/peer_service_reply.py +0 -0
  180. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/peer_staging.py +0 -0
  181. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/query_filters.py +0 -0
  182. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/quota_sync.py +0 -0
  183. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/redact.py +0 -0
  184. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/rowclear.py +0 -0
  185. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/scripts/__init__.py +0 -0
  186. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  187. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  188. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  189. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  190. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
  191. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/scrub.py +0 -0
  192. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/service/__init__.py +0 -0
  193. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/service/app.py +0 -0
  194. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/service/providers.py +0 -0
  195. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/session_bridge.py +0 -0
  196. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  197. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  198. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/source_text.py +0 -0
  199. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/stall_alert.py +0 -0
  200. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/codex-waker.default +0 -0
  201. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  202. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  203. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  204. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  205. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  206. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
  207. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
  208. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  209. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  210. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  211. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
  212. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
  213. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-triage.service +0 -0
  214. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
  215. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  216. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  217. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  218. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/the_ten.py +0 -0
  219. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/timeline_paths.py +0 -0
  220. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/tokens.py +0 -0
  221. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/triage/__init__.py +0 -0
  222. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/triage/backend.py +0 -0
  223. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/triage/job.py +0 -0
  224. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/triage/owners.json +0 -0
  225. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/triage/router.py +0 -0
  226. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/triage/rows.py +0 -0
  227. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli/triage/sensor.py +0 -0
  228. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  229. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  230. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli.egg-info/requires.txt +0 -0
  231. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/src/swarph_cli.egg-info/top_level.txt +0 -0
  232. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1006_board_publisher.py +0 -0
  233. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1006_session_board.py +0 -0
  234. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1010_strand_only.py +0 -0
  235. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1013_spawn_channel.py +0 -0
  236. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1017_muse_tui.py +0 -0
  237. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1034_copy_mode.py +0 -0
  238. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1050_surrogate_wake.py +0 -0
  239. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1052_opencode_deaf.py +0 -0
  240. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1059_watchdog_unread_env.py +0 -0
  241. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1061_roster_cli.py +0 -0
  242. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1064_stuck_sweep.py +0 -0
  243. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1065_release.py +0 -0
  244. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1066_quiet_wakes.py +0 -0
  245. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1068_structured_accept_cli.py +0 -0
  246. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1071_quota_sync.py +0 -0
  247. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1073_triage.py +0 -0
  248. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1073_triage_board.py +0 -0
  249. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1073_wheel_install.py +0 -0
  250. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1075_task_cli.py +0 -0
  251. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1083_openai_decisions.py +0 -0
  252. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1144_cell_yaml_github.py +0 -0
  253. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1197_commander_taps.py +0 -0
  254. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1203_swarph_me_refusal.py +0 -0
  255. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1206_offer_question.py +0 -0
  256. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1214_egress.py +0 -0
  257. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1219_egress_probe.py +0 -0
  258. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1221_quota_windows.py +0 -0
  259. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1222_maybe_start_cap.py +0 -0
  260. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1228_quota_reach.py +0 -0
  261. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1243_the_ten.py +0 -0
  262. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1248_ship_price_table.py +0 -0
  263. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_124_register_merge.py +0 -0
  264. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1250_price_cache.py +0 -0
  265. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1256_commander_wake.py +0 -0
  266. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1261_mcp_install.py +0 -0
  267. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1262_wake_followups.py +0 -0
  268. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1265_wake_note.py +0 -0
  269. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1269_triage_label.py +0 -0
  270. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_126_pending_from_complete.py +0 -0
  271. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1277_close_usage.py +0 -0
  272. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1278_dreaming_reach.py +0 -0
  273. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1286_dm_unread_cursor.py +0 -0
  274. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1297_commander.py +0 -0
  275. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1300_authorization_check.py +0 -0
  276. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1301_restart_skew.py +0 -0
  277. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1320_commit_trailers.py +0 -0
  278. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1321_layered_redaction.py +0 -0
  279. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  280. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1340_router_rollout.py +0 -0
  281. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1346_shell_string_gh.py +0 -0
  282. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1347_shell_depth_cap.py +0 -0
  283. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1353_obligation_release_cli.py +0 -0
  284. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1385_duplicate_session_argv.py +0 -0
  285. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_138_memory_navigate.py +0 -0
  286. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1396_dev_extract.py +0 -0
  287. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_139_tool_probe.py +0 -0
  288. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1405_skunkworks_basic.py +0 -0
  289. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1405_skunkworks_cli.py +0 -0
  290. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_1427_membrane_workflow.py +0 -0
  291. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_183_card_anchor.py +0 -0
  292. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_184_notify_honesty.py +0 -0
  293. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_201_win32_bash_refusal.py +0 -0
  294. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_243_onboard_per_peer_token.py +0 -0
  295. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_307_task4_ask_reply.py +0 -0
  296. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  297. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_3130_sender.py +0 -0
  298. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_3150_identity_router_install.py +0 -0
  299. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_319_refusal_exit_codes.py +0 -0
  300. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_323_mistral_backend.py +0 -0
  301. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_332_report_organize_findings.py +0 -0
  302. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_356_query_filters.py +0 -0
  303. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_397_gh_identity_router.py +0 -0
  304. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_397_router_preflight.py +0 -0
  305. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_402_one_identity_resolver.py +0 -0
  306. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_432_rowclear.py +0 -0
  307. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_467b_onboard_operator_credential.py +0 -0
  308. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_472_register_caller_binding.py +0 -0
  309. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_513_duplicate_session.py +0 -0
  310. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_523_guide.py +0 -0
  311. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_524_conftest_hermeticity.py +0 -0
  312. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_532_accept_flag.py +0 -0
  313. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_535_version_capability.py +0 -0
  314. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_538_signal_bench.py +0 -0
  315. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_546_default_gateway.py +0 -0
  316. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_547_verbs_from_registry.py +0 -0
  317. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_548_gateway_remainder.py +0 -0
  318. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_552_codegraph_gateway.py +0 -0
  319. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_555_relay_row_shape.py +0 -0
  320. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_556_relay_freshness.py +0 -0
  321. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_559_edges_truncated.py +0 -0
  322. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_564_bootstrap_first_peer.py +0 -0
  323. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  324. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_579_register_bootstrap_message.py +0 -0
  325. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_591_cli_step_graph.py +0 -0
  326. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_644_monitor_supervision.py +0 -0
  327. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_648_install_unit.py +0 -0
  328. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_654_reexec.py +0 -0
  329. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_656_owned_slm.py +0 -0
  330. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_684_dreaming_verb.py +0 -0
  331. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_689_pkg_version_order.py +0 -0
  332. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_715_grok_wake.py +0 -0
  333. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_716_timeline_one_path.py +0 -0
  334. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_723_grok_0251.py +0 -0
  335. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_724_ps1_ascii_or_bom.py +0 -0
  336. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_725_stdio_reconfigure.py +0 -0
  337. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_726_grok_limit_screen.py +0 -0
  338. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_729_arm_check_delivery_gap.py +0 -0
  339. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_729_dm_once.py +0 -0
  340. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_729_wake_watchdog.py +0 -0
  341. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_734_dreaming_enrich_degrade.py +0 -0
  342. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_735_dm_mcp_tools.py +0 -0
  343. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_739_wake_writer.py +0 -0
  344. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_740_edit_project.py +0 -0
  345. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_762_cards_edit_priority.py +0 -0
  346. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_764_enrich_collapse.py +0 -0
  347. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_801_confirm_flow_cli.py +0 -0
  348. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_802_stage_history.py +0 -0
  349. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_825_codegraph_hook_noise.py +0 -0
  350. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_825_install_posttooluse_only.py +0 -0
  351. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_825_remaining_cap_shred_bind.py +0 -0
  352. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_829_counterfactual_column.py +0 -0
  353. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_830_hook_binding_version.py +0 -0
  354. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_84_cli_labels.py +0 -0
  355. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_866_doctrine_guide.py +0 -0
  356. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_872_identity_refuses_not_warns.py +0 -0
  357. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_874_source_text.py +0 -0
  358. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
  359. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_931_board_search.py +0 -0
  360. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_935_deadline_clock.py +0 -0
  361. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_937_dreaming_notify.py +0 -0
  362. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_938_organize_line_limit.py +0 -0
  363. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_941_bench_backends.py +0 -0
  364. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_941_harness_342.py +0 -0
  365. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_945_same_line_pairing.py +0 -0
  366. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_955_prompt_audit.py +0 -0
  367. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_957_auth_http.py +0 -0
  368. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_959_venv_interpreter.py +0 -0
  369. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_960_channel.py +0 -0
  370. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
  371. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_961_cursor_grok_footer.py +0 -0
  372. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_961_loud_stop.py +0 -0
  373. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_963_plugin_manifest.py +0 -0
  374. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_964_channel_cell.py +0 -0
  375. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_965_mesh_wait.py +0 -0
  376. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_975_channel_hop.py +0 -0
  377. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_add_security_gate.py +0 -0
  378. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_artifact_add.py +0 -0
  379. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_artifact_hash.py +0 -0
  380. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_artifact_lib.py +0 -0
  381. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_artifact_mcp.py +0 -0
  382. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_artifact_skill.py +0 -0
  383. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_artifact_tool.py +0 -0
  384. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_artifact_uri.py +0 -0
  385. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_bench_backends.py +0 -0
  386. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_bench_claude_cli.py +0 -0
  387. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_bench_codex_cli.py +0 -0
  388. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_bench_command.py +0 -0
  389. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_bench_pack.py +0 -0
  390. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_bench_prices.py +0 -0
  391. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_bench_quality.py +0 -0
  392. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_bench_runner.py +0 -0
  393. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_bench_validate.py +0 -0
  394. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_board_card_thread.py +0 -0
  395. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_board_command.py +0 -0
  396. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_board_merge_check.py +0 -0
  397. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_board_obligation_close.py +0 -0
  398. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_brain_ask_command.py +0 -0
  399. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_brain_ask_env_diagnosis.py +0 -0
  400. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_brain_ask_identity_explicitness.py +0 -0
  401. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_brain_command.py +0 -0
  402. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_caller_meta_guard.py +0 -0
  403. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_capture_lineage.py +0 -0
  404. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_capture_liveness.py +0 -0
  405. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_capture_manifest.py +0 -0
  406. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_capture_paths.py +0 -0
  407. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_capture_security.py +0 -0
  408. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_cell_command_dispatch.py +0 -0
  409. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_cell_harden.py +0 -0
  410. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_cell_loader.py +0 -0
  411. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_cell_selfcheck.py +0 -0
  412. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_cell_verify.py +0 -0
  413. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_chain_token.py +0 -0
  414. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_channel_command.py +0 -0
  415. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  416. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_channel_post.py +0 -0
  417. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_channel_wake_policy_filter.py +0 -0
  418. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_chat_command.py +0 -0
  419. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_claude_parser.py +0 -0
  420. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_claude_tmux_template.py +0 -0
  421. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_codegraph_caller_scope.py +0 -0
  422. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_codegraph_command.py +0 -0
  423. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_codegraph_hook.py +0 -0
  424. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_codegraph_mcp.py +0 -0
  425. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_codex_waker.py +0 -0
  426. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_committee_command.py +0 -0
  427. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_compress_caller_convention.py +0 -0
  428. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_compress_command.py +0 -0
  429. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_compress_levers.py +0 -0
  430. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_compress_marker.py +0 -0
  431. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_compress_verify.py +0 -0
  432. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_console_encoding_e2e.py +0 -0
  433. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_content_composition.py +0 -0
  434. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_copilot_membrane.py +0 -0
  435. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_copilot_pane_reader.py +0 -0
  436. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_cursor_membrane.py +0 -0
  437. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_daemon_command.py +0 -0
  438. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_daemon_console_encoding.py +0 -0
  439. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_daemon_delivery.py +0 -0
  440. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_delivery_queue.py +0 -0
  441. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_display_sanitize.py +0 -0
  442. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  443. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_event_emit.py +0 -0
  444. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_feature_to_uri.py +0 -0
  445. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_gateway_brain.py +0 -0
  446. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_gateway_client.py +0 -0
  447. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_gateway_command.py +0 -0
  448. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_gateway_message_idempotency.py +0 -0
  449. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  450. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_group_command.py +0 -0
  451. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_guide_commands_parse.py +0 -0
  452. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_guide_selfcheck.py +0 -0
  453. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_heartbeat_check.py +0 -0
  454. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_highlight_command.py +0 -0
  455. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hook_output.py +0 -0
  456. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hooks_activity_marker.py +0 -0
  457. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hooks_add.py +0 -0
  458. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hooks_bundle.py +0 -0
  459. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hooks_init.py +0 -0
  460. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hooks_legacy_generation_removal.py +0 -0
  461. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hooks_lifecycle.py +0 -0
  462. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hooks_merge.py +0 -0
  463. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hooks_verify.py +0 -0
  464. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  465. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_hooks_win32_command_path.py +0 -0
  466. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_import_command.py +0 -0
  467. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_inbox_identity_provenance.py +0 -0
  468. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_init_command.py +0 -0
  469. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_init_provider_menu.py +0 -0
  470. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_install_codex_hooks.py +0 -0
  471. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_install_hook.py +0 -0
  472. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_install_multiplexer_command.py +0 -0
  473. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_install_postcompact_hook.py +0 -0
  474. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_install_wake_hook.py +0 -0
  475. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_lane_command.py +0 -0
  476. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_launchd_units.py +0 -0
  477. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_main.py +0 -0
  478. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_main_unknown_verb_guard.py +0 -0
  479. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mcp_missing_hint.py +0 -0
  480. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mcp_server.py +0 -0
  481. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_memory_command.py +0 -0
  482. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_memory_emit_snippet.py +0 -0
  483. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_memory_gateway.py +0 -0
  484. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_memory_sync.py +0 -0
  485. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_memory_sync_membrane.py +0 -0
  486. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mesh_command.py +0 -0
  487. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mesh_inbox_mark_read.py +0 -0
  488. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mesh_inbox_sanitize.py +0 -0
  489. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mesh_originate_thread_623.py +0 -0
  490. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mesh_send_unknown_peer.py +0 -0
  491. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mesh_sidecar.py +0 -0
  492. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  493. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  494. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_meta_edge_identity.py +0 -0
  495. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_monitor_channel_poll.py +0 -0
  496. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_monitor_cli.py +0 -0
  497. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_monitor_daemon_collision.py +0 -0
  498. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_monitor_self_name_verification.py +0 -0
  499. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_monitor_state_split.py +0 -0
  500. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_multiplexer.py +0 -0
  501. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_muse_membrane.py +0 -0
  502. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_muse_own_cli.py +0 -0
  503. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_obligation_close_is_surfaced.py +0 -0
  504. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_okf_links.py +0 -0
  505. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_onboard_command.py +0 -0
  506. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_opencode_membrane.py +0 -0
  507. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_opencode_plugin.py +0 -0
  508. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_operator_me.py +0 -0
  509. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_orphan_daemons.py +0 -0
  510. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_packaged_artifacts_exist.py +0 -0
  511. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_packaged_skills.py +0 -0
  512. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_peer_executor.py +0 -0
  513. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_peer_executor_windows.py +0 -0
  514. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_peer_reply_drain_command.py +0 -0
  515. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_peer_reply_drain_supervisor.py +0 -0
  516. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_peer_reply_outbox.py +0 -0
  517. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_peer_reply_transport.py +0 -0
  518. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_peer_service_e2e.py +0 -0
  519. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_peer_service_host.py +0 -0
  520. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_peer_service_payload.py +0 -0
  521. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_peer_service_reply.py +0 -0
  522. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_postcompact_recall.py +0 -0
  523. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_process_liveness.py +0 -0
  524. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_protocol_handler.py +0 -0
  525. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_providers_isolation.py +0 -0
  526. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_ratify_command.py +0 -0
  527. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_readme_claims_no_gateway_default.py +0 -0
  528. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_repl_caller_convention.py +0 -0
  529. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_schedule_command.py +0 -0
  530. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_schedule_create_contract.py +0 -0
  531. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_scrub.py +0 -0
  532. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_security.py +0 -0
  533. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_service_app.py +0 -0
  534. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_service_command.py +0 -0
  535. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_service_providers.py +0 -0
  536. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_session_bridge_inject.py +0 -0
  537. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_session_bridge_probe.py +0 -0
  538. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_session_bridge_resolve.py +0 -0
  539. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_session_path_role_gate.py +0 -0
  540. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_shipped_units_match_the_cli.py +0 -0
  541. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_smoke_chat.py +0 -0
  542. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_smoke_one_shot.py +0 -0
  543. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_smoke_phase_5_5.py +0 -0
  544. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_spawn_base_hoist.py +0 -0
  545. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_spawn_command.py +0 -0
  546. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_spawn_identity_stamp.py +0 -0
  547. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_spawn_live_pin.py +0 -0
  548. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_spawn_mitosis_lineage.py +0 -0
  549. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_spawn_tmux_session.py +0 -0
  550. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_spawn_windows_relaunch.py +0 -0
  551. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_stall_alert.py +0 -0
  552. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_subprocess_decode_encoding.py +0 -0
  553. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_timeline_command.py +0 -0
  554. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_tmux_wake_session_reanchor.py +0 -0
  555. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_tmux_wake_stale.py +0 -0
  556. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_tmux_wake_submit_verify.py +0 -0
  557. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_token_file_one_parser.py +0 -0
  558. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_token_precedence_explicit_first.py +0 -0
  559. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_unified_token_resolver.py +0 -0
  560. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_version_command.py +0 -0
  561. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_version_consistency.py +0 -0
  562. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_vibe_membrane.py +0 -0
  563. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_watchdog.py +0 -0
  564. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_watchdog_dm_wake.py +0 -0
  565. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  566. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  567. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_watchdog_emit_health.py +0 -0
  568. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_watchdog_install_flags.py +0 -0
  569. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_watchdog_model_rung.py +0 -0
  570. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/tests/test_watchdog_stale_peers.py +0 -0
  571. {swarph_cli-0.72.41 → swarph_cli-0.72.42}/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.72.41
3
+ Version: 0.72.42
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.72.41"
7
+ version = "0.72.42"
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.72.41"
19
+ __version__ = "0.72.42"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -1370,6 +1370,12 @@ class Sink:
1370
1370
 
1371
1371
  def __init__(self, name: str):
1372
1372
  self.name = name
1373
+ # Card #1452 rework 1 (item 6): True when the send a deliver() call
1374
+ # just made was a standing-wake expiry REFRESH, not a first delivery
1375
+ # of newly owed DMs. The engine reads it after a True outcome: a
1376
+ # refresh must not reset the deferred-tick stall count or clear a
1377
+ # stall alert — no send may hide a cell that never drains.
1378
+ self.refresh_send = False
1373
1379
 
1374
1380
  def deliver(self, state: "MonitorState", dms: list, up_to_id: int) -> Optional[bool]:
1375
1381
  """Push `dms` (may be a bounded/empty replay). Three outcomes:
@@ -1473,6 +1479,98 @@ def _stamp_wake(led: dict) -> None:
1473
1479
  led["last_wake_injected_at"] = now
1474
1480
 
1475
1481
 
1482
+ # Card #1452: standing-wake expiry — ONE implementation shared by every sink
1483
+ # that holds a standing wake (TmuxSink, MuseSink, CodexSink). A standing
1484
+ # wake is trusted for at most STANDING_WAKE_EXPIRY_S without DRAIN PROGRESS
1485
+ # (unread decreasing); past that it is expired and the sink owes one fresh
1486
+ # wake. A poll that sends nothing reports the DM owed (None), never
1487
+ # delivered. The clock restarts only on a real send or on observed drain
1488
+ # progress — never on a bare poll, so a stuck cell still expires.
1489
+ STANDING_WAKE_EXPIRY_S = 600.0
1490
+ # Card #1452 rework 1 (note 89766 item 4): the trust limit BACKS OFF per
1491
+ # consecutive expiry refresh — STANDING_WAKE_EXPIRY_S x 2^k, capped at
1492
+ # STANDING_WAKE_EXPIRY_CAP_S. k (`wake_backoff_k` in the ledger) resets on
1493
+ # drain progress or on a drain to 0, so a cell that is actually reading
1494
+ # never pays the backed-off limit.
1495
+ STANDING_WAKE_EXPIRY_CAP_S = 3600.0
1496
+ # Card #1452 rework 1 (note 89766 item 3): with NOTHING newly owed (the
1497
+ # delivery ledger already covers the observed cursor — the lost-wake case),
1498
+ # a standing wake earns at most this many refreshes for the same delivered
1499
+ # id; then refreshes stop and the stall alert is raised once. A new DM
1500
+ # resets the count.
1501
+ STANDING_WAKE_MAX_CAUGHTUP_REFRESHES = 3
1502
+
1503
+
1504
+ def _standing_wake_limit(led: dict) -> float:
1505
+ """Current trust limit for a standing wake: 600s x 2^k, cap 3600s."""
1506
+ k = int(led.get("wake_backoff_k", 0) or 0)
1507
+ if k < 0:
1508
+ k = 0
1509
+ return min(STANDING_WAKE_EXPIRY_S * float(2 ** min(k, 16)),
1510
+ STANDING_WAKE_EXPIRY_CAP_S)
1511
+
1512
+
1513
+ def _standing_wake_verdict(led: dict, unread, *, now=None) -> str:
1514
+ """Classify a standing wake: drained/unreadable/progress/hold/expired.
1515
+
1516
+ Mutates only the progress bookkeeping (`wake_last_unread`,
1517
+ `wake_progress_at`, `wake_backoff_k`). `hold` mutates neither clock
1518
+ field. The expiry anchor is the LATER of `wake_progress_at` and
1519
+ `last_wake_injected_at` (rework 1 item 1: preferring an old progress
1520
+ stamp over a newer injection read a fresh wake as instantly expired).
1521
+ """
1522
+ if unread is None:
1523
+ return "unreadable"
1524
+ if unread == 0:
1525
+ led["wake_backoff_k"] = 0 # a drain to 0 resets the backoff
1526
+ return "drained"
1527
+ if now is None:
1528
+ now = time.time()
1529
+ prev = led.get("wake_last_unread")
1530
+ led["wake_last_unread"] = int(unread)
1531
+ if prev is not None and int(unread) < int(prev):
1532
+ led["wake_progress_at"] = now
1533
+ led["wake_backoff_k"] = 0 # drain progress resets the backoff
1534
+ return "progress"
1535
+ anchor = max(float(led.get("wake_progress_at") or 0.0),
1536
+ float(led.get("last_wake_injected_at") or 0.0))
1537
+ if anchor <= 0 or now - anchor >= _standing_wake_limit(led):
1538
+ return "expired"
1539
+ return "hold"
1540
+
1541
+
1542
+ def _note_fresh_wake(led: dict, unread=None, *, expired=False) -> None:
1543
+ """Restart the standing-wake clock after a real send.
1544
+
1545
+ An expiry refresh (`expired=True`) raises the backoff step k for the
1546
+ NEXT interval; a first/fresh send leaves k where the last progress or
1547
+ drain reset put it. A failed caught-up refresh counts like a sent one
1548
+ (rework 2, note 89818 item 3): the engine calls this with
1549
+ `expired=True` because the sink only reaches it on success.
1550
+ """
1551
+ if expired:
1552
+ led["wake_backoff_k"] = int(led.get("wake_backoff_k", 0) or 0) + 1
1553
+ led["wake_progress_at"] = time.time()
1554
+ if unread is None:
1555
+ led.pop("wake_last_unread", None)
1556
+ else:
1557
+ led["wake_last_unread"] = int(unread)
1558
+
1559
+
1560
+ def _standing_refresh_prompt(unread, up_to_id: int) -> str:
1561
+ """Wake text for a caught-up standing-wake refresh (item 5).
1562
+
1563
+ The original DM body is no longer owed (the ledger already covers it),
1564
+ so the text names what is unread instead of replaying a body.
1565
+ """
1566
+ return (
1567
+ f"You have {unread} unread mesh DM(s). "
1568
+ f"(Standing-wake refresh: the last delivered DM id is {up_to_id}, "
1569
+ "and the inbox still shows unread mail.) "
1570
+ "Read each and act per your standing instructions."
1571
+ )
1572
+
1573
+
1476
1574
  class TmuxSink(Sink):
1477
1575
  """Poke a tmux pane — the behaviour `mesh sidecar` has always had.
1478
1576
 
@@ -1504,6 +1602,7 @@ class TmuxSink(Sink):
1504
1602
  def deliver(self, state: "MonitorState", dms: list, up_to_id: int) -> Optional[bool]:
1505
1603
  led = state.ledger(self.name)
1506
1604
  self.failure_reason = None
1605
+ self.refresh_send = False
1507
1606
  # #1010: the deferral cause, named for the monitor's DEFERRED log —
1508
1607
  # a hardcoded cause is a lie on every path that defers for another
1509
1608
  # reason (the standing-wake hold defers with a CLEAR composer).
@@ -1580,7 +1679,27 @@ class TmuxSink(Sink):
1580
1679
  from swarph_cli.commands.watchdog import _gateway_unread_count
1581
1680
  unread = _gateway_unread_count(state.gateway, state.self_name,
1582
1681
  state.token)
1583
- if unread == 0:
1682
+ # Card #1452: shared standing-wake verdict (see
1683
+ # _standing_wake_verdict). Unreadable and drain-progress polls
1684
+ # send nothing and hold the DM owed; expiry is honoured by the
1685
+ # stale bound in the clear-composer arm below.
1686
+ swake = _standing_wake_verdict(led, unread)
1687
+ if swake == "unreadable":
1688
+ print(f"[monitor] {self.name}: standing wake, unread "
1689
+ f"unreadable (None) — DM held owed, no send this poll",
1690
+ flush=True)
1691
+ self.deferred_reason = (
1692
+ "standing wake, unread unreadable — DM held owed, "
1693
+ "no send")
1694
+ return None
1695
+ if swake == "progress":
1696
+ print(f"[monitor] {self.name}: standing wake, drain "
1697
+ f"progress (unread now {unread}) — DM held owed, "
1698
+ f"no send this poll", flush=True)
1699
+ self.deferred_reason = (
1700
+ "standing wake, drain progress — DM held owed, no send")
1701
+ return None
1702
+ if swake == "drained":
1584
1703
  led["wake_outstanding"] = False # drained since — re-arm
1585
1704
  else:
1586
1705
  composer = _composer_state(self.target)
@@ -1592,6 +1711,8 @@ class TmuxSink(Sink):
1592
1711
  if _agent_running(self.target):
1593
1712
  return None
1594
1713
  _tmux_enter(self.target) # one verified nudge, no new text
1714
+ _note_fresh_wake(led, unread, expired=(swake == "expired"))
1715
+ self.refresh_send = (swake == "expired")
1595
1716
  return True
1596
1717
  if composer == "clear":
1597
1718
  # A finished opencode turn leaves a ▣ header with a
@@ -1602,6 +1723,8 @@ class TmuxSink(Sink):
1602
1723
  ok = _tmux_wake(self.target)
1603
1724
  if ok:
1604
1725
  _stamp_wake(led)
1726
+ _note_fresh_wake(led, unread, expired=(swake == "expired"))
1727
+ self.refresh_send = (swake == "expired")
1605
1728
  return True
1606
1729
  if ok is None:
1607
1730
  return None
@@ -1627,6 +1750,8 @@ class TmuxSink(Sink):
1627
1750
  ok = _tmux_wake(self.target)
1628
1751
  if ok:
1629
1752
  _stamp_wake(led)
1753
+ _note_fresh_wake(led, unread, expired=(swake == "expired"))
1754
+ self.refresh_send = (swake == "expired")
1630
1755
  return True
1631
1756
  if ok is None:
1632
1757
  return None # human adopted mid-settle: defer
@@ -1647,7 +1772,7 @@ class TmuxSink(Sink):
1647
1772
  # (lab-ovh's rebase ruling): a line that says "no
1648
1773
  # keystroke this poll" immediately followed by a keystroke
1649
1774
  # is the lie both PRs exist to stop.
1650
- if time.time() - injected_at > _WAKE_STALE_S:
1775
+ if swake == "expired":
1651
1776
  # #619: a stale re-inject into a RUNNING TUI lands in
1652
1777
  # the input-gated queue — lost again, just later.
1653
1778
  # Defer; the first idle poll re-injects for real.
@@ -1656,6 +1781,8 @@ class TmuxSink(Sink):
1656
1781
  ok = _tmux_wake(self.target)
1657
1782
  if ok:
1658
1783
  _stamp_wake(led)
1784
+ _note_fresh_wake(led, unread, expired=True)
1785
+ self.refresh_send = True
1659
1786
  return True
1660
1787
  if ok is None:
1661
1788
  return None # human adopted mid-settle: defer
@@ -1753,6 +1880,12 @@ class TmuxSink(Sink):
1753
1880
  if ok:
1754
1881
  led["wake_outstanding"] = True
1755
1882
  _stamp_wake(led)
1883
+ # Card #1452 rework 1 (item 1): a fresh Tmux wake resets the
1884
+ # progress clock, as Codex and Muse already do — otherwise a
1885
+ # progress stamp from a drained episode hours ago reads the
1886
+ # fresh wake as instantly expired and a DM a minute later
1887
+ # double-wakes inside the trust limit.
1888
+ _note_fresh_wake(led)
1756
1889
  return True
1757
1890
  # False splits by what the pane actually holds: text observably STUCK
1758
1891
  # in the composer -> mark outstanding so the next poll nudges instead
@@ -1940,9 +2073,11 @@ def _muse_send(session: str, text: str, *,
1940
2073
  class MuseSink(Sink):
1941
2074
  """Wake a live muse session with `session-message send` instead of typing.
1942
2075
 
1943
- Edge-triggered on the drain like TmuxSink: while `wake_outstanding`
1944
- stands (gateway unread > 0), further deliveries report delivered with NO
1945
- new send; the next delivery after the drain sends again. There is no
2076
+ Edge-triggered on the drain like TmuxSink, with the card #1452 expiry:
2077
+ while `wake_outstanding` stands and drain progress continues, further
2078
+ deliveries hold the DM owed (None) with NO new send; after
2079
+ STANDING_WAKE_EXPIRY_S without progress exactly one fresh wake is sent;
2080
+ the next delivery after the drain sends again. There is no
1946
2081
  composer to read — a muse session has no TUI pane — so there is no
1947
2082
  politeness gate, only the outstanding flag plus the gateway drain check.
1948
2083
  A refused or failed send returns False with a NAMED reason printed loud;
@@ -1974,17 +2109,57 @@ class MuseSink(Sink):
1974
2109
 
1975
2110
  def deliver(self, state: "MonitorState", dms: list, up_to_id: int) -> Optional[bool]:
1976
2111
  led = state.ledger(self.name)
2112
+ self.deferred_reason = None
2113
+ self.refresh_send = False
2114
+ unread = None
1977
2115
  if led.get("wake_outstanding"):
1978
2116
  # Lazy: watchdog imports mesh module-level, so the reverse must
1979
- # not. None (gateway error) reads as NOT-drained — re-arming on
1980
- # an unreadable drain signal would re-open the stack.
2117
+ # not. Card #1452: shared standing-wake verdict — a poll that
2118
+ # sends nothing holds the DM owed (None), never delivered.
1981
2119
  from swarph_cli.commands.watchdog import _gateway_unread_count
1982
- if _gateway_unread_count(state.gateway, state.self_name,
1983
- state.token) != 0:
1984
- print(f"[monitor] {self.name}: delivery reported on a STANDING wake "
1985
- f"(no send this poll)", flush=True)
1986
- return True
1987
- led["wake_outstanding"] = False # drained since — re-arm
2120
+ unread = _gateway_unread_count(state.gateway, state.self_name,
2121
+ state.token)
2122
+ swake = _standing_wake_verdict(led, unread)
2123
+ if swake == "drained":
2124
+ led["wake_outstanding"] = False # drained since — re-arm
2125
+ if not dms and up_to_id <= int(led.get("last_delivered_id", 0)):
2126
+ # Caught-up evaluation (item 2): the engine has already
2127
+ # advanced the ledger on this drain (item 5) — no send.
2128
+ return None
2129
+ elif swake == "expired":
2130
+ if not dms and up_to_id > int(led.get("last_delivered_id", 0)):
2131
+ print(f"[monitor] {self.name}: {up_to_id} observed but no body "
2132
+ f"recoverable from inbox.log for the owed range", flush=True)
2133
+ return False
2134
+ # Item 5: with nothing newly owed the original body is gone
2135
+ # from the owed range; the refresh names what is unread.
2136
+ text = (self._prompt(dms) if dms
2137
+ else _standing_refresh_prompt(unread, up_to_id))
2138
+ ok, reason = _muse_send(self.session, text)
2139
+ if ok:
2140
+ limit = _standing_wake_limit(led)
2141
+ led["wake_outstanding"] = True
2142
+ led["last_wake_injected_at"] = time.time()
2143
+ _note_fresh_wake(led, unread, expired=True)
2144
+ self.refresh_send = True
2145
+ print(f"[monitor] {self.name}: standing wake expired after "
2146
+ f"{limit:.0f}s without drain progress "
2147
+ f"— sent one fresh wake", flush=True)
2148
+ return True
2149
+ print(f"[monitor] {self.name}: muse send FAILED: {reason}", flush=True)
2150
+ return False
2151
+ elif swake == "unreadable":
2152
+ print(f"[monitor] {self.name}: standing wake, unread unreadable "
2153
+ f"(None) — DM held owed, no send this poll", flush=True)
2154
+ self.deferred_reason = (
2155
+ "standing wake, unread unreadable — DM held owed, no send")
2156
+ return None
2157
+ else:
2158
+ print(f"[monitor] {self.name}: standing wake ({swake}) — DM held "
2159
+ f"owed, no send this poll", flush=True)
2160
+ self.deferred_reason = (
2161
+ f"standing wake ({swake}) — DM held owed, no send")
2162
+ return None
1988
2163
  if not dms:
1989
2164
  # Nothing recoverable to hand over (log rotated) — do NOT claim
1990
2165
  # a delivery; the ledger stays and the gap stays visible.
@@ -1997,6 +2172,7 @@ class MuseSink(Sink):
1997
2172
  if ok:
1998
2173
  led["wake_outstanding"] = True
1999
2174
  led["last_wake_injected_at"] = time.time()
2175
+ _note_fresh_wake(led, unread)
2000
2176
  return True
2001
2177
  print(f"[monitor] {self.name}: muse send FAILED: {reason}", flush=True)
2002
2178
  return False
@@ -2051,9 +2227,11 @@ def _codex_send(thread: str, text: str, *,
2051
2227
  class CodexSink(Sink):
2052
2228
  """Wake the live gpt-ops session with `codex queue` instead of typing.
2053
2229
 
2054
- Edge-triggered on the drain like MuseSink: while `wake_outstanding`
2055
- stands (gateway unread > 0), further deliveries report delivered with NO
2056
- new send; the next delivery after the drain sends again. There is no
2230
+ Edge-triggered on the drain like MuseSink, with the card #1452 expiry:
2231
+ while `wake_outstanding` stands and drain progress continues, further
2232
+ deliveries hold the DM owed (None) with NO new send; after
2233
+ STANDING_WAKE_EXPIRY_S without progress exactly one fresh wake is sent;
2234
+ the next delivery after the drain sends again. There is no
2057
2235
  composer to read — codex queues into the session, it does not type —
2058
2236
  so there is no politeness gate, only the outstanding flag plus the
2059
2237
  gateway drain check. A refused or failed send returns False with a NAMED
@@ -2085,17 +2263,57 @@ class CodexSink(Sink):
2085
2263
 
2086
2264
  def deliver(self, state: "MonitorState", dms: list, up_to_id: int) -> Optional[bool]:
2087
2265
  led = state.ledger(self.name)
2266
+ self.deferred_reason = None
2267
+ self.refresh_send = False
2268
+ unread = None
2088
2269
  if led.get("wake_outstanding"):
2089
2270
  # Lazy: watchdog imports mesh module-level, so the reverse must
2090
- # not. None (gateway error) reads as NOT-drained — re-arming on
2091
- # an unreadable drain signal would re-open the stack.
2271
+ # not. Card #1452: shared standing-wake verdict — a poll that
2272
+ # sends nothing holds the DM owed (None), never delivered.
2092
2273
  from swarph_cli.commands.watchdog import _gateway_unread_count
2093
- if _gateway_unread_count(state.gateway, state.self_name,
2094
- state.token) != 0:
2095
- print(f"[monitor] {self.name}: delivery reported on a STANDING wake "
2096
- f"(no send this poll)", flush=True)
2097
- return True
2098
- led["wake_outstanding"] = False # drained since — re-arm
2274
+ unread = _gateway_unread_count(state.gateway, state.self_name,
2275
+ state.token)
2276
+ swake = _standing_wake_verdict(led, unread)
2277
+ if swake == "drained":
2278
+ led["wake_outstanding"] = False # drained since — re-arm
2279
+ if not dms and up_to_id <= int(led.get("last_delivered_id", 0)):
2280
+ # Caught-up evaluation (item 2): the engine has already
2281
+ # advanced the ledger on this drain (item 5) — no send.
2282
+ return None
2283
+ elif swake == "expired":
2284
+ if not dms and up_to_id > int(led.get("last_delivered_id", 0)):
2285
+ print(f"[monitor] {self.name}: {up_to_id} observed but no body "
2286
+ f"recoverable from inbox.log for the owed range", flush=True)
2287
+ return False
2288
+ # Item 5: with nothing newly owed the original body is gone
2289
+ # from the owed range; the refresh names what is unread.
2290
+ text = (self._prompt(dms) if dms
2291
+ else _standing_refresh_prompt(unread, up_to_id))
2292
+ ok, reason = _codex_send(self.thread, text)
2293
+ if ok:
2294
+ limit = _standing_wake_limit(led)
2295
+ led["wake_outstanding"] = True
2296
+ led["last_wake_injected_at"] = time.time()
2297
+ _note_fresh_wake(led, unread, expired=True)
2298
+ self.refresh_send = True
2299
+ print(f"[monitor] {self.name}: standing wake expired after "
2300
+ f"{limit:.0f}s without drain progress "
2301
+ f"— sent one fresh wake", flush=True)
2302
+ return True
2303
+ print(f"[monitor] {self.name}: codex send FAILED: {reason}", flush=True)
2304
+ return False
2305
+ elif swake == "unreadable":
2306
+ print(f"[monitor] {self.name}: standing wake, unread unreadable "
2307
+ f"(None) — DM held owed, no send this poll", flush=True)
2308
+ self.deferred_reason = (
2309
+ "standing wake, unread unreadable — DM held owed, no send")
2310
+ return None
2311
+ else:
2312
+ print(f"[monitor] {self.name}: standing wake ({swake}) — DM held "
2313
+ f"owed, no send this poll", flush=True)
2314
+ self.deferred_reason = (
2315
+ f"standing wake ({swake}) — DM held owed, no send")
2316
+ return None
2099
2317
  if not dms:
2100
2318
  # Nothing recoverable to hand over (log rotated) — do NOT claim
2101
2319
  # a delivery; the ledger stays and the gap stays visible.
@@ -2108,6 +2326,7 @@ class CodexSink(Sink):
2108
2326
  if ok:
2109
2327
  led["wake_outstanding"] = True
2110
2328
  led["last_wake_injected_at"] = time.time()
2329
+ _note_fresh_wake(led, unread)
2111
2330
  return True
2112
2331
  print(f"[monitor] {self.name}: codex send FAILED: {reason}", flush=True)
2113
2332
  return False
@@ -2403,7 +2622,7 @@ _WAKE_SUBMIT_ATTEMPTS = 4
2403
2622
  # enough that a legitimately queued follow-up survives a marathon agent turn;
2404
2623
  # short enough that a lost wake costs minutes of silence, not hours. The
2405
2624
  # retry self-rate-limits: a successful re-injection re-anchors the clock.
2406
- _WAKE_STALE_S = 600.0
2625
+ _WAKE_STALE_S = STANDING_WAKE_EXPIRY_S
2407
2626
 
2408
2627
 
2409
2628
  def _capture_pane_lines(target: str) -> Optional[list[str]]:
@@ -3583,15 +3802,151 @@ def _monitor_deliver(state: MonitorState) -> None:
3583
3802
  # Per-poll, the drain is caught within one interval and the next
3584
3803
  # DM earns a wake of its own. unread == None (gateway error)
3585
3804
  # reads as NOT-drained — never re-arm on an unreadable signal.
3586
- if led.get("wake_outstanding"):
3805
+ # Card #1452 rework 3 (note 89855 route B): this branch used to
3806
+ # read the count only while wake_outstanding stood. A running
3807
+ # plain-tmux turn clears that flag (#620), so a drain inside the
3808
+ # turn was invisible and the stall row stayed open until the
3809
+ # turn ended — and the turn's end then woke on mail already
3810
+ # read. Read while a wake stands OR while an alert stands
3811
+ # (caught-up marker set, or deferred ticks at or above
3812
+ # _STALL_FIRST). No read otherwise.
3813
+ unread = None
3814
+ from swarph_cli import stall_alert
3815
+ ticks = int(led.get("deferred_ticks", 0) or 0)
3816
+ alert_stands = (
3817
+ int(led.get("standing_refresh_alerted_id", 0) or 0) != 0
3818
+ or ticks >= stall_alert._STALL_FIRST)
3819
+ if led.get("wake_outstanding") or alert_stands:
3587
3820
  from swarph_cli.commands.watchdog import _gateway_unread_count
3588
- if _gateway_unread_count(state.gateway, state.self_name,
3589
- state.token) == 0:
3821
+ unread = _gateway_unread_count(state.gateway, state.self_name,
3822
+ state.token)
3823
+ if unread == 0:
3590
3824
  led["wake_outstanding"] = False
3825
+ # Card #1452 rework 1 (item 5): an observed drain to 0
3826
+ # ADVANCES the ledger to the observed cursor with NO
3827
+ # send — a healthy drain costs no spurious wake. Only a
3828
+ # real send moves delivery evidence otherwise. The
3829
+ # backoff and the caught-up refresh count reset here.
3830
+ if int(led["last_delivered_id"]) != observed:
3831
+ led["last_delivered_id"] = observed
3832
+ # Card #1452 rework 2 (note 89818 item 2): a drain closes
3833
+ # the stall row. The bound alert leaves deferred_ticks at
3834
+ # 0, and the tick alert leaves them high, so neither the
3835
+ # next delivery nor this branch used to close it. When
3836
+ # either alert stands, zero the ticks and close the row.
3837
+ led["wake_backoff_k"] = 0
3838
+ led["standing_refresh_count"] = 0
3839
+ led["standing_refresh_alerted_id"] = 0
3840
+ if alert_stands:
3841
+ led["deferred_ticks"] = 0
3842
+ stall_alert.clear_stall_alert(
3843
+ state.gateway, state.token, state.self_name)
3591
3844
  changed = True
3592
3845
  delivered = int(led["last_delivered_id"])
3593
3846
  if delivered >= observed:
3594
- continue # this sink owes nothing
3847
+ # Card #1452 rework 1 (item 2): a standing wake is evaluated
3848
+ # on EVERY poll, also when nothing is newly owed — the
3849
+ # lost-wake case (one unread DM, no later DM) otherwise
3850
+ # never refreshed, and its drain progress was discarded.
3851
+ # The engine runs the shared verdict itself (recording any
3852
+ # nonzero drain progress in the ledger) and calls deliver()
3853
+ # only when a refresh send is actually due, so a hold poll
3854
+ # costs no sink read (e.g. no tmux pane capture).
3855
+ if not led.get("wake_outstanding"):
3856
+ continue # this sink owes nothing, no wake stands
3857
+ if unread is None:
3858
+ continue # unreadable: the flag stands, no send
3859
+ verdict = _standing_wake_verdict(led, unread)
3860
+ if verdict == "progress":
3861
+ changed = True # persist the re-anchored progress clock
3862
+ continue
3863
+ if verdict != "expired":
3864
+ continue # hold: nothing material changed
3865
+ refresh_for = int(led.get("standing_refresh_for_id", -1))
3866
+ refresh_count = (int(led.get("standing_refresh_count", 0))
3867
+ if refresh_for == delivered else 0)
3868
+ if refresh_count >= STANDING_WAKE_MAX_CAUGHTUP_REFRESHES:
3869
+ # Item 3: at most STANDING_WAKE_MAX_CAUGHTUP_REFRESHES
3870
+ # refreshes for the same delivered id, then stop and
3871
+ # raise the existing stall alert ONCE. A new DM (the
3872
+ # owed path below) resets the count.
3873
+ if int(led.get("standing_refresh_alerted_id", 0)) != delivered:
3874
+ led["standing_refresh_alerted_id"] = delivered
3875
+ from swarph_cli import stall_alert
3876
+ stall_alert.send_stall_alert(
3877
+ state.gateway, state.token, state.self_name,
3878
+ refresh_count,
3879
+ unread if isinstance(unread, int) and unread > 0 else 1)
3880
+ print(f"{state.log_prefix} standing wake for {sink.name} "
3881
+ f"hit the caught-up refresh bound "
3882
+ f"({STANDING_WAKE_MAX_CAUGHTUP_REFRESHES} for id "
3883
+ f"{delivered}) — no further refresh; stall alert raised",
3884
+ flush=True)
3885
+ changed = True
3886
+ continue
3887
+ outcome = sink.deliver(state, [], observed)
3888
+ if outcome is None:
3889
+ # Card #1452 rework 2 (note 89818 item 1): plain tmux
3890
+ # clears wake_outstanding when a turn is running (#620)
3891
+ # and returns None. Nothing is newly owed, so a cleared
3892
+ # flag would never re-enter this sink and the lost wake
3893
+ # would stay lost. Keep the flag while unread remains.
3894
+ # A deferral is not a refresh: the clock and the count
3895
+ # stay, so the refresh still happens once the turn ends.
3896
+ if isinstance(unread, int) and unread > 0:
3897
+ led["wake_outstanding"] = True
3898
+ changed = True
3899
+ continue
3900
+ # True and False both consume one caught-up refresh (note
3901
+ # 89818 item 3). A refused send used to leave the clock and
3902
+ # the count unmoved, so a dead sink retried every poll and
3903
+ # never reached the stall alert. Count it like a sent one.
3904
+ # The sink restarts the clock only on success; do it here on
3905
+ # failure. The owed path below is unchanged: a failed send
3906
+ # there raises no new alert (carded separately).
3907
+ if not outcome:
3908
+ _note_fresh_wake(
3909
+ led, unread if isinstance(unread, int) else None,
3910
+ expired=True)
3911
+ # Note 89855 item 3: plain tmux clears the flag on the
3912
+ # running read (#620) and the idle read can then refuse
3913
+ # the send, so the flag is down unless this puts it
3914
+ # back. Without it the refused refresh is the last
3915
+ # attempt and the stall alert never comes.
3916
+ if isinstance(unread, int) and unread > 0:
3917
+ led["wake_outstanding"] = True
3918
+ led["standing_refresh_count"] = refresh_count + 1
3919
+ led["standing_refresh_for_id"] = delivered
3920
+ if outcome:
3921
+ led["last_delivery_at"] = now
3922
+ led["consecutive_failures"] = 0
3923
+ state.deliveries[sink.name] = state.deliveries.get(sink.name, 0) + 1
3924
+ print(f"{state.log_prefix} standing wake refreshed for "
3925
+ f"{sink.name} (refresh "
3926
+ f"{refresh_count + 1}/{STANDING_WAKE_MAX_CAUGHTUP_REFRESHES} "
3927
+ f"for id {delivered}; nothing newly owed)",
3928
+ flush=True)
3929
+ else:
3930
+ led["consecutive_failures"] = int(led["consecutive_failures"]) + 1
3931
+ detail = getattr(sink, "failure_reason", None) or (
3932
+ "the sink is probably gone (session restart / renamed target)"
3933
+ )
3934
+ print(f"{state.log_prefix} DELIVERY FAILED to {sink.name} "
3935
+ f"({led['consecutive_failures']} consecutive) -- DMs up to "
3936
+ f"id {observed} were still observed and archived; {detail}",
3937
+ file=sys.stderr, flush=True)
3938
+ changed = True
3939
+ continue
3940
+ # Something is newly owed: a new DM resets the caught-up
3941
+ # refresh count (item 3) so the new id can refresh. Card #1452
3942
+ # rework 3 (note 89855 route A): do NOT zero
3943
+ # standing_refresh_alerted_id here. Zeroing it dropped the
3944
+ # stall row's identity, the drain then found nothing to close,
3945
+ # and that open row absorbed the next stall. The drain branch
3946
+ # still zeroes the marker when it closes the row.
3947
+ if int(led.get("standing_refresh_count", 0) or 0):
3948
+ led["standing_refresh_count"] = 0
3949
+ changed = True
3595
3950
  if now - float(led["last_delivery_at"]) < state.min_interval_s:
3596
3951
  print(f"{state.log_prefix} wake suppressed by idle guard for "
3597
3952
  f"{sink.name} (cursor advanced; delivery still pending)",
@@ -3634,7 +3989,12 @@ def _monitor_deliver(state: MonitorState) -> None:
3634
3989
  flush=True)
3635
3990
  continue
3636
3991
  was_stalled = bool(led.get("deferred_ticks"))
3637
- if was_stalled:
3992
+ # Card #1452 rework 1 (item 6): a standing-wake REFRESH send must
3993
+ # not hide a cell that never drains — it neither resets the
3994
+ # deferred-tick count nor clears the stall alert. Only a
3995
+ # non-refresh delivery (or a drain) resolves a stall.
3996
+ is_refresh = bool(getattr(sink, "refresh_send", False))
3997
+ if was_stalled and not is_refresh:
3638
3998
  led["deferred_ticks"] = 0
3639
3999
  if outcome:
3640
4000
  led["last_delivered_id"] = observed
@@ -3643,7 +4003,7 @@ def _monitor_deliver(state: MonitorState) -> None:
3643
4003
  state.deliveries[sink.name] = state.deliveries.get(sink.name, 0) + 1
3644
4004
  print(f"{state.log_prefix} delivered to {sink.name} up to id {observed}",
3645
4005
  flush=True)
3646
- if was_stalled:
4006
+ if was_stalled and not is_refresh:
3647
4007
  from swarph_cli import stall_alert
3648
4008
  stall_alert.clear_stall_alert(
3649
4009
  state.gateway, state.token, state.self_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swarph-cli
3
- Version: 0.72.41
3
+ Version: 0.72.42
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
@@ -279,6 +279,10 @@ tests/test_139_tool_probe.py
279
279
  tests/test_1405_skunkworks_basic.py
280
280
  tests/test_1405_skunkworks_cli.py
281
281
  tests/test_1427_membrane_workflow.py
282
+ tests/test_1452_rework1_engine.py
283
+ tests/test_1452_rework2_engine.py
284
+ tests/test_1452_rework3_engine.py
285
+ tests/test_1452_standing_wake_expiry.py
282
286
  tests/test_183_card_anchor.py
283
287
  tests/test_184_notify_honesty.py
284
288
  tests/test_201_win32_bash_refusal.py