swarph-cli 0.72.0__tar.gz → 0.72.2__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 (472) hide show
  1. {swarph_cli-0.72.0/src/swarph_cli.egg-info → swarph_cli-0.72.2}/PKG-INFO +3 -1
  2. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/README.md +2 -0
  3. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/pyproject.toml +1 -1
  4. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/__init__.py +1 -1
  5. swarph_cli-0.72.2/src/swarph_cli/bench/codex_cli.py +127 -0
  6. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/bench.py +7 -0
  7. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/mesh.py +13 -3
  8. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/spawn.py +57 -23
  9. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/wake_hook_output.py +39 -5
  10. {swarph_cli-0.72.0 → swarph_cli-0.72.2/src/swarph_cli.egg-info}/PKG-INFO +3 -1
  11. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli.egg-info/SOURCES.txt +3 -0
  12. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_1006_board_publisher.py +37 -0
  13. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_1013_spawn_channel.py +72 -3
  14. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_1017_muse_tui.py +17 -1
  15. swarph_cli-0.72.2/tests/test_961_loud_stop.py +106 -0
  16. swarph_cli-0.72.2/tests/test_bench_codex_cli.py +138 -0
  17. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/LICENSE +0 -0
  18. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/setup.cfg +0 -0
  19. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/__main__.py +0 -0
  20. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/__init__.py +0 -0
  21. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/backends.py +0 -0
  22. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/claude_cli.py +0 -0
  23. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/pack.py +0 -0
  24. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/prices.py +0 -0
  25. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/providers.py +0 -0
  26. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/quality.py +0 -0
  27. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/refresh_prices.py +0 -0
  28. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/rules.py +0 -0
  29. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/runner.py +0 -0
  30. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/signal_score.py +0 -0
  31. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/validate.py +0 -0
  32. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/caller.py +0 -0
  33. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/__init__.py +0 -0
  34. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/harden.py +0 -0
  35. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/lineage.py +0 -0
  36. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/liveness.py +0 -0
  37. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/manifest.py +0 -0
  38. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/paths.py +0 -0
  39. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/verify.py +0 -0
  40. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/cell.py +0 -0
  41. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/chain_token.py +0 -0
  42. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/channel.py +0 -0
  43. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/__init__.py +0 -0
  44. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/_content.py +0 -0
  45. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/_display.py +0 -0
  46. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/_gateway_client.py +0 -0
  47. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/add.py +0 -0
  48. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/board.py +0 -0
  49. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/board_merge_check.py +0 -0
  50. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/brain.py +0 -0
  51. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/brain_ask.py +0 -0
  52. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/cell.py +0 -0
  53. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/cell_probe.py +0 -0
  54. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  55. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/channel.py +0 -0
  56. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/chat.py +0 -0
  57. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/codegraph.py +0 -0
  58. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/codegraph_hook.py +0 -0
  59. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  60. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/codex_waker.py +0 -0
  61. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/compress.py +0 -0
  62. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/daemon.py +0 -0
  63. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/dreaming.py +0 -0
  64. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/event.py +0 -0
  65. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/gateway.py +0 -0
  66. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/gh_route.py +0 -0
  67. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/group.py +0 -0
  68. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/guide.py +0 -0
  69. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/highlight.py +0 -0
  70. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/hook_interpreter.py +0 -0
  71. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/hook_output.py +0 -0
  72. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/hooks.py +0 -0
  73. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/import_session.py +0 -0
  74. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/init.py +0 -0
  75. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  76. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_hook.py +0 -0
  77. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  78. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
  79. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
  80. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  81. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/lane.py +0 -0
  82. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/mcp_server.py +0 -0
  83. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/memory.py +0 -0
  84. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
  85. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/memory_sync.py +0 -0
  86. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/monitor.py +0 -0
  87. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/okf_links.py +0 -0
  88. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/onboard.py +0 -0
  89. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  90. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  91. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/protocol_handler.py +0 -0
  92. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/ratify.py +0 -0
  93. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/schedule.py +0 -0
  94. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/security.py +0 -0
  95. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/service.py +0 -0
  96. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/timeline.py +0 -0
  97. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/version.py +0 -0
  98. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/watchdog.py +0 -0
  99. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/compress/__init__.py +0 -0
  100. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/compress/levers.py +0 -0
  101. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/compress/marker.py +0 -0
  102. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/compress/verify.py +0 -0
  103. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/console_safe.py +0 -0
  104. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/delivery_queue.py +0 -0
  105. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dm_frame.py +0 -0
  106. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/__init__.py +0 -0
  107. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/candidates.py +0 -0
  108. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/clone.py +0 -0
  109. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/enrich.py +0 -0
  110. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/index_check.py +0 -0
  111. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/notify.py +0 -0
  112. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/organize.py +0 -0
  113. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/probes.py +0 -0
  114. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/report.py +0 -0
  115. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/run.py +0 -0
  116. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/slm.py +0 -0
  117. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/transcripts.py +0 -0
  118. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/verify.py +0 -0
  119. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/__init__.py +0 -0
  120. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/feature_registry.py +0 -0
  121. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/lanes_control.py +0 -0
  122. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/schema.sql +0 -0
  123. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/server.py +0 -0
  124. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/services_control.py +0 -0
  125. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway_default.py +0 -0
  126. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gh_identity.py +0 -0
  127. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/guide/GUIDE.md +0 -0
  128. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/identity.py +0 -0
  129. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/main.py +0 -0
  130. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/multiplexer.py +0 -0
  131. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/__init__.py +0 -0
  132. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/__main__.py +0 -0
  133. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/api.py +0 -0
  134. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/cli.py +0 -0
  135. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/config.py +0 -0
  136. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/fmt.py +0 -0
  137. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/orphan_daemons.py +0 -0
  138. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/pane_probe.py +0 -0
  139. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/parsers/__init__.py +0 -0
  140. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/parsers/claude.py +0 -0
  141. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
  142. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  143. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  144. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  145. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  146. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  147. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  148. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  149. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  150. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  151. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  152. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  153. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_executor.py +0 -0
  154. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_executor_windows.py +0 -0
  155. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_reconciliation.py +0 -0
  156. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_reply_outbox.py +0 -0
  157. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_service_host.py +0 -0
  158. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_service_payload.py +0 -0
  159. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_service_reply.py +0 -0
  160. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_staging.py +0 -0
  161. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/query_filters.py +0 -0
  162. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/__init__.py +0 -0
  163. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  164. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  165. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  166. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  167. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
  168. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/service/__init__.py +0 -0
  169. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/service/app.py +0 -0
  170. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/service/providers.py +0 -0
  171. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/session_bridge.py +0 -0
  172. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  173. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  174. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/source_text.py +0 -0
  175. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/stall_alert.py +0 -0
  176. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/codex-waker.default +0 -0
  177. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  178. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  179. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  180. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  181. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  182. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
  183. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
  184. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  185. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  186. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  187. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  188. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  189. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  190. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/timeline_paths.py +0 -0
  191. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/tokens.py +0 -0
  192. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  193. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  194. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli.egg-info/requires.txt +0 -0
  195. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli.egg-info/top_level.txt +0 -0
  196. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_1006_session_board.py +0 -0
  197. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_124_register_merge.py +0 -0
  198. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_126_pending_from_complete.py +0 -0
  199. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  200. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_138_memory_navigate.py +0 -0
  201. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_139_tool_probe.py +0 -0
  202. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_183_card_anchor.py +0 -0
  203. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_184_notify_honesty.py +0 -0
  204. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_201_win32_bash_refusal.py +0 -0
  205. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_243_onboard_per_peer_token.py +0 -0
  206. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_307_task4_ask_reply.py +0 -0
  207. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  208. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_319_refusal_exit_codes.py +0 -0
  209. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_323_mistral_backend.py +0 -0
  210. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_332_report_organize_findings.py +0 -0
  211. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_356_query_filters.py +0 -0
  212. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_397_gh_identity_router.py +0 -0
  213. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_397_router_preflight.py +0 -0
  214. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_402_one_identity_resolver.py +0 -0
  215. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_467b_onboard_operator_credential.py +0 -0
  216. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_472_register_caller_binding.py +0 -0
  217. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_484_codex_queue_sink.py +0 -0
  218. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_523_guide.py +0 -0
  219. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_524_conftest_hermeticity.py +0 -0
  220. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_532_accept_flag.py +0 -0
  221. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_535_version_capability.py +0 -0
  222. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_538_signal_bench.py +0 -0
  223. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_546_default_gateway.py +0 -0
  224. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_547_verbs_from_registry.py +0 -0
  225. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_548_gateway_remainder.py +0 -0
  226. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_552_codegraph_gateway.py +0 -0
  227. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_555_relay_row_shape.py +0 -0
  228. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_556_relay_freshness.py +0 -0
  229. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_559_edges_truncated.py +0 -0
  230. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_564_bootstrap_first_peer.py +0 -0
  231. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  232. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_579_register_bootstrap_message.py +0 -0
  233. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_591_cli_step_graph.py +0 -0
  234. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_644_monitor_supervision.py +0 -0
  235. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_648_install_unit.py +0 -0
  236. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_654_reexec.py +0 -0
  237. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_656_owned_slm.py +0 -0
  238. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_684_dreaming_verb.py +0 -0
  239. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_689_pkg_version_order.py +0 -0
  240. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_715_grok_wake.py +0 -0
  241. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_716_timeline_one_path.py +0 -0
  242. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_723_grok_0251.py +0 -0
  243. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_724_ps1_ascii_or_bom.py +0 -0
  244. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_725_stdio_reconfigure.py +0 -0
  245. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_726_grok_limit_screen.py +0 -0
  246. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_729_arm_check_delivery_gap.py +0 -0
  247. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_729_dm_once.py +0 -0
  248. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_729_wake_watchdog.py +0 -0
  249. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_734_dreaming_enrich_degrade.py +0 -0
  250. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_735_dm_mcp_tools.py +0 -0
  251. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_739_wake_writer.py +0 -0
  252. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_740_edit_project.py +0 -0
  253. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_762_cards_edit_priority.py +0 -0
  254. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_764_enrich_collapse.py +0 -0
  255. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_801_confirm_flow_cli.py +0 -0
  256. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_802_stage_history.py +0 -0
  257. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_825_codegraph_hook_noise.py +0 -0
  258. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_825_install_posttooluse_only.py +0 -0
  259. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_825_remaining_cap_shred_bind.py +0 -0
  260. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_829_counterfactual_column.py +0 -0
  261. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_830_hook_binding_version.py +0 -0
  262. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_84_cli_labels.py +0 -0
  263. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_866_doctrine_guide.py +0 -0
  264. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_872_identity_refuses_not_warns.py +0 -0
  265. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_874_source_text.py +0 -0
  266. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
  267. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_937_dreaming_notify.py +0 -0
  268. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_938_organize_line_limit.py +0 -0
  269. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_941_bench_backends.py +0 -0
  270. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_941_harness_342.py +0 -0
  271. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_945_same_line_pairing.py +0 -0
  272. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_955_prompt_audit.py +0 -0
  273. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_957_auth_http.py +0 -0
  274. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_959_venv_interpreter.py +0 -0
  275. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_960_channel.py +0 -0
  276. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
  277. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_961_cursor_grok_footer.py +0 -0
  278. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_963_plugin_manifest.py +0 -0
  279. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_964_channel_cell.py +0 -0
  280. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_965_mesh_wait.py +0 -0
  281. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_975_channel_hop.py +0 -0
  282. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_add_security_gate.py +0 -0
  283. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_add.py +0 -0
  284. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_hash.py +0 -0
  285. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_lib.py +0 -0
  286. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_mcp.py +0 -0
  287. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_skill.py +0 -0
  288. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_tool.py +0 -0
  289. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_uri.py +0 -0
  290. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_backends.py +0 -0
  291. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_claude_cli.py +0 -0
  292. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_command.py +0 -0
  293. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_pack.py +0 -0
  294. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_prices.py +0 -0
  295. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_quality.py +0 -0
  296. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_runner.py +0 -0
  297. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_validate.py +0 -0
  298. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_board_card_thread.py +0 -0
  299. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_board_command.py +0 -0
  300. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_board_merge_check.py +0 -0
  301. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_board_obligation_close.py +0 -0
  302. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_brain_ask_command.py +0 -0
  303. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_brain_ask_env_diagnosis.py +0 -0
  304. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_brain_ask_identity_explicitness.py +0 -0
  305. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_brain_command.py +0 -0
  306. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_caller_meta_guard.py +0 -0
  307. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_capture_lineage.py +0 -0
  308. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_capture_liveness.py +0 -0
  309. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_capture_manifest.py +0 -0
  310. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_capture_paths.py +0 -0
  311. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_capture_security.py +0 -0
  312. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cell_command_dispatch.py +0 -0
  313. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cell_harden.py +0 -0
  314. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cell_loader.py +0 -0
  315. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cell_selfcheck.py +0 -0
  316. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cell_verify.py +0 -0
  317. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_chain_token.py +0 -0
  318. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_channel_command.py +0 -0
  319. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  320. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_channel_post.py +0 -0
  321. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_channel_wake_policy_filter.py +0 -0
  322. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_chat_command.py +0 -0
  323. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_claude_parser.py +0 -0
  324. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_claude_tmux_template.py +0 -0
  325. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_codegraph_caller_scope.py +0 -0
  326. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_codegraph_command.py +0 -0
  327. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_codegraph_hook.py +0 -0
  328. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_codegraph_mcp.py +0 -0
  329. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_codex_waker.py +0 -0
  330. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_compress_caller_convention.py +0 -0
  331. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_compress_command.py +0 -0
  332. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_compress_levers.py +0 -0
  333. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_compress_marker.py +0 -0
  334. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_compress_verify.py +0 -0
  335. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_console_encoding_e2e.py +0 -0
  336. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_content_composition.py +0 -0
  337. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cursor_membrane.py +0 -0
  338. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_daemon_command.py +0 -0
  339. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_daemon_console_encoding.py +0 -0
  340. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_daemon_delivery.py +0 -0
  341. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_delivery_queue.py +0 -0
  342. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_display_sanitize.py +0 -0
  343. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  344. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_event_emit.py +0 -0
  345. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_feature_to_uri.py +0 -0
  346. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_gateway_brain.py +0 -0
  347. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_gateway_client.py +0 -0
  348. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_gateway_command.py +0 -0
  349. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_gateway_message_idempotency.py +0 -0
  350. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  351. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_group_command.py +0 -0
  352. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_guide_commands_parse.py +0 -0
  353. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_guide_selfcheck.py +0 -0
  354. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_heartbeat_check.py +0 -0
  355. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_highlight_command.py +0 -0
  356. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hook_output.py +0 -0
  357. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_activity_marker.py +0 -0
  358. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_add.py +0 -0
  359. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_bundle.py +0 -0
  360. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_init.py +0 -0
  361. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_legacy_generation_removal.py +0 -0
  362. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_lifecycle.py +0 -0
  363. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_merge.py +0 -0
  364. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_verify.py +0 -0
  365. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  366. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_win32_command_path.py +0 -0
  367. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_import_command.py +0 -0
  368. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_inbox_identity_provenance.py +0 -0
  369. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_init_command.py +0 -0
  370. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_init_provider_menu.py +0 -0
  371. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_install_codex_hooks.py +0 -0
  372. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_install_hook.py +0 -0
  373. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_install_multiplexer_command.py +0 -0
  374. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_install_postcompact_hook.py +0 -0
  375. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_install_wake_hook.py +0 -0
  376. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_lane_command.py +0 -0
  377. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_main.py +0 -0
  378. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_main_unknown_verb_guard.py +0 -0
  379. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mcp_missing_hint.py +0 -0
  380. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mcp_server.py +0 -0
  381. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_memory_command.py +0 -0
  382. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_memory_emit_snippet.py +0 -0
  383. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_memory_gateway.py +0 -0
  384. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_memory_sync.py +0 -0
  385. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_memory_sync_membrane.py +0 -0
  386. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_command.py +0 -0
  387. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_inbox_mark_read.py +0 -0
  388. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_inbox_sanitize.py +0 -0
  389. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_originate_thread_623.py +0 -0
  390. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_send_unknown_peer.py +0 -0
  391. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_sidecar.py +0 -0
  392. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  393. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_sidecar_muse_sink.py +0 -0
  394. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  395. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_meta_edge_identity.py +0 -0
  396. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_monitor_channel_poll.py +0 -0
  397. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_monitor_cli.py +0 -0
  398. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_monitor_daemon_collision.py +0 -0
  399. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_monitor_self_name_verification.py +0 -0
  400. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_monitor_state_split.py +0 -0
  401. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_multiplexer.py +0 -0
  402. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_muse_membrane.py +0 -0
  403. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_muse_own_cli.py +0 -0
  404. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_obligation_close_is_surfaced.py +0 -0
  405. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_okf_links.py +0 -0
  406. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_onboard_command.py +0 -0
  407. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_opencode_membrane.py +0 -0
  408. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_opencode_plugin.py +0 -0
  409. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_operator_me.py +0 -0
  410. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_orphan_daemons.py +0 -0
  411. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_packaged_artifacts_exist.py +0 -0
  412. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_packaged_skills.py +0 -0
  413. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_executor.py +0 -0
  414. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_executor_windows.py +0 -0
  415. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_reply_drain_command.py +0 -0
  416. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_reply_drain_supervisor.py +0 -0
  417. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_reply_outbox.py +0 -0
  418. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_reply_transport.py +0 -0
  419. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_service_e2e.py +0 -0
  420. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_service_host.py +0 -0
  421. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_service_payload.py +0 -0
  422. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_service_reply.py +0 -0
  423. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_postcompact_recall.py +0 -0
  424. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_process_liveness.py +0 -0
  425. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_protocol_handler.py +0 -0
  426. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_providers_isolation.py +0 -0
  427. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_ratify_command.py +0 -0
  428. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_readme_claims_no_gateway_default.py +0 -0
  429. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_repl_caller_convention.py +0 -0
  430. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_schedule_command.py +0 -0
  431. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_schedule_create_contract.py +0 -0
  432. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_security.py +0 -0
  433. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_service_app.py +0 -0
  434. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_service_command.py +0 -0
  435. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_service_providers.py +0 -0
  436. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_session_bridge_inject.py +0 -0
  437. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_session_bridge_probe.py +0 -0
  438. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_session_bridge_resolve.py +0 -0
  439. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_session_path_role_gate.py +0 -0
  440. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_shipped_units_match_the_cli.py +0 -0
  441. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_smoke_chat.py +0 -0
  442. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_smoke_one_shot.py +0 -0
  443. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_smoke_phase_5_5.py +0 -0
  444. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_base_hoist.py +0 -0
  445. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_command.py +0 -0
  446. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_identity_stamp.py +0 -0
  447. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_live_pin.py +0 -0
  448. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_mitosis_lineage.py +0 -0
  449. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_tmux_session.py +0 -0
  450. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_windows_relaunch.py +0 -0
  451. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_stall_alert.py +0 -0
  452. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_subprocess_decode_encoding.py +0 -0
  453. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_timeline_command.py +0 -0
  454. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_tmux_wake_runstate_defer.py +0 -0
  455. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_tmux_wake_session_reanchor.py +0 -0
  456. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_tmux_wake_stale.py +0 -0
  457. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_tmux_wake_submit_verify.py +0 -0
  458. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_token_file_one_parser.py +0 -0
  459. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_token_precedence_explicit_first.py +0 -0
  460. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_unified_token_resolver.py +0 -0
  461. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_version_command.py +0 -0
  462. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_version_consistency.py +0 -0
  463. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_vibe_membrane.py +0 -0
  464. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog.py +0 -0
  465. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_dm_wake.py +0 -0
  466. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  467. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  468. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_emit_health.py +0 -0
  469. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_install_flags.py +0 -0
  470. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_model_rung.py +0 -0
  471. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_stale_peers.py +0 -0
  472. {swarph_cli-0.72.0 → swarph_cli-0.72.2}/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.0
3
+ Version: 0.72.2
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
@@ -248,6 +248,8 @@ Task types: `numeric` (rel-err), `categorical` (exact), `ranking` (Kendall-tau),
248
248
 
249
249
  `claude-sonnet-5-5:subscription` runs `claude -p` on the Claude subscription when `claude` is on PATH. The argv is fixed: `--max-turns 1`, `--output-format stream-json`, `--strict-mcp-config`, an empty MCP config, `--tools ""`, `--setting-sources ""`. The prompt goes on stdin. The child environment drops `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, and every `SWARPH_CHANNEL*` name. A result whose `apiKeySource` is not `none` is `billing:<source>`, is not scored, and aborts the rest of the run on every arm. A usage limit is retried after 60s and then 300s; the arm then stops with `--ledger`, and the next run skips tasks that already completed. It is not scored as an answer.
250
250
 
251
+ `gpt-5.6-sol:codex` runs `codex exec` on the ChatGPT subscription when `codex` is on PATH. The argv is fixed: `--json`, `--ephemeral`, `--skip-git-repo-check`, `--ignore-user-config`, `--ignore-rules`, `--sandbox read-only`, in an empty temporary directory. `codex exec` has no system-prompt flag, so the pack's `system` goes on stdin ahead of the prompt. The child environment drops `OPENAI_API_KEY`, `CODEX_API_KEY`, and every `SWARPH_CHANNEL*` name. The billing guard runs **before** the call: the codex stream reports no key source, so the arm reads `auth_mode` from `$CODEX_HOME/auth.json` and refuses with `billing:<mode>` unless it is `chatgpt` (`billing:unknown` when the file cannot be read). Usage limits follow the claude arm: retried, then resumable with `--ledger`, never scored. The isolation flags drop the operator's MCP servers and plugins only. Measured on codex-cli 0.157.0 with a one-line prompt: 15,472 input tokens by default, 14,410 with the flags. The rest is the CLI's own agent instructions, so this arm's input tokens are not comparable with the claude arm's.
252
+
251
253
  ### `swarph brain-ask` (v0.14.0)
252
254
 
253
255
  Search the **swarph-brain** (gbrain) — the swarm's sovereign $0 semantic-retrieval memory — over MCP. The "does the swarm already know X?" reflex, as a one-shot.
@@ -199,6 +199,8 @@ Task types: `numeric` (rel-err), `categorical` (exact), `ranking` (Kendall-tau),
199
199
 
200
200
  `claude-sonnet-5-5:subscription` runs `claude -p` on the Claude subscription when `claude` is on PATH. The argv is fixed: `--max-turns 1`, `--output-format stream-json`, `--strict-mcp-config`, an empty MCP config, `--tools ""`, `--setting-sources ""`. The prompt goes on stdin. The child environment drops `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, and every `SWARPH_CHANNEL*` name. A result whose `apiKeySource` is not `none` is `billing:<source>`, is not scored, and aborts the rest of the run on every arm. A usage limit is retried after 60s and then 300s; the arm then stops with `--ledger`, and the next run skips tasks that already completed. It is not scored as an answer.
201
201
 
202
+ `gpt-5.6-sol:codex` runs `codex exec` on the ChatGPT subscription when `codex` is on PATH. The argv is fixed: `--json`, `--ephemeral`, `--skip-git-repo-check`, `--ignore-user-config`, `--ignore-rules`, `--sandbox read-only`, in an empty temporary directory. `codex exec` has no system-prompt flag, so the pack's `system` goes on stdin ahead of the prompt. The child environment drops `OPENAI_API_KEY`, `CODEX_API_KEY`, and every `SWARPH_CHANNEL*` name. The billing guard runs **before** the call: the codex stream reports no key source, so the arm reads `auth_mode` from `$CODEX_HOME/auth.json` and refuses with `billing:<mode>` unless it is `chatgpt` (`billing:unknown` when the file cannot be read). Usage limits follow the claude arm: retried, then resumable with `--ledger`, never scored. The isolation flags drop the operator's MCP servers and plugins only. Measured on codex-cli 0.157.0 with a one-line prompt: 15,472 input tokens by default, 14,410 with the flags. The rest is the CLI's own agent instructions, so this arm's input tokens are not comparable with the claude arm's.
203
+
202
204
  ### `swarph brain-ask` (v0.14.0)
203
205
 
204
206
  Search the **swarph-brain** (gbrain) — the swarm's sovereign $0 semantic-retrieval memory — over MCP. The "does the swarm already know X?" reflex, as a one-shot.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swarph-cli"
7
- version = "0.72.0"
7
+ version = "0.72.2"
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.0"
19
+ __version__ = "0.72.2"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -0,0 +1,127 @@
1
+ """codex exec transport for the bench `codex` backend. Subscription-only, isolated,
2
+ billing-guarded. Sibling of :mod:`swarph_cli.bench.claude_cli`, and it differs from it
3
+ in three places that matter.
4
+
5
+ Measured 2026-10-02, codex-cli 0.157.0, macOS arm64, a one-line prompt:
6
+ default config 15,472 input tokens
7
+ --ignore-user-config --ignore-rules 14,410 input tokens
8
+ The isolation flags remove the operator's MCP servers and plugins, and that is all
9
+ they remove. The floor is the CLI's own agent instructions: there is no flag here that
10
+ turns `codex exec` into a bare completion, so this arm does not reach the ~421 tokens
11
+ `claude -p --tools ""` does. Compare arms on quality and on OUTPUT tokens; the input
12
+ count carries this fixed load.
13
+
14
+ THE BILLING GUARD IS CHECKED BEFORE THE CALL, NOT READ FROM THE RESULT. The claude
15
+ stream names its key source (`apiKeySource`). The codex stream names nothing about
16
+ billing, so the guard reads `auth_mode` from `$CODEX_HOME/auth.json` and refuses to
17
+ call unless it is `chatgpt`. A file that cannot be read is `billing:unknown`: not
18
+ knowing is a refusal, never a pass.
19
+
20
+ NO SYSTEM-PROMPT FLAG. `codex exec` has none, so the pack's `system` is sent on stdin
21
+ ahead of the prompt, separated by a blank line.
22
+
23
+ The child runs in an empty temporary directory under a read-only sandbox, so there is
24
+ no repository for the agent to read and nothing it can write.
25
+ """
26
+ from __future__ import annotations
27
+
28
+ import json
29
+ import os
30
+ import subprocess
31
+ import tempfile
32
+ from pathlib import Path
33
+ from typing import Optional
34
+
35
+ from swarph_cli.bench.claude_cli import CliResult
36
+
37
+ _STRIP_EXACT = ("OPENAI_API_KEY", "CODEX_API_KEY")
38
+ _RATE = ("usage limit", "rate limit", "429", "too many requests")
39
+ _SUBSCRIPTION_MODE = "chatgpt"
40
+
41
+
42
+ def build_argv(model_id: str) -> list:
43
+ """Fixed argv. The trailing `-` reads the prompt from stdin, never from argv."""
44
+ return ["codex", "exec", "--model", model_id, "--json", "--ephemeral",
45
+ "--skip-git-repo-check", "--ignore-user-config", "--ignore-rules",
46
+ "--sandbox", "read-only", "-"]
47
+
48
+
49
+ def clean_env(env: dict) -> dict:
50
+ """Drop billing keys and every SWARPH_CHANNEL* name, including ones not listed yet."""
51
+ return {
52
+ k: v for k, v in env.items()
53
+ if k not in _STRIP_EXACT and not k.startswith("SWARPH_CHANNEL")
54
+ }
55
+
56
+
57
+ def codex_home(env: dict) -> Path:
58
+ return Path(env.get("CODEX_HOME") or (Path.home() / ".codex"))
59
+
60
+
61
+ def auth_mode(home: Path) -> Optional[str]:
62
+ """`auth_mode` from auth.json, or None when it cannot be read. None is not a pass."""
63
+ try:
64
+ data = json.loads((home / "auth.json").read_text(encoding="utf-8"))
65
+ except (OSError, ValueError):
66
+ return None
67
+ mode = data.get("auth_mode") if isinstance(data, dict) else None
68
+ return mode if isinstance(mode, str) and mode else None
69
+
70
+
71
+ def stdin_text(prompt: str, system: str) -> str:
72
+ return f"{system}\n\n{prompt}" if system else prompt
73
+
74
+
75
+ def _is_rate(text: str) -> bool:
76
+ low = (text or "").lower()
77
+ return any(t in low for t in _RATE)
78
+
79
+
80
+ def parse_stream(lines, stderr: str = "", key: Optional[str] = _SUBSCRIPTION_MODE) -> CliResult:
81
+ """JSONL from `codex exec --json` -> CliResult.
82
+
83
+ The answer is the LAST agent_message. Usage is the LAST turn.completed: that event
84
+ carries the thread's running total, so adding two of them would double-count.
85
+ A usage limit is `rate_limit` whether it arrives as an event or on stderr — the
86
+ runner retries that string and never scores it as an answer.
87
+ """
88
+ text, usage, failure = None, None, None
89
+ for ln in lines:
90
+ try:
91
+ e = json.loads(ln)
92
+ except Exception:
93
+ continue
94
+ if not isinstance(e, dict):
95
+ continue
96
+ kind = e.get("type")
97
+ if kind == "item.completed":
98
+ item = e.get("item") or {}
99
+ if item.get("type") == "agent_message" and isinstance(item.get("text"), str):
100
+ text = item["text"]
101
+ elif kind == "turn.completed":
102
+ usage = e.get("usage") or {}
103
+ elif kind in ("error", "turn.failed"):
104
+ detail = e.get("message") or e.get("error") or ""
105
+ failure = (kind, detail if isinstance(detail, str) else json.dumps(detail))
106
+ u = usage or {}
107
+ tin, tout = int(u.get("input_tokens") or 0), int(u.get("output_tokens") or 0)
108
+ if failure is not None:
109
+ err = "rate_limit" if _is_rate(failure[1]) or _is_rate(stderr) else f"cli_error:{failure[0]}"
110
+ return CliResult("", tin, tout, key, None, error=err)
111
+ if text is None or usage is None:
112
+ err = "rate_limit" if _is_rate(stderr) else "no_result"
113
+ return CliResult("", tin, tout, key, None, error=err)
114
+ return CliResult(text, tin, tout, key, None)
115
+
116
+
117
+ def call(model_id: str, prompt: str, system: str, *, runner=subprocess.run,
118
+ timeout: int = 300, env: Optional[dict] = None) -> CliResult:
119
+ source = dict(os.environ) if env is None else dict(env)
120
+ mode = auth_mode(codex_home(source))
121
+ if mode != _SUBSCRIPTION_MODE:
122
+ # Refused before any call: nothing was spent, and nothing is scored.
123
+ return CliResult("", 0, 0, mode, None, error=f"billing:{mode or 'unknown'}")
124
+ with tempfile.TemporaryDirectory(prefix="swarph-bench-codex-") as cwd:
125
+ p = runner(build_argv(model_id), input=stdin_text(prompt, system), capture_output=True,
126
+ text=True, env=clean_env(source), timeout=timeout, cwd=cwd)
127
+ return parse_stream((p.stdout or "").splitlines(), p.stderr or "", key=mode)
@@ -61,10 +61,17 @@ def _default_backends() -> dict[str, Backend]:
61
61
  if shutil.which("claude"):
62
62
  from swarph_cli.bench.claude_cli import call as claude_call
63
63
  subscription = SubscriptionBackend(call_fn=claude_call)
64
+ # codex on PATH wires its own lane to an isolated `codex exec`. Its own key,
65
+ # like mistral: `id:subscription` keeps meaning claude.
66
+ codex = SubscriptionBackend()
67
+ if shutil.which("codex"):
68
+ from swarph_cli.bench.codex_cli import call as codex_call
69
+ codex = SubscriptionBackend(call_fn=codex_call)
64
70
  return {
65
71
  "metered": MeteredGeminiBackend(),
66
72
  "mistral": MeteredMistralBackend(),
67
73
  "subscription": subscription,
74
+ "codex": codex,
68
75
  "rule": RuleBackend(),
69
76
  "signal": SignalBackend(),
70
77
  "typed-http": TypedHttpBackend(),
@@ -2302,6 +2302,9 @@ _OPENCODE_WAKE_PROMPT = "check mesh: swarph_dm_unread"
2302
2302
  # Grok's TUI has the same shape (#715, grok 1.0.41): no push channel, so
2303
2303
  # the wake is one line naming the pull tool and no DM body.
2304
2304
  _GROK_WAKE_PROMPT = "check mesh: swarph_dm_unread"
2305
+ # Muse 1.4.1 has no push channel either. The wake names the pull tool,
2306
+ # same text the grok and opencode sinks inject.
2307
+ _MUSE_WAKE_PROMPT = "check mesh: swarph_dm_unread"
2305
2308
  # A finished turn keeps its ▣ header and adds a duration.
2306
2309
  # Short turns read `· 3.3s` (drop-on-meta-edge, 1.18.33, card #961 post
2307
2310
  # 54557). A longer idle turn reads `· 3m 4s` (opencode pane, 2026-09-29
@@ -2439,7 +2442,7 @@ def _only_wake_text(content: str) -> bool:
2439
2442
  human's line.
2440
2443
  """
2441
2444
  rest = content
2442
- for prompt in (_GROK_WAKE_PROMPT, _OPENCODE_WAKE_PROMPT, _WAKE_PROMPT):
2445
+ for prompt in (_MUSE_WAKE_PROMPT, _GROK_WAKE_PROMPT, _OPENCODE_WAKE_PROMPT, _WAKE_PROMPT):
2443
2446
  rest = rest.replace(prompt, "")
2444
2447
  return rest.strip() == ""
2445
2448
 
@@ -2611,8 +2614,13 @@ def _is_muse_rule(line: str) -> bool:
2611
2614
 
2612
2615
 
2613
2616
  def _is_muse_status(line: str) -> bool:
2614
- """The status under the lower rule. Measured: ``muse-spark-… · … · YOLO``."""
2615
- return "muse-spark" in line and "·" in line
2617
+ """A status row under the lower rule.
2618
+
2619
+ Measured muse-spark is ``model · effort · path · YOLO``. An echo
2620
+ provider is ``echo · ~/x · YOLO``. The anchor is two or more `` · ``
2621
+ separators, not the model name. A model switch must not blind the sink.
2622
+ """
2623
+ return line.count(" · ") >= 2
2616
2624
 
2617
2625
 
2618
2626
  def _is_muse_composer_row(lines: list[str], index: int) -> bool:
@@ -2853,6 +2861,8 @@ def _wake_prompt_for(lines: Optional[list[str]]) -> str:
2853
2861
  return _GROK_WAKE_PROMPT
2854
2862
  if lines and _is_opencode_pane(lines):
2855
2863
  return _OPENCODE_WAKE_PROMPT
2864
+ if lines and _is_muse_pane(lines):
2865
+ return _MUSE_WAKE_PROMPT
2856
2866
  return _WAKE_PROMPT
2857
2867
 
2858
2868
 
@@ -393,14 +393,21 @@ _CLAUDE_CHANNELS = frozenset({"allowlisted", "dev"})
393
393
  _MUSE_CHANNELS = frozenset({"ingress"})
394
394
 
395
395
 
396
- def _resolve_channel(cell: Cell) -> str:
397
- """Effective channel mode: $SWARPH_CHANNEL wins (incl. "off"), else the
398
- cell.yaml `channel` field (kept by swarph-shared in the forward-compat
399
- `extra` bag), else "" (absent). Never launches anything; callers validate.
400
- """
401
- env_mode = os.environ.get("SWARPH_CHANNEL") or ""
402
- if env_mode:
403
- return env_mode
396
+ # Providers whose spawn consumes $SWARPH_CHANNEL. Anything else ignores an
397
+ # inherited value (a Claude cell's shell carries allowlisted; spawning grok
398
+ # from it must not refuse). Measured 2026-10-01: 0.72.0 blamed cell.yaml
399
+ # for that env and exited on grok-researcher.yaml, which has no channel field.
400
+ _ENV_CHANNEL_PROVIDERS = frozenset({"claude", "muse"})
401
+
402
+
403
+ def _channel_where(source: str) -> str:
404
+ """Name the place the mode came from. An env value must not read as cell.yaml."""
405
+ if source == "env":
406
+ return "SWARPH_CHANNEL"
407
+ return "cell.yaml: 'channel'"
408
+
409
+
410
+ def _field_channel(cell: Cell) -> str:
404
411
  extra = getattr(cell, "extra", None) or {}
405
412
  value = extra.get("channel", "") if isinstance(extra, dict) else ""
406
413
  if value is None:
@@ -413,64 +420,88 @@ def _resolve_channel(cell: Cell) -> str:
413
420
  return value
414
421
 
415
422
 
416
- def _channel_marketplace_dir() -> Path:
423
+ def _resolve_channel(cell: Cell) -> tuple[str, str]:
424
+ """Effective channel mode and where it came from.
425
+
426
+ ``$SWARPH_CHANNEL`` wins (incl. "off") only for providers that support
427
+ it: claude (allowlisted/dev/off) and muse (ingress/off). Other providers
428
+ ignore the inherited env, as before 0.72.0, and the cell.yaml field is
429
+ still read. Returns ``(mode, source)`` with source ``env``, ``cell.yaml``,
430
+ or ``""``. Never launches anything; callers validate.
431
+ """
432
+ env_mode = os.environ.get("SWARPH_CHANNEL") or ""
433
+ provider = getattr(cell, "provider", None)
434
+ # No provider attribute: the stamp probes construct a name-only cell.
435
+ # Those are claude-shaped; the env still applies.
436
+ if env_mode and (provider is None or provider in _ENV_CHANNEL_PROVIDERS):
437
+ return env_mode, "env"
438
+ field = _field_channel(cell)
439
+ return field, ("cell.yaml" if field else "")
440
+
441
+
442
+ def _channel_marketplace_dir(source: str = "cell.yaml") -> Path:
417
443
  """Install location of the `swarph` Claude marketplace (the allowlist).
418
444
 
419
445
  Resolved through ~/.claude/plugins/known_marketplaces.json, the same
420
446
  registry claude reads — never a second hardcoded copy that drifts.
447
+ ``source`` names env vs cell.yaml so a missing registry is not blamed
448
+ on the file when the mode came from ``$SWARPH_CHANNEL``.
421
449
  """
450
+ where = _channel_where(source)
422
451
  registry = Path.home() / ".claude" / "plugins" / "known_marketplaces.json"
423
452
  try:
424
453
  data = json.loads(registry.read_text(encoding="utf-8"))
425
454
  except (OSError, ValueError) as exc:
426
455
  raise CellError(
427
- f"cell.yaml: channel 'allowlisted' needs the swarph marketplace, "
456
+ f"{where} 'allowlisted' needs the swarph marketplace, "
428
457
  f"but its registry is unreadable: {registry} ({exc})."
429
458
  ) from exc
430
459
  try:
431
460
  location = data["swarph"]["installLocation"]
432
461
  except (KeyError, TypeError) as exc:
433
462
  raise CellError(
434
- f"cell.yaml: channel 'allowlisted' needs the swarph marketplace, "
463
+ f"{where} 'allowlisted' needs the swarph marketplace, "
435
464
  f"but it is not registered in {registry}."
436
465
  ) from exc
437
466
  path = Path(location)
438
467
  if not path.is_dir():
439
468
  raise CellError(
440
- f"cell.yaml: channel 'allowlisted' needs the swarph marketplace "
469
+ f"{where} 'allowlisted' needs the swarph marketplace "
441
470
  f"at {path}, which is not a directory."
442
471
  )
443
472
  return path
444
473
 
445
474
 
446
- def _validate_channel(cell: Cell, mode: str) -> str:
475
+ def _validate_channel(cell: Cell, mode: str, source: str = "cell.yaml") -> str:
447
476
  """Fail closed on any channel mode the provider cannot consume.
448
477
 
449
478
  Returns the mode unchanged. "" and "off" are valid everywhere (no-op).
450
- Raises CellError naming the field (and the file, for a missing
451
- marketplace) so the operator fixes config, never debugs a deaf cell.
479
+ Raises CellError naming the source (``SWARPH_CHANNEL`` or the cell.yaml
480
+ field) and the file, for a missing marketplace, so the operator fixes
481
+ config, never debugs a deaf cell.
452
482
  """
453
483
  if mode in ("", "off"):
454
484
  return mode
485
+ where = _channel_where(source)
455
486
  provider = cell.provider
456
487
  if provider == "claude":
457
488
  if mode not in _CLAUDE_CHANNELS:
458
489
  raise CellError(
459
- f"cell.yaml: 'channel' {mode!r} is not valid for provider "
490
+ f"{where} {mode!r} is not valid for provider "
460
491
  f"'claude'. Valid values: {sorted(_CLAUDE_CHANNELS | {'off'})}."
461
492
  )
462
493
  if mode == "allowlisted":
463
- _channel_marketplace_dir()
494
+ _channel_marketplace_dir(source)
464
495
  return mode
465
496
  if provider == "muse":
466
497
  if mode not in _MUSE_CHANNELS:
467
498
  raise CellError(
468
- f"cell.yaml: 'channel' {mode!r} is not valid for provider "
499
+ f"{where} {mode!r} is not valid for provider "
469
500
  f"'muse'. Valid values: {sorted(_MUSE_CHANNELS | {'off'})}."
470
501
  )
471
502
  return mode
472
503
  raise CellError(
473
- f"cell.yaml: 'channel' {mode!r} is only valid for providers "
504
+ f"{where} {mode!r} is only valid for providers "
474
505
  f"'claude' and 'muse'; provider is {provider!r}."
475
506
  )
476
507
 
@@ -498,7 +529,8 @@ def _build_claude_argv(
498
529
  argv.extend(["--append-system-prompt", starter])
499
530
 
500
531
  argv.extend(passthrough)
501
- mode = _validate_channel(cell, _resolve_channel(cell))
532
+ mode, source = _resolve_channel(cell)
533
+ mode = _validate_channel(cell, mode, source)
502
534
  if mode == "allowlisted":
503
535
  argv.extend(["--channels", "plugin:swarph@swarph"])
504
536
  elif mode == "dev":
@@ -545,7 +577,7 @@ def _spawn_env_base(cell: Cell) -> dict[str, str]:
545
577
  env = scrub_env_for_subprocess()
546
578
  env["SWARPH_SPAWN"] = "1"
547
579
  env["SWARPH_SELF"] = cell.name
548
- mode = _resolve_channel(cell)
580
+ mode, _source = _resolve_channel(cell)
549
581
  # NOTE: the marketplace/validity gate lives in _validate_channel, which
550
582
  # _build_claude_argv (and the muse env builder) run. This base stays a
551
583
  # pure reflection of the resolved mode so every provider's env agrees.
@@ -587,7 +619,8 @@ def _muse_env(cell: Cell) -> dict[str, str]:
587
619
  run_spawn choke point; the mode read here agrees with it by construction.
588
620
  """
589
621
  env = _claude_env(cell)
590
- if _resolve_channel(cell) == "ingress":
622
+ mode, _source = _resolve_channel(cell)
623
+ if mode == "ingress":
591
624
  env["MUSE_EXPERIMENTAL_EXTERNAL_AGENT_INGRESS"] = "on"
592
625
  return env
593
626
 
@@ -3308,7 +3341,8 @@ def run_spawn(argv: Optional[list[str]] = None) -> int:
3308
3341
  # must not leave a minted sidecar behind). One choke point for every
3309
3342
  # provider; builders below see only validated modes.
3310
3343
  try:
3311
- _validate_channel(cell, _resolve_channel(cell))
3344
+ mode, source = _resolve_channel(cell)
3345
+ _validate_channel(cell, mode, source)
3312
3346
  except CellError as exc:
3313
3347
  print(f"swarph spawn: {exc}", file=sys.stderr)
3314
3348
  return 1
@@ -10,6 +10,11 @@ distinction is not WHICH harness, it is WHERE THE WAKE LIVES):
10
10
  * ``claude`` / ``codex`` → ARM-INSTRUCTION. The wake lives in the harness:
11
11
  emit the watch pipeline (tail -F inbox.log | dm_notify_filter) as
12
12
  additionalContext so the agent arms it as a background watch.
13
+ * ``grok`` → the same arm instruction, with the pipeline wrapped in
14
+ ``timeout -k 5s 590m`` and one ``[MESH WAKE EXPIRED]`` line. Grok caps a
15
+ background task at 10h (measured 2026-10-01); the wrapper exits 10
16
+ minutes early so the stop is a wake, not a SIGKILL the session never
17
+ sees. The duration is one unit: coreutils timeout rejects ``9h50m``.
13
18
  * ``cursor`` → ARM-INSTRUCTION, same pipeline as claude/codex, emitted in
14
19
  Cursor's ``additional_context`` envelope (the ``~/.cursor/hooks.json``
15
20
  sessionStart shape). The wake is the session-armed tail. A missing or
@@ -43,7 +48,7 @@ from swarph_cli.cell import (
43
48
  load_cell,
44
49
  )
45
50
 
46
- _ARM_HARNESSES = ("claude", "codex", "muse", "opencode")
51
+ _ARM_HARNESSES = ("claude", "codex", "muse", "opencode", "grok")
47
52
  _INJECT_HARNESSES = ("antigravity",)
48
53
  _VERIFY_HARNESSES = ("cursor",)
49
54
  _KNOWN_HARNESSES = _ARM_HARNESSES + _INJECT_HARNESSES + _VERIFY_HARNESSES
@@ -52,6 +57,12 @@ _KNOWN_HARNESSES = _ARM_HARNESSES + _INJECT_HARNESSES + _VERIFY_HARNESSES
52
57
  _FILTER_MODULE = "swarph_cli.scripts.dm_notify_filter"
53
58
  # Same default as `swarph monitor arm-check --max-age-s` (15 minutes).
54
59
  _INBOX_MAX_AGE_S = 15 * 60
60
+ _EXPIRED_LINE = "[MESH WAKE EXPIRED] re-arm the inbox tail now"
61
+ # Harnesses whose background tasks die at a cap. The wrapper is that cap
62
+ # minus 10 minutes, as one unit coreutils timeout accepts. Grok's cap is
63
+ # 10h (grok-researcher, 2026-10-01); "9h50m" is rejected as an invalid
64
+ # time interval on this box.
65
+ _HARNESS_TIMEOUT = {"grok": "590m"}
55
66
 
56
67
 
57
68
  def _read_stdin_payload() -> dict[str, Any]:
@@ -233,7 +244,27 @@ def _provenance_note(source: str) -> str:
233
244
  return f" (identity from {source})"
234
245
 
235
246
 
236
- def _arm_instruction(cell_name: Optional[str], source: str = "unresolved") -> str:
247
+ def _watch_pipeline(inbox: Path, interpreter: str) -> str:
248
+ return f'tail -n 0 -F "{inbox}" | "{interpreter}" -u -m {_FILTER_MODULE}'
249
+
250
+
251
+ def _loud_stop(pipeline: str, duration: str) -> str:
252
+ """Self-expire before the harness kills the task, then say so.
253
+
254
+ ``-k 5s`` sends KILL if the tail is still up after TERM. A single-quoted
255
+ ``sh -c`` matches the pipeline, which quotes paths with double quotes.
256
+ """
257
+ return (
258
+ f"timeout -k 5s {duration} sh -c '{pipeline}'; "
259
+ f"echo '{_EXPIRED_LINE}'"
260
+ )
261
+
262
+
263
+ def _arm_instruction(
264
+ cell_name: Optional[str],
265
+ source: str = "unresolved",
266
+ harness: str = "",
267
+ ) -> str:
237
268
  interpreter = sys.executable
238
269
  if not cell_name:
239
270
  # CANNOT-RESOLVE is a LOUD REFUSAL, never a placeholder (card #527
@@ -259,8 +290,10 @@ def _arm_instruction(cell_name: Optional[str], source: str = "unresolved") -> st
259
290
  f'"{interpreter}" -m swarph_cli monitor arm-check '
260
291
  f'--as {cell_name} --path "{inbox}"'
261
292
  )
262
- tail = f'tail -n 0 -F "{inbox}"'
263
- pipeline = f'{tail} | "{interpreter}" -u -m {_FILTER_MODULE}'
293
+ pipeline = _watch_pipeline(inbox, interpreter)
294
+ cap = _HARNESS_TIMEOUT.get(harness)
295
+ if cap:
296
+ pipeline = _loud_stop(pipeline, cap)
264
297
  return (
265
298
  "[swarph silent-wake] This cell's DM wake lives in THIS harness. "
266
299
  "BEFORE arming, refuse a missing/stale inbox.log (#729):\n"
@@ -490,7 +523,8 @@ def run_wake_hook_output(argv: Optional[list[str]] = None) -> int:
490
523
  )
491
524
  if harness in _ARM_HARNESSES:
492
525
  return _emit(
493
- {"context": _arm_instruction(cell_name, cell_source)}, harness=harness
526
+ {"context": _arm_instruction(cell_name, cell_source, harness)},
527
+ harness=harness,
494
528
  )
495
529
  return _emit(
496
530
  {"context": _verify_report(cell_name, cell_source)}, harness=harness
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swarph-cli
3
- Version: 0.72.0
3
+ Version: 0.72.2
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
@@ -248,6 +248,8 @@ Task types: `numeric` (rel-err), `categorical` (exact), `ranking` (Kendall-tau),
248
248
 
249
249
  `claude-sonnet-5-5:subscription` runs `claude -p` on the Claude subscription when `claude` is on PATH. The argv is fixed: `--max-turns 1`, `--output-format stream-json`, `--strict-mcp-config`, an empty MCP config, `--tools ""`, `--setting-sources ""`. The prompt goes on stdin. The child environment drops `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, and every `SWARPH_CHANNEL*` name. A result whose `apiKeySource` is not `none` is `billing:<source>`, is not scored, and aborts the rest of the run on every arm. A usage limit is retried after 60s and then 300s; the arm then stops with `--ledger`, and the next run skips tasks that already completed. It is not scored as an answer.
250
250
 
251
+ `gpt-5.6-sol:codex` runs `codex exec` on the ChatGPT subscription when `codex` is on PATH. The argv is fixed: `--json`, `--ephemeral`, `--skip-git-repo-check`, `--ignore-user-config`, `--ignore-rules`, `--sandbox read-only`, in an empty temporary directory. `codex exec` has no system-prompt flag, so the pack's `system` goes on stdin ahead of the prompt. The child environment drops `OPENAI_API_KEY`, `CODEX_API_KEY`, and every `SWARPH_CHANNEL*` name. The billing guard runs **before** the call: the codex stream reports no key source, so the arm reads `auth_mode` from `$CODEX_HOME/auth.json` and refuses with `billing:<mode>` unless it is `chatgpt` (`billing:unknown` when the file cannot be read). Usage limits follow the claude arm: retried, then resumable with `--ledger`, never scored. The isolation flags drop the operator's MCP servers and plugins only. Measured on codex-cli 0.157.0 with a one-line prompt: 15,472 input tokens by default, 14,410 with the flags. The rest is the CLI's own agent instructions, so this arm's input tokens are not comparable with the claude arm's.
252
+
251
253
  ### `swarph brain-ask` (v0.14.0)
252
254
 
253
255
  Search the **swarph-brain** (gbrain) — the swarm's sovereign $0 semantic-retrieval memory — over MCP. The "does the swarm already know X?" reflex, as a one-shot.
@@ -40,6 +40,7 @@ src/swarph_cli.egg-info/top_level.txt
40
40
  src/swarph_cli/bench/__init__.py
41
41
  src/swarph_cli/bench/backends.py
42
42
  src/swarph_cli/bench/claude_cli.py
43
+ src/swarph_cli/bench/codex_cli.py
43
44
  src/swarph_cli/bench/pack.py
44
45
  src/swarph_cli/bench/prices.py
45
46
  src/swarph_cli/bench/providers.py
@@ -270,6 +271,7 @@ tests/test_959_venv_interpreter.py
270
271
  tests/test_960_channel.py
271
272
  tests/test_960_ensure_monitor_heartbeat.py
272
273
  tests/test_961_cursor_grok_footer.py
274
+ tests/test_961_loud_stop.py
273
275
  tests/test_963_plugin_manifest.py
274
276
  tests/test_964_channel_cell.py
275
277
  tests/test_965_mesh_wait.py
@@ -284,6 +286,7 @@ tests/test_artifact_tool.py
284
286
  tests/test_artifact_uri.py
285
287
  tests/test_bench_backends.py
286
288
  tests/test_bench_claude_cli.py
289
+ tests/test_bench_codex_cli.py
287
290
  tests/test_bench_command.py
288
291
  tests/test_bench_pack.py
289
292
  tests/test_bench_prices.py
@@ -309,3 +309,40 @@ def test_live_entry_drops_a_closed_row_and_a_failed_read_sends_nothing(tmp_path,
309
309
  assert all(argv[:3] != ["swarph", "mesh", "send"] for argv in calls)
310
310
  assert all("inbox" not in argv for argv in calls)
311
311
  assert not hasattr(pub, "commander_replies")
312
+
313
+
314
+ def test_in_session_marker_sets_the_flag_and_strips_the_title():
315
+ """An accept starting [commander][in-session] Re-login... builds
316
+ in_session=true and a title without the marker. A plain [commander]
317
+ row with no deploy or hard-gate words stays false. On main the title
318
+ keeps [in-session] and the flag stays false.
319
+ """
320
+ pub = _load()
321
+ listing = (ROOT / "tests" / "fixtures" / "session-board" / "listagents-lab.txt").read_text(encoding="utf-8")
322
+ rows = pub.commander_rows([
323
+ {
324
+ "id": 5,
325
+ "holder": "droplet",
326
+ "card_id": 1006,
327
+ "state": "open",
328
+ "accept": "[commander][in-session] Re-login to the board | PASS=the commander re-logs",
329
+ },
330
+ {
331
+ "id": 6,
332
+ "holder": "droplet",
333
+ "card_id": 1006,
334
+ "state": "open",
335
+ "accept": "[commander] Note the weather today | PASS=nothing",
336
+ },
337
+ ])
338
+ board = pub.build_board.build(listing, rows)
339
+ questions = [
340
+ q for sess in board["sessions"] if sess["name"] == "droplet" for q in sess["questions"]
341
+ ]
342
+ marked = next(q for q in questions if q["obligation"] == 5)
343
+ plain = next(q for q in questions if q["obligation"] == 6)
344
+ assert marked["in_session"] is True
345
+ assert marked["title"] == "Re-login to the board"
346
+ assert "[in-session]" not in marked["title"]
347
+ assert "[commander]" not in marked["title"]
348
+ assert plain["in_session"] is False