swarph-cli 0.72.28__tar.gz → 0.72.29__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 (532) hide show
  1. {swarph_cli-0.72.28/src/swarph_cli.egg-info → swarph_cli-0.72.29}/PKG-INFO +2 -2
  2. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/README.md +1 -1
  3. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/pyproject.toml +4 -1
  4. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/__init__.py +1 -1
  5. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/claude_cli.py +5 -2
  6. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/board.py +84 -12
  7. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/hook_output.py +45 -37
  8. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/lane.py +16 -1
  9. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/mesh.py +83 -3
  10. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/roster.py +11 -5
  11. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/schedule.py +12 -7
  12. swarph_cli-0.72.29/src/swarph_cli/duplicate_session.py +284 -0
  13. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/stall_alert.py +35 -63
  14. swarph_cli-0.72.29/src/swarph_cli/the_ten.py +223 -0
  15. {swarph_cli-0.72.28 → swarph_cli-0.72.29/src/swarph_cli.egg-info}/PKG-INFO +2 -2
  16. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli.egg-info/SOURCES.txt +9 -0
  17. swarph_cli-0.72.29/tests/test_1034_copy_mode.py +61 -0
  18. swarph_cli-0.72.29/tests/test_1222_maybe_start_cap.py +126 -0
  19. swarph_cli-0.72.29/tests/test_1228_quota_reach.py +53 -0
  20. swarph_cli-0.72.29/tests/test_1243_the_ten.py +274 -0
  21. swarph_cli-0.72.29/tests/test_513_duplicate_session.py +215 -0
  22. swarph_cli-0.72.29/tests/test_931_board_search.py +88 -0
  23. swarph_cli-0.72.29/tests/test_935_deadline_clock.py +55 -0
  24. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_bench_claude_cli.py +15 -4
  25. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_copilot_pane_reader.py +5 -1
  26. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hook_output.py +3 -0
  27. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_lane_command.py +80 -3
  28. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_schedule_command.py +35 -12
  29. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_stall_alert.py +101 -62
  30. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/LICENSE +0 -0
  31. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/setup.cfg +0 -0
  32. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/__main__.py +0 -0
  33. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/__init__.py +0 -0
  34. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/backends.py +0 -0
  35. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/codex_cli.py +0 -0
  36. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/pack.py +0 -0
  37. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/prices.py +0 -0
  38. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/providers.py +0 -0
  39. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/quality.py +0 -0
  40. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/refresh_prices.py +0 -0
  41. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/rules.py +0 -0
  42. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/runner.py +0 -0
  43. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/signal_score.py +0 -0
  44. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/bench/validate.py +0 -0
  45. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/caller.py +0 -0
  46. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/capture/__init__.py +0 -0
  47. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/capture/harden.py +0 -0
  48. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/capture/lineage.py +0 -0
  49. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/capture/liveness.py +0 -0
  50. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/capture/manifest.py +0 -0
  51. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/capture/paths.py +0 -0
  52. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/capture/verify.py +0 -0
  53. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/cell.py +0 -0
  54. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/chain_token.py +0 -0
  55. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/channel.py +0 -0
  56. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/__init__.py +0 -0
  57. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/_content.py +0 -0
  58. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/_display.py +0 -0
  59. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/_gateway_client.py +0 -0
  60. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/add.py +0 -0
  61. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/bench.py +0 -0
  62. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/board_merge_check.py +0 -0
  63. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/brain.py +0 -0
  64. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/brain_ask.py +0 -0
  65. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/cell.py +0 -0
  66. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/cell_probe.py +0 -0
  67. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  68. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/channel.py +0 -0
  69. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/chat.py +0 -0
  70. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/codegraph.py +0 -0
  71. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/codegraph_hook.py +0 -0
  72. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  73. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/codex_waker.py +0 -0
  74. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/compress.py +0 -0
  75. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/daemon.py +0 -0
  76. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/dreaming.py +0 -0
  77. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/event.py +0 -0
  78. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/gateway.py +0 -0
  79. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/gh_route.py +0 -0
  80. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/group.py +0 -0
  81. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/guide.py +0 -0
  82. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/highlight.py +0 -0
  83. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/hook_interpreter.py +0 -0
  84. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/hooks.py +0 -0
  85. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/import_session.py +0 -0
  86. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/init.py +0 -0
  87. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  88. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/install_hook.py +0 -0
  89. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  90. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
  91. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
  92. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  93. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/mcp_server.py +0 -0
  94. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/memory.py +0 -0
  95. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
  96. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/memory_sync.py +0 -0
  97. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/monitor.py +0 -0
  98. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/okf_links.py +0 -0
  99. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/onboard.py +0 -0
  100. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  101. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  102. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/protocol_handler.py +0 -0
  103. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/ratify.py +0 -0
  104. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/rowclear_hook.py +0 -0
  105. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/security.py +0 -0
  106. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/service.py +0 -0
  107. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/spawn.py +0 -0
  108. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/sweep.py +0 -0
  109. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/timeline.py +0 -0
  110. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/triage.py +0 -0
  111. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/version.py +0 -0
  112. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/wake_hook_output.py +0 -0
  113. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/commands/watchdog.py +0 -0
  114. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/compress/__init__.py +0 -0
  115. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/compress/levers.py +0 -0
  116. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/compress/marker.py +0 -0
  117. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/compress/verify.py +0 -0
  118. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/console_safe.py +0 -0
  119. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/delivery_queue.py +0 -0
  120. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dm_frame.py +0 -0
  121. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/__init__.py +0 -0
  122. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/candidates.py +0 -0
  123. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/clone.py +0 -0
  124. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/enrich.py +0 -0
  125. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/index_check.py +0 -0
  126. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/notify.py +0 -0
  127. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/organize.py +0 -0
  128. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/probes.py +0 -0
  129. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/report.py +0 -0
  130. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/run.py +0 -0
  131. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/slm.py +0 -0
  132. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/transcripts.py +0 -0
  133. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/dreaming/verify.py +0 -0
  134. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/gateway/__init__.py +0 -0
  135. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/gateway/feature_registry.py +0 -0
  136. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/gateway/lanes_control.py +0 -0
  137. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/gateway/schema.sql +0 -0
  138. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/gateway/server.py +0 -0
  139. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/gateway/services_control.py +0 -0
  140. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/gateway_default.py +0 -0
  141. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/gh_identity.py +0 -0
  142. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/guide/GUIDE.md +0 -0
  143. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/identity.py +0 -0
  144. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/launchd/swarph-codex-outbox.plist +0 -0
  145. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/launchd/swarph-codex-outbox.timer.plist +0 -0
  146. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/launchd/swarph-monitor.plist +0 -0
  147. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/launchd/swarph-watchdog.plist +0 -0
  148. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/launchd/swarph-watchdog.timer.plist +0 -0
  149. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/launchd_render.py +0 -0
  150. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/main.py +0 -0
  151. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/multiplexer.py +0 -0
  152. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/operator/__init__.py +0 -0
  153. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/operator/__main__.py +0 -0
  154. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/operator/api.py +0 -0
  155. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/operator/cli.py +0 -0
  156. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/operator/config.py +0 -0
  157. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/operator/fmt.py +0 -0
  158. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/orphan_daemons.py +0 -0
  159. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/pane_probe.py +0 -0
  160. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/parsers/__init__.py +0 -0
  161. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/parsers/claude.py +0 -0
  162. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
  163. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  164. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  165. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  166. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  167. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  168. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  169. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  170. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  171. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  172. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  173. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  174. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/peer_executor.py +0 -0
  175. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/peer_executor_windows.py +0 -0
  176. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/peer_reconciliation.py +0 -0
  177. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/peer_reply_outbox.py +0 -0
  178. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/peer_service_host.py +0 -0
  179. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/peer_service_payload.py +0 -0
  180. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/peer_service_reply.py +0 -0
  181. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/peer_staging.py +0 -0
  182. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/query_filters.py +0 -0
  183. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/quota_sync.py +0 -0
  184. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/rowclear.py +0 -0
  185. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/scripts/__init__.py +0 -0
  186. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  187. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  188. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  189. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  190. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
  191. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/scrub.py +0 -0
  192. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/service/__init__.py +0 -0
  193. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/service/app.py +0 -0
  194. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/service/providers.py +0 -0
  195. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/session_bridge.py +0 -0
  196. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  197. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  198. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/source_text.py +0 -0
  199. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/codex-waker.default +0 -0
  200. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  201. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  202. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  203. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  204. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  205. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
  206. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
  207. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  208. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  209. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  210. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
  211. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
  212. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-triage.service +0 -0
  213. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
  214. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  215. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  216. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  217. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/timeline_paths.py +0 -0
  218. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/tokens.py +0 -0
  219. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/triage/__init__.py +0 -0
  220. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/triage/backend.py +0 -0
  221. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/triage/job.py +0 -0
  222. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/triage/owners.json +0 -0
  223. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/triage/router.py +0 -0
  224. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/triage/rows.py +0 -0
  225. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli/triage/sensor.py +0 -0
  226. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  227. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  228. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli.egg-info/requires.txt +0 -0
  229. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/src/swarph_cli.egg-info/top_level.txt +0 -0
  230. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1006_board_publisher.py +0 -0
  231. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1006_session_board.py +0 -0
  232. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1010_strand_only.py +0 -0
  233. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1013_spawn_channel.py +0 -0
  234. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1017_muse_tui.py +0 -0
  235. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1050_surrogate_wake.py +0 -0
  236. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1052_opencode_deaf.py +0 -0
  237. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1059_watchdog_unread_env.py +0 -0
  238. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1061_roster_cli.py +0 -0
  239. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1064_stuck_sweep.py +0 -0
  240. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1065_release.py +0 -0
  241. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1066_quiet_wakes.py +0 -0
  242. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1068_structured_accept_cli.py +0 -0
  243. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1071_quota_sync.py +0 -0
  244. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1073_triage.py +0 -0
  245. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1073_triage_board.py +0 -0
  246. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1073_wheel_install.py +0 -0
  247. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1075_task_cli.py +0 -0
  248. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1083_openai_decisions.py +0 -0
  249. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1144_cell_yaml_github.py +0 -0
  250. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1197_commander_taps.py +0 -0
  251. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1203_swarph_me_refusal.py +0 -0
  252. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1206_offer_question.py +0 -0
  253. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1214_egress.py +0 -0
  254. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1219_egress_probe.py +0 -0
  255. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_1221_quota_windows.py +0 -0
  256. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_124_register_merge.py +0 -0
  257. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_126_pending_from_complete.py +0 -0
  258. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  259. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_138_memory_navigate.py +0 -0
  260. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_139_tool_probe.py +0 -0
  261. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_183_card_anchor.py +0 -0
  262. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_184_notify_honesty.py +0 -0
  263. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_201_win32_bash_refusal.py +0 -0
  264. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_243_onboard_per_peer_token.py +0 -0
  265. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_307_task4_ask_reply.py +0 -0
  266. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  267. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_319_refusal_exit_codes.py +0 -0
  268. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_323_mistral_backend.py +0 -0
  269. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_332_report_organize_findings.py +0 -0
  270. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_356_query_filters.py +0 -0
  271. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_397_gh_identity_router.py +0 -0
  272. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_397_router_preflight.py +0 -0
  273. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_402_one_identity_resolver.py +0 -0
  274. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_432_rowclear.py +0 -0
  275. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_467b_onboard_operator_credential.py +0 -0
  276. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_472_register_caller_binding.py +0 -0
  277. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_484_codex_queue_sink.py +0 -0
  278. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_523_guide.py +0 -0
  279. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_524_conftest_hermeticity.py +0 -0
  280. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_532_accept_flag.py +0 -0
  281. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_535_version_capability.py +0 -0
  282. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_538_signal_bench.py +0 -0
  283. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_546_default_gateway.py +0 -0
  284. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_547_verbs_from_registry.py +0 -0
  285. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_548_gateway_remainder.py +0 -0
  286. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_552_codegraph_gateway.py +0 -0
  287. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_555_relay_row_shape.py +0 -0
  288. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_556_relay_freshness.py +0 -0
  289. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_559_edges_truncated.py +0 -0
  290. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_564_bootstrap_first_peer.py +0 -0
  291. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  292. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_579_register_bootstrap_message.py +0 -0
  293. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_591_cli_step_graph.py +0 -0
  294. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_644_monitor_supervision.py +0 -0
  295. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_648_install_unit.py +0 -0
  296. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_654_reexec.py +0 -0
  297. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_656_owned_slm.py +0 -0
  298. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_684_dreaming_verb.py +0 -0
  299. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_689_pkg_version_order.py +0 -0
  300. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_715_grok_wake.py +0 -0
  301. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_716_timeline_one_path.py +0 -0
  302. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_723_grok_0251.py +0 -0
  303. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_724_ps1_ascii_or_bom.py +0 -0
  304. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_725_stdio_reconfigure.py +0 -0
  305. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_726_grok_limit_screen.py +0 -0
  306. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_729_arm_check_delivery_gap.py +0 -0
  307. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_729_dm_once.py +0 -0
  308. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_729_wake_watchdog.py +0 -0
  309. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_734_dreaming_enrich_degrade.py +0 -0
  310. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_735_dm_mcp_tools.py +0 -0
  311. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_739_wake_writer.py +0 -0
  312. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_740_edit_project.py +0 -0
  313. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_762_cards_edit_priority.py +0 -0
  314. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_764_enrich_collapse.py +0 -0
  315. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_801_confirm_flow_cli.py +0 -0
  316. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_802_stage_history.py +0 -0
  317. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_825_codegraph_hook_noise.py +0 -0
  318. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_825_install_posttooluse_only.py +0 -0
  319. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_825_remaining_cap_shred_bind.py +0 -0
  320. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_829_counterfactual_column.py +0 -0
  321. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_830_hook_binding_version.py +0 -0
  322. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_84_cli_labels.py +0 -0
  323. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_866_doctrine_guide.py +0 -0
  324. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_872_identity_refuses_not_warns.py +0 -0
  325. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_874_source_text.py +0 -0
  326. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
  327. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_937_dreaming_notify.py +0 -0
  328. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_938_organize_line_limit.py +0 -0
  329. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_941_bench_backends.py +0 -0
  330. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_941_harness_342.py +0 -0
  331. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_945_same_line_pairing.py +0 -0
  332. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_955_prompt_audit.py +0 -0
  333. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_957_auth_http.py +0 -0
  334. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_959_venv_interpreter.py +0 -0
  335. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_960_channel.py +0 -0
  336. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
  337. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_961_cursor_grok_footer.py +0 -0
  338. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_961_loud_stop.py +0 -0
  339. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_963_plugin_manifest.py +0 -0
  340. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_964_channel_cell.py +0 -0
  341. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_965_mesh_wait.py +0 -0
  342. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_975_channel_hop.py +0 -0
  343. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_add_security_gate.py +0 -0
  344. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_artifact_add.py +0 -0
  345. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_artifact_hash.py +0 -0
  346. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_artifact_lib.py +0 -0
  347. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_artifact_mcp.py +0 -0
  348. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_artifact_skill.py +0 -0
  349. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_artifact_tool.py +0 -0
  350. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_artifact_uri.py +0 -0
  351. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_bench_backends.py +0 -0
  352. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_bench_codex_cli.py +0 -0
  353. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_bench_command.py +0 -0
  354. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_bench_pack.py +0 -0
  355. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_bench_prices.py +0 -0
  356. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_bench_quality.py +0 -0
  357. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_bench_runner.py +0 -0
  358. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_bench_validate.py +0 -0
  359. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_board_card_thread.py +0 -0
  360. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_board_command.py +0 -0
  361. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_board_merge_check.py +0 -0
  362. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_board_obligation_close.py +0 -0
  363. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_brain_ask_command.py +0 -0
  364. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_brain_ask_env_diagnosis.py +0 -0
  365. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_brain_ask_identity_explicitness.py +0 -0
  366. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_brain_command.py +0 -0
  367. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_caller_meta_guard.py +0 -0
  368. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_capture_lineage.py +0 -0
  369. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_capture_liveness.py +0 -0
  370. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_capture_manifest.py +0 -0
  371. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_capture_paths.py +0 -0
  372. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_capture_security.py +0 -0
  373. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_cell_command_dispatch.py +0 -0
  374. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_cell_harden.py +0 -0
  375. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_cell_loader.py +0 -0
  376. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_cell_selfcheck.py +0 -0
  377. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_cell_verify.py +0 -0
  378. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_chain_token.py +0 -0
  379. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_channel_command.py +0 -0
  380. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  381. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_channel_post.py +0 -0
  382. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_channel_wake_policy_filter.py +0 -0
  383. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_chat_command.py +0 -0
  384. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_claude_parser.py +0 -0
  385. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_claude_tmux_template.py +0 -0
  386. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_codegraph_caller_scope.py +0 -0
  387. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_codegraph_command.py +0 -0
  388. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_codegraph_hook.py +0 -0
  389. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_codegraph_mcp.py +0 -0
  390. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_codex_waker.py +0 -0
  391. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_compress_caller_convention.py +0 -0
  392. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_compress_command.py +0 -0
  393. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_compress_levers.py +0 -0
  394. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_compress_marker.py +0 -0
  395. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_compress_verify.py +0 -0
  396. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_console_encoding_e2e.py +0 -0
  397. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_content_composition.py +0 -0
  398. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_copilot_membrane.py +0 -0
  399. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_cursor_membrane.py +0 -0
  400. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_daemon_command.py +0 -0
  401. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_daemon_console_encoding.py +0 -0
  402. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_daemon_delivery.py +0 -0
  403. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_delivery_queue.py +0 -0
  404. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_display_sanitize.py +0 -0
  405. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  406. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_event_emit.py +0 -0
  407. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_feature_to_uri.py +0 -0
  408. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_gateway_brain.py +0 -0
  409. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_gateway_client.py +0 -0
  410. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_gateway_command.py +0 -0
  411. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_gateway_message_idempotency.py +0 -0
  412. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  413. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_group_command.py +0 -0
  414. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_guide_commands_parse.py +0 -0
  415. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_guide_selfcheck.py +0 -0
  416. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_heartbeat_check.py +0 -0
  417. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_highlight_command.py +0 -0
  418. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hooks_activity_marker.py +0 -0
  419. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hooks_add.py +0 -0
  420. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hooks_bundle.py +0 -0
  421. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hooks_init.py +0 -0
  422. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hooks_legacy_generation_removal.py +0 -0
  423. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hooks_lifecycle.py +0 -0
  424. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hooks_merge.py +0 -0
  425. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hooks_verify.py +0 -0
  426. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  427. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_hooks_win32_command_path.py +0 -0
  428. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_import_command.py +0 -0
  429. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_inbox_identity_provenance.py +0 -0
  430. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_init_command.py +0 -0
  431. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_init_provider_menu.py +0 -0
  432. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_install_codex_hooks.py +0 -0
  433. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_install_hook.py +0 -0
  434. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_install_multiplexer_command.py +0 -0
  435. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_install_postcompact_hook.py +0 -0
  436. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_install_wake_hook.py +0 -0
  437. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_launchd_units.py +0 -0
  438. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_main.py +0 -0
  439. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_main_unknown_verb_guard.py +0 -0
  440. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mcp_missing_hint.py +0 -0
  441. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mcp_server.py +0 -0
  442. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_memory_command.py +0 -0
  443. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_memory_emit_snippet.py +0 -0
  444. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_memory_gateway.py +0 -0
  445. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_memory_sync.py +0 -0
  446. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_memory_sync_membrane.py +0 -0
  447. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mesh_command.py +0 -0
  448. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mesh_inbox_mark_read.py +0 -0
  449. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mesh_inbox_sanitize.py +0 -0
  450. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mesh_originate_thread_623.py +0 -0
  451. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mesh_send_unknown_peer.py +0 -0
  452. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mesh_sidecar.py +0 -0
  453. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  454. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mesh_sidecar_muse_sink.py +0 -0
  455. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  456. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_meta_edge_identity.py +0 -0
  457. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_monitor_channel_poll.py +0 -0
  458. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_monitor_cli.py +0 -0
  459. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_monitor_daemon_collision.py +0 -0
  460. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_monitor_self_name_verification.py +0 -0
  461. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_monitor_state_split.py +0 -0
  462. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_multiplexer.py +0 -0
  463. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_muse_membrane.py +0 -0
  464. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_muse_own_cli.py +0 -0
  465. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_obligation_close_is_surfaced.py +0 -0
  466. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_okf_links.py +0 -0
  467. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_onboard_command.py +0 -0
  468. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_opencode_membrane.py +0 -0
  469. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_opencode_plugin.py +0 -0
  470. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_operator_me.py +0 -0
  471. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_orphan_daemons.py +0 -0
  472. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_packaged_artifacts_exist.py +0 -0
  473. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_packaged_skills.py +0 -0
  474. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_peer_executor.py +0 -0
  475. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_peer_executor_windows.py +0 -0
  476. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_peer_reply_drain_command.py +0 -0
  477. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_peer_reply_drain_supervisor.py +0 -0
  478. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_peer_reply_outbox.py +0 -0
  479. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_peer_reply_transport.py +0 -0
  480. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_peer_service_e2e.py +0 -0
  481. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_peer_service_host.py +0 -0
  482. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_peer_service_payload.py +0 -0
  483. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_peer_service_reply.py +0 -0
  484. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_postcompact_recall.py +0 -0
  485. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_process_liveness.py +0 -0
  486. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_protocol_handler.py +0 -0
  487. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_providers_isolation.py +0 -0
  488. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_ratify_command.py +0 -0
  489. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_readme_claims_no_gateway_default.py +0 -0
  490. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_repl_caller_convention.py +0 -0
  491. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_schedule_create_contract.py +0 -0
  492. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_scrub.py +0 -0
  493. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_security.py +0 -0
  494. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_service_app.py +0 -0
  495. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_service_command.py +0 -0
  496. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_service_providers.py +0 -0
  497. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_session_bridge_inject.py +0 -0
  498. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_session_bridge_probe.py +0 -0
  499. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_session_bridge_resolve.py +0 -0
  500. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_session_path_role_gate.py +0 -0
  501. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_shipped_units_match_the_cli.py +0 -0
  502. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_smoke_chat.py +0 -0
  503. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_smoke_one_shot.py +0 -0
  504. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_smoke_phase_5_5.py +0 -0
  505. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_spawn_base_hoist.py +0 -0
  506. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_spawn_command.py +0 -0
  507. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_spawn_identity_stamp.py +0 -0
  508. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_spawn_live_pin.py +0 -0
  509. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_spawn_mitosis_lineage.py +0 -0
  510. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_spawn_tmux_session.py +0 -0
  511. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_spawn_windows_relaunch.py +0 -0
  512. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_subprocess_decode_encoding.py +0 -0
  513. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_timeline_command.py +0 -0
  514. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_tmux_wake_runstate_defer.py +0 -0
  515. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_tmux_wake_session_reanchor.py +0 -0
  516. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_tmux_wake_stale.py +0 -0
  517. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_tmux_wake_submit_verify.py +0 -0
  518. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_token_file_one_parser.py +0 -0
  519. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_token_precedence_explicit_first.py +0 -0
  520. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_unified_token_resolver.py +0 -0
  521. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_version_command.py +0 -0
  522. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_version_consistency.py +0 -0
  523. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_vibe_membrane.py +0 -0
  524. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_watchdog.py +0 -0
  525. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_watchdog_dm_wake.py +0 -0
  526. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  527. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  528. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_watchdog_emit_health.py +0 -0
  529. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_watchdog_install_flags.py +0 -0
  530. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_watchdog_model_rung.py +0 -0
  531. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/tests/test_watchdog_stale_peers.py +0 -0
  532. {swarph_cli-0.72.28 → swarph_cli-0.72.29}/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.28
3
+ Version: 0.72.29
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
@@ -179,7 +179,7 @@ The mesh **board** — the projects + cards kanban the mesh coordinates on — a
179
179
  ```
180
180
  swarph board projects list
181
181
  swarph board projects add <slug> --title "…" [--goal "…"]
182
- swarph board cards list [--project <id|slug>] [--stage <s>] [--assignee <who>]
182
+ swarph board cards list [--project <id|slug>] [--stage <s>] [--assignee <who>] [--search <text>] # --search: title OR body, says how many cards it searched
183
183
  swarph board cards show <id>
184
184
  swarph board cards add --project <id|slug> --title "…" [--body "…"] [--ai2] [--priority N]
185
185
  swarph board cards edit <id> [--title "…"] [--body "…"] [--project <id|slug>] [--priority N]
@@ -130,7 +130,7 @@ The mesh **board** — the projects + cards kanban the mesh coordinates on — a
130
130
  ```
131
131
  swarph board projects list
132
132
  swarph board projects add <slug> --title "…" [--goal "…"]
133
- swarph board cards list [--project <id|slug>] [--stage <s>] [--assignee <who>]
133
+ swarph board cards list [--project <id|slug>] [--stage <s>] [--assignee <who>] [--search <text>] # --search: title OR body, says how many cards it searched
134
134
  swarph board cards show <id>
135
135
  swarph board cards add --project <id|slug> --title "…" [--body "…"] [--ai2] [--priority N]
136
136
  swarph board cards edit <id> [--title "…"] [--body "…"] [--project <id|slug>] [--priority N]
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swarph-cli"
7
- version = "0.72.28"
7
+ version = "0.72.29"
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" }
@@ -173,3 +173,6 @@ testpaths = ["tests"]
173
173
  # nearly identical. That agreement is a polluted baseline, not isolation.
174
174
  pythonpath = ["src"]
175
175
  addopts = "-v --tb=short"
176
+ markers = [
177
+ "live_tmux: drives a real tmux server/pane; opt-in, and the test must state its reason (card #1034)",
178
+ ]
@@ -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.28"
19
+ __version__ = "0.72.29"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -23,9 +23,12 @@ class CliResult:
23
23
 
24
24
 
25
25
  def build_argv(model_id: str, system: str) -> list:
26
+ # Card #1090: one token each. --mcp-config is variadic, so a following
27
+ # JSON token is consumed only while the token after that is a flag.
26
28
  return ["claude", "-p", "--model", model_id, "--system-prompt", system, "--max-turns", "1",
27
- "--output-format", "stream-json", "--verbose", "--strict-mcp-config",
28
- "--mcp-config", '{"mcpServers":{}}', "--tools", "", "--setting-sources", ""]
29
+ "--output-format", "stream-json", "--verbose",
30
+ "--tools=", "--strict-mcp-config",
31
+ '--mcp-config={"mcpServers":{}}', "--setting-sources="]
29
32
 
30
33
 
31
34
  def clean_env(env: dict) -> dict:
@@ -71,9 +71,11 @@ def _patch_json(url: str, body: dict, token: str, *, timeout: float = 10.0) -> t
71
71
  # ── pure builders (unit-tested) ───────────────────────────────────────────────
72
72
 
73
73
  def _cards_list_url(gateway: str, *, project=None, stage=None, assignee=None,
74
- label=None) -> str:
74
+ label=None, search=None) -> str:
75
75
  q = {k: v for k, v in (("project", project), ("stage", stage),
76
76
  ("assignee", assignee), ("label", label)) if v}
77
+ if search is not None: # blank still goes: the gateway refuses it, we do not drop it
78
+ q["q"] = search
77
79
  base = f"{gateway.rstrip('/')}/board/cards"
78
80
  return f"{base}?{urllib.parse.urlencode(q)}" if q else base
79
81
 
@@ -353,6 +355,10 @@ def _format_due_head(data) -> list[str]:
353
355
  def _format_cards(data) -> str:
354
356
  head = _format_due_head(data)
355
357
  rows = _cards_of(data)
358
+ if isinstance(data, dict) and "searched" in data:
359
+ # #931: a zero must say how many cards it looked at.
360
+ head = [f"searched {data['searched']} cards: {len(rows)} match"] + (
361
+ [""] + head if head else [])
356
362
  if not rows:
357
363
  body = ["(no cards)"]
358
364
  else:
@@ -604,14 +610,49 @@ def _thread_line(d) -> str:
604
610
  f"(#509/#562 — the VERB is the mechanism, the thread is where it lands)")
605
611
 
606
612
 
613
+ def _hours_token(n) -> str:
614
+ if isinstance(n, float) and n.is_integer():
615
+ n = int(n)
616
+ return str(n)
617
+
618
+
619
+ def _clock_line(d) -> str | None:
620
+ """The due-date clock (#935). It starts when the row is taken, not now.
621
+
622
+ `clock_hours` is the menu step's hours, or the `--hours` override.
623
+ `timeout_at` is a different clock — when the row reads OVERDUE — and
624
+ is not this line. Absent fields mean an older gateway; the caller
625
+ keeps its previous sentence rather than inventing a clock.
626
+ """
627
+ hours = d.get("clock_hours")
628
+ if hours is None:
629
+ return None
630
+ source = d.get("clock_source") or "menu"
631
+ menu = d.get("menu_hours")
632
+ if (source == "override" and isinstance(menu, (int, float))
633
+ and not isinstance(menu, bool) and menu
634
+ and isinstance(hours, (int, float)) and not isinstance(hours, bool)):
635
+ if hours % menu == 0:
636
+ detail = f"override, {int(hours // menu)}x menu {_hours_token(menu)}h"
637
+ else:
638
+ detail = f"override, menu {_hours_token(menu)}h"
639
+ else:
640
+ detail = str(source)
641
+ return f"clock: {_hours_token(hours)}h ({detail}) — STARTS ON TAKE, not now"
642
+
643
+
607
644
  def _format_ask(d) -> str:
608
- """One line naming the obligation, its holder, and when it goes red.
645
+ """Name the obligation, who owes it, and the deadline clock.
609
646
 
610
647
  >>> NAMING THE DEADLINE OR ITS ABSENCE IS THE POINT, NOT DECORATION. <<< #145's
611
648
  lesson, one layer over: "0 overdue" must not be able to mean "nobody set dates".
612
- An obligation with no timeout never goes red on its own, and the operator has to
613
- be told that AT THE MOMENT THEY CREATE IT — afterwards it looks identical to one
614
- that simply is not late yet.
649
+ The deadline is the due-date clock (`clock_hours`): the menu step's hours,
650
+ or the `--hours` override, and it STARTS ON TAKE, not at mint (#935).
651
+ `timeout_at` is the other clock — when the row READS OVERDUE — and is
652
+ printed under that name, never as the deadline. A response that carries
653
+ neither clock says NO TIMEOUT, because an obligation with no timeout never
654
+ goes red on its own and the operator has to be told that AT THE MOMENT
655
+ THEY CREATE IT.
615
656
 
616
657
  #532 applies the same rule to the falsifier: an obligation with no accept
617
658
  check reads RED in the sweep, and one whose check has no FAIL branch is
@@ -619,9 +660,17 @@ def _format_ask(d) -> str:
619
660
  rows look identical to sound ones.
620
661
  """
621
662
  when = d.get("timeout_at")
622
- deadline = f"overdue after {when}" if when else _NO_TIMEOUT
623
- return (f"obligation #{d.get('id')} on card #{d.get('card_id')}: "
624
- f"{d.get('holder')} owes it, status={d.get('status')}, {deadline}\n"
663
+ clock = _clock_line(d)
664
+ head = (f"obligation #{d.get('id')} on card #{d.get('card_id')}: "
665
+ f"{d.get('holder')} owes it, status={d.get('status')}")
666
+ if clock:
667
+ extra = f"\n {clock}"
668
+ extra += f"\n overdue after {when}" if when else f"\n {_NO_TIMEOUT}"
669
+ else:
670
+ deadline = f"overdue after {when}" if when else _NO_TIMEOUT
671
+ head = f"{head}, {deadline}"
672
+ extra = ""
673
+ return (f"{head}{extra}\n"
625
674
  f" {_accept_line(d.get('accept'))}\n"
626
675
  f" {_thread_line(d)}")
627
676
 
@@ -763,6 +812,13 @@ def _ask_line(d) -> str:
763
812
  if missing:
764
813
  line += f" · still missing: {missing}"
765
814
  if not str(state).startswith("closed"):
815
+ clock = _clock_line(d)
816
+ if clock:
817
+ # #935: the due-date clock, then the overdue clock under its own name.
818
+ # A stepped mint used to say neither, so --timeout-hours was read as the due date.
819
+ line += "\n " + clock
820
+ if d.get("timeout_at"):
821
+ line += "\n overdue after " + _s(d["timeout_at"])
766
822
  line += "\n " + _accept_line(d.get("accept"))
767
823
  if d.get("step") is None:
768
824
  # unstepped: no menu clock, no container — the pre-#591 rules hold
@@ -974,6 +1030,9 @@ def _build_parser() -> argparse.ArgumentParser:
974
1030
  cl = cards.add_parser("list", help="list cards")
975
1031
  cl.add_argument("--project"); cl.add_argument("--stage"); cl.add_argument("--assignee")
976
1032
  cl.add_argument("--label", help="only cards carrying this label (exact match)")
1033
+ cl.add_argument("--search", metavar="TEXT",
1034
+ help="only cards whose title OR body contains TEXT (case-insensitive, "
1035
+ "matched by the gateway); prints how many cards were searched")
977
1036
  cl.add_argument("--json", action="store_true"); _add_common(cl)
978
1037
  cs = cards.add_parser("show", help="show one card"); cs.add_argument("id", type=int)
979
1038
  cs.add_argument("--json", action="store_true"); _add_common(cs)
@@ -1034,7 +1093,8 @@ def _build_parser() -> argparse.ArgumentParser:
1034
1093
  ck.add_argument("what", help="what is owed, in one line")
1035
1094
  ck.add_argument("--timeout-hours", type=int, default=None,
1036
1095
  help="hours until this obligation reads OVERDUE (default: none, "
1037
- "which means it never goes red on its own)")
1096
+ "which means it never goes red on its own). This is not "
1097
+ "the due-date clock; that is --hours, and it starts on take")
1038
1098
  ck.add_argument("--accept", default=None, metavar='"PASS = ... | FAIL = ..."',
1039
1099
  help="the falsifiable check that closes this obligation "
1040
1100
  "(#532). Omitting it mints an obligation that reads RED "
@@ -1057,7 +1117,9 @@ def _build_parser() -> argparse.ArgumentParser:
1057
1117
  help="explicit edges by step name (added to the menu's); repeatable, "
1058
1118
  "comma lists and the contract's `+step` spelling all accepted")
1059
1119
  ck.add_argument("--hours", type=int, default=None,
1060
- help="clock override, up to 4x the menu value")
1120
+ help="the due-date clock in hours. Starts on take, not now. "
1121
+ "Default is the menu step's hours. Up to 4x that value. "
1122
+ "Not the overdue timeout (--timeout-hours)")
1061
1123
  ck.add_argument("--holder", dest="holder_flag", default=None, metavar="PEER|me",
1062
1124
  help="who owes it: a peer (offered), `me` (open: a bound self-ask "
1063
1125
  "is a take), or omit (requested: the eligible set is DM'd)")
@@ -1186,7 +1248,9 @@ def _build_parser() -> argparse.ArgumentParser:
1186
1248
  oa.add_argument("--accept-json", default=None, metavar="'{...}'",
1187
1249
  help="replace the check with a structured one (#1068); "
1188
1250
  "mutually exclusive with --accept")
1189
- oa.add_argument("--hours", type=int, default=None, help="clock override, up to 4x the menu value")
1251
+ oa.add_argument("--hours", type=int, default=None,
1252
+ help="the due-date clock, starts on take, up to 4x the menu value. "
1253
+ "Not the overdue timeout")
1190
1254
  oa.add_argument("--needs-add", action="append", dest="needs_add", default=None,
1191
1255
  metavar="STEP", help="add an edge (repeatable)")
1192
1256
  oa.add_argument("--needs-remove", action="append", dest="needs_remove", default=None,
@@ -1338,7 +1402,15 @@ def run_board(argv: list[str]) -> int:
1338
1402
  return 1
1339
1403
  st, d = _http_get_json(_cards_list_url(gw, project=pid, stage=args.stage,
1340
1404
  assignee=args.assignee,
1341
- label=getattr(args, "label", None)), token)
1405
+ label=getattr(args, "label", None),
1406
+ search=args.search), token)
1407
+ if (args.search is not None and st and 200 <= st < 300
1408
+ and not (isinstance(d, dict) and "searched" in d)):
1409
+ # A gateway older than #931 ignores q and returns EVERY card.
1410
+ print("swarph board: the gateway ignored --search (its reply has no "
1411
+ "`searched` count), so this list is NOT filtered; refusing to "
1412
+ "show it as a search result", file=sys.stderr)
1413
+ return 1
1342
1414
  return _out(st, d, _format_cards, aj)
1343
1415
  if args.command == "show":
1344
1416
  st, d = _http_get_json(f"{gw}/board/cards/{args.id}", token)
@@ -5,10 +5,10 @@ Receives Claude Code's hook-input JSON on stdin, discovers the
5
5
  applicable cell.yaml, and emits a hook-output JSON to stdout
6
6
  containing the starter prompt as ``additionalContext``.
7
7
 
8
- Skipped (no-op) when ``SWARPH_SPAWN=1`` env is set — that environment
9
- marker is set by ``swarph spawn`` to indicate the spawn path already
10
- injected the prompt via ``--append-system-prompt``. Avoids
11
- double-injection when the session was launched through swarph.
8
+ ``SWARPH_SPAWN=1`` means ``swarph spawn`` already put the starter on
9
+ ``--append-system-prompt``. This hook then emits the ten and only the
10
+ ten, so the starter is not doubled. With no ten to read, that path is
11
+ still a no-op.
12
12
 
13
13
  Cell discovery:
14
14
  1. Cwd-local ``./cell.yaml`` (alpha #891 D3 auto-discovery)
@@ -39,13 +39,14 @@ from swarph_cli.cell import (
39
39
  load_cell,
40
40
  read_starter_prompt,
41
41
  )
42
+ from swarph_cli.the_ten import session_block
42
43
 
43
44
 
44
45
  def _emit_no_op() -> int:
45
46
  """Emit empty additionalContext + exit 0.
46
47
 
47
- Used when there's no cell.yaml to load OR when SWARPH_SPAWN=1 OR
48
- on any error path. Hook MUST NOT block session startup.
48
+ Used when there is nothing to add: no starter and no ten, or
49
+ ``SWARPH_SPAWN=1`` with no ten. Hook MUST NOT block session startup.
49
50
  """
50
51
  output = {
51
52
  "hookSpecificOutput": {
@@ -77,12 +78,34 @@ def _discover_cell_path() -> Path | None:
77
78
  return None
78
79
 
79
80
 
80
- def run_hook_output(argv: list[str] | None = None) -> int:
81
- # Skip when launched-via-swarph-spawn (already injected via
82
- # --append-system-prompt; double-injection would duplicate context).
83
- if os.environ.get("SWARPH_SPAWN", "").strip() == "1":
84
- return _emit_no_op()
81
+ def _emit(additional: str) -> int:
82
+ output: dict[str, Any] = {
83
+ "hookSpecificOutput": {
84
+ "hookEventName": "SessionStart",
85
+ "additionalContext": additional,
86
+ }
87
+ }
88
+ print(json.dumps(output))
89
+ return 0
90
+
85
91
 
92
+ def _starter_text() -> str:
93
+ """The cell's starter prompt, or ``""`` when there is nothing to add.
94
+
95
+ A missing cell, a malformed cell, or an unreadable starter is an
96
+ empty starter. The hook still emits the ten when that block exists.
97
+ """
98
+ cell_path = _discover_cell_path()
99
+ if cell_path is None:
100
+ return ""
101
+ try:
102
+ cell = load_cell(cell_path)
103
+ return read_starter_prompt(cell) or ""
104
+ except CellError:
105
+ return ""
106
+
107
+
108
+ def run_hook_output(argv: list[str] | None = None) -> int:
86
109
  # Drain hook-input from stdin (we don't actually use any field
87
110
  # currently, but Claude Code's protocol expects us to consume it
88
111
  # without blocking on TTY-detection edge cases).
@@ -92,32 +115,17 @@ def run_hook_output(argv: list[str] | None = None) -> int:
92
115
  except Exception:
93
116
  pass # swallow stdin-read errors; hook output is the only thing that matters
94
117
 
95
- cell_path = _discover_cell_path()
96
- if cell_path is None:
97
- return _emit_no_op()
98
-
99
- try:
100
- cell = load_cell(cell_path)
101
- except CellError:
102
- # cell.yaml exists but is malformed — emit no-op + skip rather
103
- # than blocking session startup. Operator can fix cell.yaml
104
- # offline; meanwhile sessions still start.
105
- return _emit_no_op()
118
+ # Commit-addressed. Empty when the repo or the ref is missing, and
119
+ # that emptiness must not change the starter-only behaviour.
120
+ block = session_block()
106
121
 
107
- try:
108
- starter = read_starter_prompt(cell)
109
- except CellError:
110
- # starter_prompt_path set but unreadable — emit no-op.
111
- return _emit_no_op()
122
+ # SWARPH_SPAWN=1 means the starter is already on --append-system-prompt.
123
+ # The ten is not part of that flag, so this path still emits the block
124
+ # and only the block.
125
+ if os.environ.get("SWARPH_SPAWN", "").strip() == "1":
126
+ return _emit(block) if block else _emit_no_op()
112
127
 
113
- if not starter:
128
+ parts = [part for part in (_starter_text(), block) if part]
129
+ if not parts:
114
130
  return _emit_no_op()
115
-
116
- output: dict[str, Any] = {
117
- "hookSpecificOutput": {
118
- "hookEventName": "SessionStart",
119
- "additionalContext": starter,
120
- }
121
- }
122
- print(json.dumps(output))
123
- return 0
131
+ return _emit("\n\n".join(parts))
@@ -111,7 +111,22 @@ def _run_create(args: argparse.Namespace) -> int:
111
111
  status, payload = post_json(f"{base}/lanes", body, token)
112
112
  if not _ok(status):
113
113
  return _fail("create", status, payload)
114
- print(f"created lane {args.name}")
114
+ # Card #949. The gateway persists the row at n=0 and starts workers only
115
+ # in scale_lane. Sending n on create is not enough on a server that
116
+ # ignores it, and a bare "created" line reads as if the workers exist.
117
+ # When the operator asked for workers, scale and report both results.
118
+ # n=0 stays a create, and the line says so.
119
+ if args.n and args.n > 0:
120
+ name = urllib.parse.quote(args.name, safe="")
121
+ scale_status, scale_payload = post_json(
122
+ f"{base}/lanes/{name}/scale", {"n": args.n}, token)
123
+ print(f"created lane {args.name}")
124
+ if not _ok(scale_status):
125
+ return _fail("scale", scale_status, scale_payload)
126
+ got = scale_payload.get("n", args.n) if isinstance(scale_payload, dict) else args.n
127
+ print(f"scaled {args.name} -> {got}")
128
+ return 0
129
+ print(f"created lane {args.name} n=0; run lane scale")
115
130
  return 0
116
131
 
117
132
 
@@ -1511,6 +1511,15 @@ class TmuxSink(Sink):
1511
1511
  print(f"[monitor] {self.name}: {reason} — deferring, zero keys",
1512
1512
  flush=True)
1513
1513
  return None
1514
+ # #1034: a pane in copy-mode (or view-mode) swallows the wake keys --
1515
+ # tmux runs them as copy-mode commands, the TUI never sees them, and the
1516
+ # capture still reads idle. Ask tmux, not the screen; if in a mode, send
1517
+ # nothing and keep the DM owed (the same owed-state #1010/#1126 use).
1518
+ if _pane_in_mode(self.target):
1519
+ self.deferred_reason = "pane in copy-mode"
1520
+ print(f"[monitor] {self.name}: pane in copy-mode — deferring, zero keys",
1521
+ flush=True)
1522
+ return None
1514
1523
  # #620: a wake's job is done the moment a TURN is observed running —
1515
1524
  # the cell is awake, whoever woke it (our injected wake fired, or
1516
1525
  # the human typed). Both older clearing paths miss the zombie
@@ -2589,6 +2598,16 @@ def _opencode_turn_finished(lines: list[str]) -> bool:
2589
2598
  # when the same pane is seen unchanged on a later poll at least this
2590
2599
  # many seconds later (the monitor polls each minute, so about 2 polls).
2591
2600
  _MAYBE_START_GRACE_S = 60
2601
+ # Card #1222: the grace above is reset every time the footer CHANGES ("a
2602
+ # progressing turn rewrites this region every poll"), which is right for a
2603
+ # booting turn — but a pane whose footer churns FOREVER (a recreated session
2604
+ # showing a bare header — the 2026-10-18 opencode deafness) re-arms first_seen
2605
+ # on every poll and NEVER matures to idle. wake_outstanding then stands
2606
+ # indefinitely: 8h of deafness, three offers never woke the cell. This ABSOLUTE
2607
+ # cap is anchored to the FIRST sighting of maybe-starting and is NOT reset by
2608
+ # churn, so a bare header past it reads idle and the wake can re-inject. 600 s
2609
+ # matches #616's _WAKE_STALE_S bound.
2610
+ _MAYBE_START_MAX_S = 600.0
2592
2611
 
2593
2612
 
2594
2613
  def _opencode_pane_fingerprint(lines: list[str]) -> str:
@@ -2625,19 +2644,39 @@ def _opencode_poll_verdict(lines: list[str], now: float,
2625
2644
  if last is None or _OPENCODE_DONE.search(last):
2626
2645
  return "idle", fingerprint, None
2627
2646
  first_seen = None
2647
+ capped_since = None
2628
2648
  if isinstance(prior, dict):
2629
2649
  seen = prior.get("first_seen")
2630
2650
  if (prior.get("fingerprint") == fingerprint
2631
2651
  and isinstance(seen, (int, float))
2632
2652
  and not isinstance(seen, bool)):
2633
2653
  first_seen = float(seen)
2654
+ cap = prior.get("capped_since")
2655
+ if isinstance(cap, (int, float)) and not isinstance(cap, bool):
2656
+ capped_since = float(cap)
2657
+ # Card #1222: the first sighting of maybe-starting is remembered in its own
2658
+ # field so FOOTER CHURN cannot reset the hard cap. A bare header that has
2659
+ # deferred for _MAYBE_START_MAX_S is aborting or idle, never still booting.
2660
+ if capped_since is None:
2661
+ capped_since = first_seen if first_seen is not None else now
2662
+ if now - capped_since >= _MAYBE_START_MAX_S:
2663
+ # Card #1222: past the hard cap the pane is idle, AND the record is KEPT
2664
+ # (non-None) so the caller does not drop the anchor. Dropping it would
2665
+ # make the very next poll a first sight -> maybe-starting again: the
2666
+ # deafness would sawtooth instead of ending.
2667
+ return "idle", fingerprint, {
2668
+ "fingerprint": fingerprint,
2669
+ "first_seen": first_seen if first_seen is not None else now,
2670
+ "capped_since": capped_since}
2634
2671
  if first_seen is None:
2635
2672
  return ("maybe-starting", fingerprint,
2636
- {"fingerprint": fingerprint, "first_seen": now})
2673
+ {"fingerprint": fingerprint, "first_seen": now,
2674
+ "capped_since": capped_since})
2637
2675
  if now - first_seen >= _MAYBE_START_GRACE_S:
2638
2676
  return "idle", fingerprint, None
2639
2677
  return ("maybe-starting", fingerprint,
2640
- {"fingerprint": fingerprint, "first_seen": first_seen})
2678
+ {"fingerprint": fingerprint, "first_seen": first_seen,
2679
+ "capped_since": capped_since})
2641
2680
 
2642
2681
 
2643
2682
  def _opencode_in_progress(target: str, ledger=None, now=None):
@@ -2659,7 +2698,10 @@ def _opencode_in_progress(target: str, ledger=None, now=None):
2659
2698
  moment = time.time() if now is None else now
2660
2699
  verdict, _fingerprint, record = _opencode_poll_verdict(
2661
2700
  lines, moment, ledger.get("opencode_maybe_start"))
2662
- if verdict == "maybe-starting":
2701
+ # Card #1222: keep the record whenever the verdict returns one. maybe-starting
2702
+ # carries the grace anchor; the cap-‘idle’ carries the anchor too so the cap
2703
+ # stays anchored across polls. running / grace-idle return None and clear it.
2704
+ if record is not None:
2663
2705
  ledger["opencode_maybe_start"] = record
2664
2706
  else:
2665
2707
  ledger.pop("opencode_maybe_start", None)
@@ -3192,6 +3234,28 @@ def _composer_state(target: str) -> Optional[str]:
3192
3234
  return "busy"
3193
3235
 
3194
3236
 
3237
+ def _pane_in_mode(target: str) -> bool:
3238
+ """True if the pane is in a tmux MODE (copy-mode / view-mode), card #1034.
3239
+
3240
+ In copy-mode the TUI receives nothing: a keystroke is a copy-mode command,
3241
+ the captured screen still reads idle (it shows the scrolled view), and the
3242
+ monitor would mark the DM delivered while the cell never woke -- "delivered
3243
+ is not submitted" with a new cause. Ask tmux, not the screen:
3244
+ #{pane_in_mode} is 1 in a mode. Unknown (tmux cannot answer) reads as NOT in
3245
+ mode, matching the pre-fix behaviour; the composer gate already fails closed
3246
+ on an unreadable pane.
3247
+ """
3248
+ try:
3249
+ r = subprocess.run(
3250
+ ["tmux", "display-message", "-p", "-t", target, "#{pane_in_mode}"],
3251
+ capture_output=True, timeout=5,
3252
+ text=True, encoding="utf-8", errors="replace",
3253
+ )
3254
+ except (OSError, subprocess.TimeoutExpired):
3255
+ return False
3256
+ return r.returncode == 0 and (r.stdout or "").strip() == "1"
3257
+
3258
+
3195
3259
  def _tmux_session_created(target: str) -> Optional[float]:
3196
3260
  """Epoch seconds the target's tmux SESSION was created, or None.
3197
3261
 
@@ -3726,6 +3790,22 @@ def _monitor_iteration(state: MonitorState, *, poll_channels: bool = True) -> No
3726
3790
  _write_cursor_atomic(state.heartbeat_path, {
3727
3791
  "ts": time.time(), "iterations": state.iterations, "pid": os.getpid()})
3728
3792
 
3793
+ # Card #513: detect a SECOND live session under this identity and raise ONE
3794
+ # alarm row. Per-cell, IN the monitor (not the send path). It NEVER kills
3795
+ # anything and never raises out of the loop. Throttled inside.
3796
+ _maybe_duplicate_check(state)
3797
+
3798
+
3799
+ def _maybe_duplicate_check(state: MonitorState) -> None:
3800
+ """Card #513. Enumerate at most once every duplicate_session.CHECK_EVERY ticks
3801
+ (the check spawns `ps`), and never on the first tick so an ordinary monitor
3802
+ test drives one clean iteration. duplicate_session.check swallows its own
3803
+ errors, so this can never break delivery. It NEVER kills anything."""
3804
+ from swarph_cli import duplicate_session
3805
+ if state.iterations % duplicate_session.CHECK_EVERY != 0:
3806
+ return
3807
+ duplicate_session.check(state)
3808
+
3729
3809
 
3730
3810
  def _monitor_loop(state: MonitorState) -> int:
3731
3811
  print(
@@ -297,12 +297,18 @@ def _local_tmux_peers() -> list:
297
297
 
298
298
 
299
299
  def _capture_peer_pane(peer: str):
300
- """One read-only full-height capture of the peer's active pane. Never
301
- sends keys (ruling 6); None on any failure — the peer reads unknown."""
300
+ """One read-only capture of the peer's pane, including scrollback.
301
+
302
+ Card #1228 F2. `capture-pane -p` alone is the visible screen. A Claude
303
+ Code /usage stdout display scrolls off it, so the multi-window parser
304
+ never sees the form it knows. `-S -` starts at the top of history.
305
+ Never sends keys (ruling 6); None on any failure — the peer reads unknown.
306
+ """
302
307
  try:
303
- out = subprocess.run(["tmux", "capture-pane", "-p", "-t", peer],
304
- capture_output=True, timeout=10, text=True,
305
- encoding="utf-8", errors="replace")
308
+ out = subprocess.run(
309
+ ["tmux", "capture-pane", "-p", "-S", "-", "-t", peer],
310
+ capture_output=True, timeout=10, text=True,
311
+ encoding="utf-8", errors="replace")
306
312
  except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
307
313
  return None
308
314
  if out.returncode != 0:
@@ -57,10 +57,11 @@ def _build_parser() -> argparse.ArgumentParser:
57
57
  create.add_argument(
58
58
  "--deliver",
59
59
  choices=["wake", "dm"],
60
- default="wake",
61
- help="delivery mode: wake (default) types into a host-local tmux pane; "
62
- "dm schedules a deferred DM to the target peer — use dm for any "
63
- "cell not on lab's box (card #1081)",
60
+ default="dm",
61
+ help="delivery mode: dm (default) schedules a deferred DM to the target "
62
+ "peer and works for any cell; wake types into a host-local tmux pane "
63
+ "and the gateway refuses it for any cell off lab's box, so pass "
64
+ "--deliver wake only when you mean it (card #1081)",
64
65
  )
65
66
  add_common_args(create)
66
67
 
@@ -196,11 +197,15 @@ def _run_create(args: argparse.Namespace) -> int:
196
197
  body["out_channel"] = args.out_channel
197
198
  if args.min_interval is not None:
198
199
  body["min_interval_sec"] = args.min_interval
199
- if args.deliver == "dm":
200
- body["deliver"] = "dm"
200
+ body["deliver"] = args.deliver
201
201
  status, payload = post_json(f"{base}/scheduled-events", body, token)
202
202
  if not _ok(status):
203
- return _fail("create", status, payload)
203
+ rc = _fail("create", status, payload)
204
+ if status == 403 and "operator-gated" in str(payload.get("detail", "")):
205
+ print("hint: a wake-delivery create is refused as operator-gated for any "
206
+ "cell off lab's box. Use `--deliver dm` (the default) to schedule a "
207
+ "deferred DM to the target peer instead.", file=sys.stderr)
208
+ return rc
204
209
  print(f"scheduled {args.name}")
205
210
  return 0
206
211