swarph-cli 0.72.8__tar.gz → 0.72.9__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 (481) hide show
  1. {swarph_cli-0.72.8/src/swarph_cli.egg-info → swarph_cli-0.72.9}/PKG-INFO +1 -1
  2. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/pyproject.toml +1 -1
  3. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/__init__.py +1 -1
  4. swarph_cli-0.72.9/src/swarph_cli/commands/roster.py +237 -0
  5. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/guide/GUIDE.md +1 -0
  6. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/main.py +1 -0
  7. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/rowclear.py +65 -4
  8. {swarph_cli-0.72.8 → swarph_cli-0.72.9/src/swarph_cli.egg-info}/PKG-INFO +1 -1
  9. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli.egg-info/SOURCES.txt +2 -0
  10. swarph_cli-0.72.9/tests/test_1061_roster_cli.py +137 -0
  11. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_432_rowclear.py +165 -0
  12. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_sidecar.py +40 -0
  13. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/LICENSE +0 -0
  14. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/README.md +0 -0
  15. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/setup.cfg +0 -0
  16. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/__main__.py +0 -0
  17. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/__init__.py +0 -0
  18. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/backends.py +0 -0
  19. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/claude_cli.py +0 -0
  20. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/codex_cli.py +0 -0
  21. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/pack.py +0 -0
  22. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/prices.py +0 -0
  23. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/providers.py +0 -0
  24. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/quality.py +0 -0
  25. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/refresh_prices.py +0 -0
  26. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/rules.py +0 -0
  27. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/runner.py +0 -0
  28. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/signal_score.py +0 -0
  29. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/validate.py +0 -0
  30. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/caller.py +0 -0
  31. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/__init__.py +0 -0
  32. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/harden.py +0 -0
  33. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/lineage.py +0 -0
  34. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/liveness.py +0 -0
  35. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/manifest.py +0 -0
  36. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/paths.py +0 -0
  37. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/verify.py +0 -0
  38. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/cell.py +0 -0
  39. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/chain_token.py +0 -0
  40. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/channel.py +0 -0
  41. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/__init__.py +0 -0
  42. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/_content.py +0 -0
  43. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/_display.py +0 -0
  44. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/_gateway_client.py +0 -0
  45. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/add.py +0 -0
  46. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/bench.py +0 -0
  47. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/board.py +0 -0
  48. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/board_merge_check.py +0 -0
  49. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/brain.py +0 -0
  50. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/brain_ask.py +0 -0
  51. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/cell.py +0 -0
  52. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/cell_probe.py +0 -0
  53. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  54. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/channel.py +0 -0
  55. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/chat.py +0 -0
  56. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/codegraph.py +0 -0
  57. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/codegraph_hook.py +0 -0
  58. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  59. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/codex_waker.py +0 -0
  60. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/compress.py +0 -0
  61. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/daemon.py +0 -0
  62. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/dreaming.py +0 -0
  63. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/event.py +0 -0
  64. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/gateway.py +0 -0
  65. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/gh_route.py +0 -0
  66. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/group.py +0 -0
  67. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/guide.py +0 -0
  68. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/highlight.py +0 -0
  69. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/hook_interpreter.py +0 -0
  70. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/hook_output.py +0 -0
  71. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/hooks.py +0 -0
  72. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/import_session.py +0 -0
  73. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/init.py +0 -0
  74. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  75. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_hook.py +0 -0
  76. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  77. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
  78. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
  79. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  80. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/lane.py +0 -0
  81. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/mcp_server.py +0 -0
  82. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/memory.py +0 -0
  83. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
  84. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/memory_sync.py +0 -0
  85. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/mesh.py +0 -0
  86. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/monitor.py +0 -0
  87. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/okf_links.py +0 -0
  88. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/onboard.py +0 -0
  89. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  90. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  91. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/protocol_handler.py +0 -0
  92. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/ratify.py +0 -0
  93. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/rowclear_hook.py +0 -0
  94. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/schedule.py +0 -0
  95. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/security.py +0 -0
  96. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/service.py +0 -0
  97. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/spawn.py +0 -0
  98. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/timeline.py +0 -0
  99. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/version.py +0 -0
  100. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/wake_hook_output.py +0 -0
  101. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/watchdog.py +0 -0
  102. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/compress/__init__.py +0 -0
  103. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/compress/levers.py +0 -0
  104. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/compress/marker.py +0 -0
  105. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/compress/verify.py +0 -0
  106. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/console_safe.py +0 -0
  107. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/delivery_queue.py +0 -0
  108. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dm_frame.py +0 -0
  109. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/__init__.py +0 -0
  110. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/candidates.py +0 -0
  111. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/clone.py +0 -0
  112. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/enrich.py +0 -0
  113. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/index_check.py +0 -0
  114. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/notify.py +0 -0
  115. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/organize.py +0 -0
  116. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/probes.py +0 -0
  117. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/report.py +0 -0
  118. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/run.py +0 -0
  119. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/slm.py +0 -0
  120. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/transcripts.py +0 -0
  121. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/verify.py +0 -0
  122. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/__init__.py +0 -0
  123. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/feature_registry.py +0 -0
  124. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/lanes_control.py +0 -0
  125. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/schema.sql +0 -0
  126. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/server.py +0 -0
  127. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/services_control.py +0 -0
  128. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway_default.py +0 -0
  129. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gh_identity.py +0 -0
  130. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/identity.py +0 -0
  131. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/multiplexer.py +0 -0
  132. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/__init__.py +0 -0
  133. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/__main__.py +0 -0
  134. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/api.py +0 -0
  135. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/cli.py +0 -0
  136. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/config.py +0 -0
  137. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/fmt.py +0 -0
  138. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/orphan_daemons.py +0 -0
  139. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/pane_probe.py +0 -0
  140. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/parsers/__init__.py +0 -0
  141. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/parsers/claude.py +0 -0
  142. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
  143. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  144. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  145. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  146. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  147. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  148. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  149. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  150. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  151. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  152. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  153. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  154. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_executor.py +0 -0
  155. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_executor_windows.py +0 -0
  156. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_reconciliation.py +0 -0
  157. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_reply_outbox.py +0 -0
  158. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_service_host.py +0 -0
  159. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_service_payload.py +0 -0
  160. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_service_reply.py +0 -0
  161. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_staging.py +0 -0
  162. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/query_filters.py +0 -0
  163. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/__init__.py +0 -0
  164. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  165. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  166. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  167. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  168. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
  169. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/service/__init__.py +0 -0
  170. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/service/app.py +0 -0
  171. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/service/providers.py +0 -0
  172. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/session_bridge.py +0 -0
  173. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  174. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  175. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/source_text.py +0 -0
  176. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/stall_alert.py +0 -0
  177. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/codex-waker.default +0 -0
  178. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  179. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  180. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  181. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  182. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  183. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
  184. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
  185. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  186. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  187. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  188. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  189. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  190. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  191. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/timeline_paths.py +0 -0
  192. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/tokens.py +0 -0
  193. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  194. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  195. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli.egg-info/requires.txt +0 -0
  196. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli.egg-info/top_level.txt +0 -0
  197. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1006_board_publisher.py +0 -0
  198. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1006_session_board.py +0 -0
  199. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1010_strand_only.py +0 -0
  200. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1013_spawn_channel.py +0 -0
  201. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1017_muse_tui.py +0 -0
  202. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1050_surrogate_wake.py +0 -0
  203. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1052_opencode_deaf.py +0 -0
  204. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1059_watchdog_unread_env.py +0 -0
  205. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_124_register_merge.py +0 -0
  206. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_126_pending_from_complete.py +0 -0
  207. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  208. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_138_memory_navigate.py +0 -0
  209. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_139_tool_probe.py +0 -0
  210. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_183_card_anchor.py +0 -0
  211. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_184_notify_honesty.py +0 -0
  212. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_201_win32_bash_refusal.py +0 -0
  213. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_243_onboard_per_peer_token.py +0 -0
  214. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_307_task4_ask_reply.py +0 -0
  215. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  216. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_319_refusal_exit_codes.py +0 -0
  217. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_323_mistral_backend.py +0 -0
  218. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_332_report_organize_findings.py +0 -0
  219. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_356_query_filters.py +0 -0
  220. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_397_gh_identity_router.py +0 -0
  221. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_397_router_preflight.py +0 -0
  222. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_402_one_identity_resolver.py +0 -0
  223. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_467b_onboard_operator_credential.py +0 -0
  224. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_472_register_caller_binding.py +0 -0
  225. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_484_codex_queue_sink.py +0 -0
  226. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_523_guide.py +0 -0
  227. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_524_conftest_hermeticity.py +0 -0
  228. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_532_accept_flag.py +0 -0
  229. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_535_version_capability.py +0 -0
  230. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_538_signal_bench.py +0 -0
  231. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_546_default_gateway.py +0 -0
  232. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_547_verbs_from_registry.py +0 -0
  233. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_548_gateway_remainder.py +0 -0
  234. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_552_codegraph_gateway.py +0 -0
  235. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_555_relay_row_shape.py +0 -0
  236. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_556_relay_freshness.py +0 -0
  237. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_559_edges_truncated.py +0 -0
  238. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_564_bootstrap_first_peer.py +0 -0
  239. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  240. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_579_register_bootstrap_message.py +0 -0
  241. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_591_cli_step_graph.py +0 -0
  242. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_644_monitor_supervision.py +0 -0
  243. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_648_install_unit.py +0 -0
  244. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_654_reexec.py +0 -0
  245. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_656_owned_slm.py +0 -0
  246. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_684_dreaming_verb.py +0 -0
  247. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_689_pkg_version_order.py +0 -0
  248. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_715_grok_wake.py +0 -0
  249. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_716_timeline_one_path.py +0 -0
  250. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_723_grok_0251.py +0 -0
  251. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_724_ps1_ascii_or_bom.py +0 -0
  252. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_725_stdio_reconfigure.py +0 -0
  253. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_726_grok_limit_screen.py +0 -0
  254. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_729_arm_check_delivery_gap.py +0 -0
  255. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_729_dm_once.py +0 -0
  256. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_729_wake_watchdog.py +0 -0
  257. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_734_dreaming_enrich_degrade.py +0 -0
  258. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_735_dm_mcp_tools.py +0 -0
  259. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_739_wake_writer.py +0 -0
  260. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_740_edit_project.py +0 -0
  261. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_762_cards_edit_priority.py +0 -0
  262. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_764_enrich_collapse.py +0 -0
  263. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_801_confirm_flow_cli.py +0 -0
  264. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_802_stage_history.py +0 -0
  265. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_825_codegraph_hook_noise.py +0 -0
  266. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_825_install_posttooluse_only.py +0 -0
  267. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_825_remaining_cap_shred_bind.py +0 -0
  268. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_829_counterfactual_column.py +0 -0
  269. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_830_hook_binding_version.py +0 -0
  270. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_84_cli_labels.py +0 -0
  271. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_866_doctrine_guide.py +0 -0
  272. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_872_identity_refuses_not_warns.py +0 -0
  273. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_874_source_text.py +0 -0
  274. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
  275. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_937_dreaming_notify.py +0 -0
  276. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_938_organize_line_limit.py +0 -0
  277. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_941_bench_backends.py +0 -0
  278. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_941_harness_342.py +0 -0
  279. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_945_same_line_pairing.py +0 -0
  280. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_955_prompt_audit.py +0 -0
  281. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_957_auth_http.py +0 -0
  282. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_959_venv_interpreter.py +0 -0
  283. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_960_channel.py +0 -0
  284. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
  285. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_961_cursor_grok_footer.py +0 -0
  286. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_961_loud_stop.py +0 -0
  287. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_963_plugin_manifest.py +0 -0
  288. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_964_channel_cell.py +0 -0
  289. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_965_mesh_wait.py +0 -0
  290. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_975_channel_hop.py +0 -0
  291. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_add_security_gate.py +0 -0
  292. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_add.py +0 -0
  293. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_hash.py +0 -0
  294. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_lib.py +0 -0
  295. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_mcp.py +0 -0
  296. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_skill.py +0 -0
  297. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_tool.py +0 -0
  298. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_uri.py +0 -0
  299. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_backends.py +0 -0
  300. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_claude_cli.py +0 -0
  301. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_codex_cli.py +0 -0
  302. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_command.py +0 -0
  303. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_pack.py +0 -0
  304. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_prices.py +0 -0
  305. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_quality.py +0 -0
  306. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_runner.py +0 -0
  307. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_validate.py +0 -0
  308. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_board_card_thread.py +0 -0
  309. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_board_command.py +0 -0
  310. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_board_merge_check.py +0 -0
  311. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_board_obligation_close.py +0 -0
  312. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_brain_ask_command.py +0 -0
  313. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_brain_ask_env_diagnosis.py +0 -0
  314. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_brain_ask_identity_explicitness.py +0 -0
  315. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_brain_command.py +0 -0
  316. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_caller_meta_guard.py +0 -0
  317. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_capture_lineage.py +0 -0
  318. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_capture_liveness.py +0 -0
  319. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_capture_manifest.py +0 -0
  320. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_capture_paths.py +0 -0
  321. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_capture_security.py +0 -0
  322. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cell_command_dispatch.py +0 -0
  323. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cell_harden.py +0 -0
  324. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cell_loader.py +0 -0
  325. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cell_selfcheck.py +0 -0
  326. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cell_verify.py +0 -0
  327. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_chain_token.py +0 -0
  328. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_channel_command.py +0 -0
  329. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  330. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_channel_post.py +0 -0
  331. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_channel_wake_policy_filter.py +0 -0
  332. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_chat_command.py +0 -0
  333. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_claude_parser.py +0 -0
  334. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_claude_tmux_template.py +0 -0
  335. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_codegraph_caller_scope.py +0 -0
  336. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_codegraph_command.py +0 -0
  337. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_codegraph_hook.py +0 -0
  338. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_codegraph_mcp.py +0 -0
  339. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_codex_waker.py +0 -0
  340. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_compress_caller_convention.py +0 -0
  341. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_compress_command.py +0 -0
  342. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_compress_levers.py +0 -0
  343. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_compress_marker.py +0 -0
  344. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_compress_verify.py +0 -0
  345. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_console_encoding_e2e.py +0 -0
  346. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_content_composition.py +0 -0
  347. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cursor_membrane.py +0 -0
  348. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_daemon_command.py +0 -0
  349. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_daemon_console_encoding.py +0 -0
  350. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_daemon_delivery.py +0 -0
  351. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_delivery_queue.py +0 -0
  352. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_display_sanitize.py +0 -0
  353. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  354. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_event_emit.py +0 -0
  355. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_feature_to_uri.py +0 -0
  356. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_gateway_brain.py +0 -0
  357. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_gateway_client.py +0 -0
  358. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_gateway_command.py +0 -0
  359. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_gateway_message_idempotency.py +0 -0
  360. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  361. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_group_command.py +0 -0
  362. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_guide_commands_parse.py +0 -0
  363. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_guide_selfcheck.py +0 -0
  364. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_heartbeat_check.py +0 -0
  365. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_highlight_command.py +0 -0
  366. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hook_output.py +0 -0
  367. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_activity_marker.py +0 -0
  368. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_add.py +0 -0
  369. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_bundle.py +0 -0
  370. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_init.py +0 -0
  371. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_legacy_generation_removal.py +0 -0
  372. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_lifecycle.py +0 -0
  373. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_merge.py +0 -0
  374. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_verify.py +0 -0
  375. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  376. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_win32_command_path.py +0 -0
  377. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_import_command.py +0 -0
  378. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_inbox_identity_provenance.py +0 -0
  379. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_init_command.py +0 -0
  380. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_init_provider_menu.py +0 -0
  381. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_install_codex_hooks.py +0 -0
  382. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_install_hook.py +0 -0
  383. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_install_multiplexer_command.py +0 -0
  384. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_install_postcompact_hook.py +0 -0
  385. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_install_wake_hook.py +0 -0
  386. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_lane_command.py +0 -0
  387. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_main.py +0 -0
  388. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_main_unknown_verb_guard.py +0 -0
  389. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mcp_missing_hint.py +0 -0
  390. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mcp_server.py +0 -0
  391. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_memory_command.py +0 -0
  392. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_memory_emit_snippet.py +0 -0
  393. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_memory_gateway.py +0 -0
  394. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_memory_sync.py +0 -0
  395. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_memory_sync_membrane.py +0 -0
  396. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_command.py +0 -0
  397. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_inbox_mark_read.py +0 -0
  398. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_inbox_sanitize.py +0 -0
  399. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_originate_thread_623.py +0 -0
  400. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_send_unknown_peer.py +0 -0
  401. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  402. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_sidecar_muse_sink.py +0 -0
  403. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  404. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_meta_edge_identity.py +0 -0
  405. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_monitor_channel_poll.py +0 -0
  406. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_monitor_cli.py +0 -0
  407. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_monitor_daemon_collision.py +0 -0
  408. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_monitor_self_name_verification.py +0 -0
  409. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_monitor_state_split.py +0 -0
  410. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_multiplexer.py +0 -0
  411. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_muse_membrane.py +0 -0
  412. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_muse_own_cli.py +0 -0
  413. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_obligation_close_is_surfaced.py +0 -0
  414. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_okf_links.py +0 -0
  415. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_onboard_command.py +0 -0
  416. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_opencode_membrane.py +0 -0
  417. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_opencode_plugin.py +0 -0
  418. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_operator_me.py +0 -0
  419. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_orphan_daemons.py +0 -0
  420. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_packaged_artifacts_exist.py +0 -0
  421. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_packaged_skills.py +0 -0
  422. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_executor.py +0 -0
  423. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_executor_windows.py +0 -0
  424. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_reply_drain_command.py +0 -0
  425. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_reply_drain_supervisor.py +0 -0
  426. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_reply_outbox.py +0 -0
  427. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_reply_transport.py +0 -0
  428. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_service_e2e.py +0 -0
  429. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_service_host.py +0 -0
  430. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_service_payload.py +0 -0
  431. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_service_reply.py +0 -0
  432. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_postcompact_recall.py +0 -0
  433. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_process_liveness.py +0 -0
  434. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_protocol_handler.py +0 -0
  435. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_providers_isolation.py +0 -0
  436. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_ratify_command.py +0 -0
  437. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_readme_claims_no_gateway_default.py +0 -0
  438. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_repl_caller_convention.py +0 -0
  439. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_schedule_command.py +0 -0
  440. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_schedule_create_contract.py +0 -0
  441. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_security.py +0 -0
  442. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_service_app.py +0 -0
  443. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_service_command.py +0 -0
  444. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_service_providers.py +0 -0
  445. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_session_bridge_inject.py +0 -0
  446. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_session_bridge_probe.py +0 -0
  447. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_session_bridge_resolve.py +0 -0
  448. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_session_path_role_gate.py +0 -0
  449. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_shipped_units_match_the_cli.py +0 -0
  450. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_smoke_chat.py +0 -0
  451. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_smoke_one_shot.py +0 -0
  452. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_smoke_phase_5_5.py +0 -0
  453. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_base_hoist.py +0 -0
  454. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_command.py +0 -0
  455. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_identity_stamp.py +0 -0
  456. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_live_pin.py +0 -0
  457. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_mitosis_lineage.py +0 -0
  458. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_tmux_session.py +0 -0
  459. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_windows_relaunch.py +0 -0
  460. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_stall_alert.py +0 -0
  461. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_subprocess_decode_encoding.py +0 -0
  462. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_timeline_command.py +0 -0
  463. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_tmux_wake_runstate_defer.py +0 -0
  464. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_tmux_wake_session_reanchor.py +0 -0
  465. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_tmux_wake_stale.py +0 -0
  466. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_tmux_wake_submit_verify.py +0 -0
  467. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_token_file_one_parser.py +0 -0
  468. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_token_precedence_explicit_first.py +0 -0
  469. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_unified_token_resolver.py +0 -0
  470. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_version_command.py +0 -0
  471. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_version_consistency.py +0 -0
  472. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_vibe_membrane.py +0 -0
  473. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog.py +0 -0
  474. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_dm_wake.py +0 -0
  475. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  476. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  477. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_emit_health.py +0 -0
  478. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_install_flags.py +0 -0
  479. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_model_rung.py +0 -0
  480. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_stale_peers.py +0 -0
  481. {swarph_cli-0.72.8 → swarph_cli-0.72.9}/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.8
3
+ Version: 0.72.9
4
4
  Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
5
5
  Author: Pierre Samson, Claude Opus
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swarph-cli"
7
- version = "0.72.8"
7
+ version = "0.72.9"
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.8"
19
+ __version__ = "0.72.9"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -0,0 +1,237 @@
1
+ """``swarph roster`` — read/write the gateway's operator-maintained capacity table.
2
+
3
+ card #1061 (ROSTER AS DATA): the roster replaces tribal knowledge about who
4
+ builds, who reviews, on which model/effort, under which quota, and who is out
5
+ until when. Reads hit GET /roster (any authenticated caller); writes hit
6
+ PUT /roster/{peer} (operators only — the gateway 403s the rest).
7
+
8
+ swarph roster [--peer PEER] [--json] list the table (or one row)
9
+ swarph roster set PEER [--model M] [--effort E] [--roles r1,r2]
10
+ [--quota-pool P] [--quota-used PCT --quota-as-of TS] [--resets DATE]
11
+ [--until TS | --clear-until] [--note TEXT]
12
+
13
+ A quota VALUE without its as_of coordinate is a rumour: --quota-used /
14
+ --resets without --quota-as-of are refused client-side (exit 2) before the
15
+ gateway's own 400. The pool NAME needs no coordinate (identifier, not a
16
+ measurement). --clear-until is the grok-returns flow (explicit null clears).
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import argparse
21
+ import json
22
+ import sys
23
+ import urllib.error
24
+ import urllib.request
25
+
26
+ # card #1061 role vocabulary — mirrors the gateway's _ROSTER_ROLES. A role
27
+ # the gateway does not know is refused here (exit 2) before its 400; when the
28
+ # vocabulary grows, BOTH pins change together (gateway tests + test_1061 below).
29
+ ROSTER_ROLES = ("build", "validate", "plan-review", "orchestrate")
30
+
31
+
32
+ def _http_get_json(url, token, *, timeout=10.0):
33
+ from swarph_cli.commands.mesh import _http_get_json as _get
34
+ return _get(url, token, timeout=timeout)
35
+
36
+
37
+ def _http_put_json(url, body, token, *, timeout=10.0):
38
+ from swarph_cli.commands.mesh import _require_absolute_gateway_url
39
+ _require_absolute_gateway_url(url)
40
+ data = json.dumps(body).encode("utf-8")
41
+ req = urllib.request.Request(
42
+ url, data=data, method="PUT",
43
+ headers={"Authorization": f"Bearer {token}",
44
+ "Content-Type": "application/json"})
45
+ try:
46
+ with urllib.request.urlopen(req, timeout=timeout) as resp:
47
+ return resp.status, json.loads(resp.read().decode("utf-8") or "{}")
48
+ except urllib.error.HTTPError as exc:
49
+ try:
50
+ err_body = json.loads(exc.read().decode("utf-8") or "{}")
51
+ except Exception:
52
+ err_body = {"detail": str(exc)}
53
+ return exc.code, err_body
54
+ except urllib.error.URLError as exc:
55
+ return 0, {"detail": str(exc)}
56
+
57
+
58
+ def _resolve(args):
59
+ from swarph_cli.tokens import resolve_token
60
+ resolution = resolve_token(args.self_name, args.token_file,
61
+ identity_is_explicit=bool(args.self_name))
62
+ if resolution is None:
63
+ print("swarph roster: no token (set MESH_GATEWAY_TOKEN, pass "
64
+ "--token-file, or --as a peer with a stored token)",
65
+ file=sys.stderr)
66
+ return None
67
+ return resolution.token
68
+
69
+
70
+ def _quota_compact(r):
71
+ if r.get("quota_used_pct") is None and not r.get("quota_pool"):
72
+ return "-"
73
+ parts = []
74
+ if r.get("quota_pool"):
75
+ parts.append(str(r["quota_pool"]))
76
+ if r.get("quota_used_pct") is not None:
77
+ parts.append(f"{r['quota_used_pct']}%")
78
+ if r.get("quota_as_of"):
79
+ parts.append(f"@{r['quota_as_of']}")
80
+ if r.get("quota_resets_at"):
81
+ parts.append(f"(resets {r['quota_resets_at']})")
82
+ return " ".join(parts)
83
+
84
+
85
+ def _line(r):
86
+ roles = ",".join(r["roles"]) if r.get("roles") else "-"
87
+ bits = [r["peer"],
88
+ f"model={r.get('model') or '-'}",
89
+ f"effort={r.get('effort') or '-'}",
90
+ f"roles={roles}",
91
+ f"quota={_quota_compact(r)}"]
92
+ if r.get("unavailable_until"):
93
+ bits.append(f"out-until={r['unavailable_until']}")
94
+ bits.append(f"updated_by={r.get('updated_by') or '?'}")
95
+ return " ".join(bits)
96
+
97
+
98
+ def _run_list(args):
99
+ token = _resolve(args)
100
+ if token is None:
101
+ return 2
102
+ gateway = args.gateway.rstrip("/")
103
+ status, payload = _http_get_json(f"{gateway}/roster", token)
104
+ if status < 200 or status >= 300:
105
+ detail = payload.get("detail", "<gateway error>") if isinstance(payload, dict) else "<gateway error>"
106
+ print(f"swarph roster: gateway {status}: {detail}", file=sys.stderr)
107
+ return 1
108
+ rows = payload.get("roster") if isinstance(payload, dict) else None
109
+ if not isinstance(rows, list):
110
+ print("swarph roster: unexpected /roster shape (no roster list)",
111
+ file=sys.stderr)
112
+ return 1
113
+ if args.peer:
114
+ rows = [r for r in rows if isinstance(r, dict) and r.get("peer") == args.peer]
115
+ if not rows:
116
+ print(f"swarph roster: no row for {args.peer!r}", file=sys.stderr)
117
+ return 1
118
+ if args.json:
119
+ print(json.dumps(rows, indent=2))
120
+ else:
121
+ for r in rows:
122
+ print(_line(r) if isinstance(r, dict) else r)
123
+ return 0
124
+
125
+
126
+ def _run_set(args):
127
+ token = _resolve(args)
128
+ if token is None:
129
+ return 2
130
+ if ((args.quota_used is not None or args.resets is not None)
131
+ and args.quota_as_of is None):
132
+ print("swarph roster set: --quota-used / --resets need --quota-as-of "
133
+ "(a quota value without its coordinate is a rumour)",
134
+ file=sys.stderr)
135
+ return 2
136
+ body = {}
137
+ if args.model is not None:
138
+ body["model"] = args.model
139
+ if args.effort is not None:
140
+ body["effort"] = args.effort
141
+ if args.roles is not None:
142
+ roles = [x.strip() for x in args.roles.split(",") if x.strip()]
143
+ bad = [x for x in roles if x not in ROSTER_ROLES]
144
+ if bad:
145
+ print(f"swarph roster set: unknown role(s) {bad} "
146
+ f"(vocabulary: {', '.join(ROSTER_ROLES)})", file=sys.stderr)
147
+ return 2
148
+ body["roles"] = roles
149
+ if args.quota_pool is not None:
150
+ body["quota_pool"] = args.quota_pool
151
+ if args.quota_used is not None:
152
+ body["quota_used_pct"] = args.quota_used
153
+ if args.resets is not None:
154
+ body["quota_resets_at"] = args.resets
155
+ if args.quota_as_of is not None:
156
+ body["quota_as_of"] = args.quota_as_of
157
+ if args.until is not None:
158
+ body["unavailable_until"] = args.until
159
+ if args.clear_until:
160
+ body["unavailable_until"] = None
161
+ if args.note is not None:
162
+ body["note"] = args.note
163
+ if not body:
164
+ print("swarph roster set: nothing to set (pass a field flag)",
165
+ file=sys.stderr)
166
+ return 2
167
+ gateway = args.gateway.rstrip("/")
168
+ status, payload = _http_put_json(
169
+ f"{gateway}/roster/{args.peer}", body, token)
170
+ if status < 200 or status >= 300:
171
+ detail = payload.get("detail", "<gateway error>") if isinstance(payload, dict) else "<gateway error>"
172
+ print(f"swarph roster set: gateway {status}: {detail}", file=sys.stderr)
173
+ return 1
174
+ if args.json:
175
+ print(json.dumps(payload, indent=2))
176
+ else:
177
+ print(f"updated {args.peer} (updated_by={payload.get('updated_by', '?')})")
178
+ return 0
179
+
180
+
181
+ def _add_global(p):
182
+ p.add_argument("--as", dest="self_name", default=None,
183
+ help="peer identity for token resolution")
184
+ from swarph_cli.gateway_default import env_gateway
185
+ p.add_argument("--gateway", default=env_gateway(),
186
+ help="mesh-gateway base URL")
187
+ p.add_argument("--token-file", default=None,
188
+ help="explicit Bearer [REDACTED] file")
189
+
190
+
191
+ def _build_parser():
192
+ p = argparse.ArgumentParser(
193
+ prog="swarph roster",
194
+ description="Read/write the gateway capacity roster (card #1061).")
195
+ _add_global(p)
196
+ p.add_argument("--peer", default=None,
197
+ help="show only this peer (list mode)")
198
+ p.add_argument("--json", action="store_true",
199
+ help="print the raw gateway payload")
200
+ sub = p.add_subparsers(dest="command")
201
+ s = sub.add_parser("set", help="upsert one roster row (operators only)")
202
+ _add_global(s)
203
+ s.add_argument("peer", help="peer the row belongs to")
204
+ s.add_argument("--json", action="store_true",
205
+ help="print the raw gateway payload")
206
+ s.add_argument("--model", default=None)
207
+ s.add_argument("--effort", default=None)
208
+ s.add_argument("--roles", default=None,
209
+ help="comma-separated subset of " + ",".join(ROSTER_ROLES))
210
+ s.add_argument("--quota-pool", default=None)
211
+ s.add_argument("--quota-used", type=float, default=None,
212
+ help="quota_used_pct (needs --quota-as-of)")
213
+ s.add_argument("--quota-as-of", default=None)
214
+ s.add_argument("--resets", default=None,
215
+ help="quota_resets_at date (needs --quota-as-of)")
216
+ group = s.add_mutually_exclusive_group()
217
+ group.add_argument("--until", default=None,
218
+ help="unavailable_until timestamp")
219
+ group.add_argument("--clear-until", action="store_true",
220
+ help="clear unavailable_until (peer is back)")
221
+ s.add_argument("--note", default=None)
222
+ return p
223
+
224
+
225
+ def run_roster(argv):
226
+ parser = _build_parser()
227
+ args = parser.parse_args(argv)
228
+ try:
229
+ if args.command == "set":
230
+ return _run_set(args)
231
+ if args.command is None:
232
+ return _run_list(args)
233
+ parser.error(f"unknown command: {args.command}")
234
+ except RuntimeError as exc:
235
+ print(f"swarph roster: {exc}", file=sys.stderr)
236
+ return 2
237
+ return 2
@@ -543,6 +543,7 @@ answers `--help`; hook-plumbing verbs are the callbacks hooks invoke, not comman
543
543
  - `swarph protocol-handler` -- register `swarph://` as an OS URL-scheme handler.
544
544
  - `swarph ratify` -- witness flip that admits an onboarded peer; takes the peer name and `--reason`.
545
545
  - `swarph rights` -- RBAC rights over the gateway (companion of `swarph group`).
546
+ - `swarph roster` -- the gateway capacity table (card #1061): who builds, who reviews, quota, who is out until when. `swarph roster --peer <peer>`, `swarph roster set <peer> --roles build` (operators only).
546
547
  - `swarph rowclear-hook` -- SessionStart hook (card #432): when `source` is `clear`, write the new session id into the role's `<role>.session-id` pin so the next spawn resumes the cleared session.
547
548
  - `swarph scan` -- statically scan an artifact for dangerous patterns before publish.
548
549
  - `swarph schedule` -- the gateway's scheduled events: create, list, get, enable, disable, delete, fire-now.
@@ -110,6 +110,7 @@ _VERB_HANDLERS: dict[str, str] = {
110
110
  "board": "swarph_cli.commands.board.run_board",
111
111
  "group": "swarph_cli.commands.group.run_group",
112
112
  "rights": "swarph_cli.commands.group.run_rights",
113
+ "roster": "swarph_cli.commands.roster.run_roster",
113
114
  "mcp-server": "swarph_cli.commands.mcp_server.run_mcp_server",
114
115
  "compress": "swarph_cli.commands.compress.run_compress",
115
116
  "cell": "swarph_cli.commands.cell.run_cell",
@@ -6,6 +6,10 @@ when the cell holds no live row, the pane reads idle, and no DM is owed.
6
6
  type nothing), or ``live``. v1 opt-in is drop-on-meta-edge only: a cell
7
7
  that owns a project keeps its context (design_1007 / optin_owners).
8
8
 
9
+ v1.1 (#1362): a taken row whose step needs are UNMET is waiting, not
10
+ working — it does not count as live. Needs state comes from the card's
11
+ step graph; anything unreadable about it fails closed (no clear).
12
+
9
13
  A ``/clear`` mints a new Claude session id. The SessionStart hook with
10
14
  ``source=clear`` writes that id into the role's ``<role>.session-id``
11
15
  pin, so the next spawn resumes the cleared session instead of the long
@@ -95,11 +99,62 @@ def _dm_owed(state) -> bool:
95
99
  return False
96
100
 
97
101
 
102
+ def _step_needs_met(state, row: dict, http_get: Callable,
103
+ graphs: dict) -> Optional[bool]:
104
+ """Is this open row's work actionable (True), waiting (False), or
105
+ unevaluable (None)?
106
+
107
+ A row with no step has no needs to unmeet (ruling_1236: still live).
108
+ Otherwise the card's step graph (GET /board/cards/{id}/graph) names the
109
+ step's needs with a satisfied flag — every need satisfied means the
110
+ holder can act; one unsatisfied need means the cell is between rows.
111
+ Anything unreadable — no card id, a failed graph fetch, a missing step
112
+ entry, a needs entry without a boolean satisfied flag — is None: an
113
+ unevaluable row must not look like an empty cell (fail closed, #1362).
114
+ One graph fetch per card per poll; the same http_get the board read uses.
115
+ """
116
+ step = row.get("step")
117
+ if not step:
118
+ return True
119
+ card_id = row.get("card_id")
120
+ if not isinstance(card_id, int) or isinstance(card_id, bool):
121
+ return None
122
+ if card_id not in graphs:
123
+ url = f"{state.gateway}/board/cards/{card_id}/graph"
124
+ try:
125
+ status, body = http_get(url, state.token)
126
+ except Exception:
127
+ return None
128
+ if status != 200 or not isinstance(body, dict):
129
+ return None
130
+ steps = body.get("steps")
131
+ if not isinstance(steps, list):
132
+ return None
133
+ graphs[card_id] = steps
134
+ for entry in graphs[card_id]:
135
+ if isinstance(entry, dict) and entry.get("step") == step:
136
+ needs = entry.get("needs")
137
+ if not isinstance(needs, list):
138
+ return None
139
+ for need in needs:
140
+ if not isinstance(need, dict) or not isinstance(
141
+ need.get("satisfied"), bool):
142
+ return None
143
+ if not need["satisfied"]:
144
+ return False
145
+ return True
146
+ return None
147
+
148
+
98
149
  def _live_row_count(state, http_get: Callable) -> Optional[int]:
99
- """How many unfinished rows this cell holds, or None if unread.
150
+ """How many ACTIONABLE rows this cell holds, or None if unread.
100
151
 
101
152
  None fails closed: an unreadable board must not look like an empty
102
153
  one, or a live row we failed to see gets a ``/clear``.
154
+
155
+ v1.1 (#1362): an open row whose step needs are unmet is waiting, not
156
+ working — it does not count. An open row with no step, or whose step
157
+ needs nothing, is still live (ruling_1236 unchanged).
103
158
  """
104
159
  url = f"{state.gateway}/board/obligations?holder={state.self_name}"
105
160
  try:
@@ -111,15 +166,21 @@ def _live_row_count(state, http_get: Callable) -> Optional[int]:
111
166
  rows = body.get("obligations")
112
167
  if not isinstance(rows, list):
113
168
  return None
169
+ graphs: dict = {}
114
170
  live = 0
115
171
  for row in rows:
116
172
  if not isinstance(row, dict):
117
173
  return None
118
174
  status = str(row.get("status") or "")
119
- if status == _LIVE:
120
- live += 1
121
- elif status not in _FINISHED:
175
+ if status in _FINISHED:
176
+ continue
177
+ if status != _LIVE:
122
178
  return None
179
+ met = _step_needs_met(state, row, http_get, graphs)
180
+ if met is None:
181
+ return None
182
+ if met:
183
+ live += 1
123
184
  return live
124
185
 
125
186
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swarph-cli
3
- Version: 0.72.8
3
+ Version: 0.72.9
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
@@ -110,6 +110,7 @@ src/swarph_cli/commands/peer_reply_drain.py
110
110
  src/swarph_cli/commands/postcompact_hook_output.py
111
111
  src/swarph_cli/commands/protocol_handler.py
112
112
  src/swarph_cli/commands/ratify.py
113
+ src/swarph_cli/commands/roster.py
113
114
  src/swarph_cli/commands/rowclear_hook.py
114
115
  src/swarph_cli/commands/schedule.py
115
116
  src/swarph_cli/commands/security.py
@@ -196,6 +197,7 @@ tests/test_1017_muse_tui.py
196
197
  tests/test_1050_surrogate_wake.py
197
198
  tests/test_1052_opencode_deaf.py
198
199
  tests/test_1059_watchdog_unread_env.py
200
+ tests/test_1061_roster_cli.py
199
201
  tests/test_124_register_merge.py
200
202
  tests/test_126_pending_from_complete.py
201
203
  tests/test_132_ensure_monitor_state_dir.py
@@ -0,0 +1,137 @@
1
+ """card #1061 — ``swarph roster`` list + set against a faked gateway transport."""
2
+ from __future__ import annotations
3
+
4
+ from swarph_cli.commands import roster
5
+
6
+
7
+ def _env(monkeypatch):
8
+ monkeypatch.setenv("MESH_GATEWAY_URL", "http://gw.test:8788")
9
+ monkeypatch.setenv("MESH_GATEWAY_TOKEN", "tok")
10
+
11
+
12
+ def _fake_get(monkeypatch, payload, status=200):
13
+ calls = []
14
+
15
+ def _fake(url, token, **kw):
16
+ calls.append((url, token))
17
+ return status, payload
18
+
19
+ monkeypatch.setattr(roster, "_http_get_json", _fake)
20
+ return calls
21
+
22
+
23
+ def _fake_put(monkeypatch, payload=None, status=200):
24
+ calls = []
25
+
26
+ def _fake(url, body, token, **kw):
27
+ calls.append((url, body, token))
28
+ return status, ({"peer": "p", "updated_by": "shared-token",
29
+ **body} if payload is None else payload)
30
+
31
+ monkeypatch.setattr(roster, "_http_put_json", _fake)
32
+ return calls
33
+
34
+
35
+ ROWS = {"roster": [
36
+ {"peer": "meta-muse", "model": None, "effort": "MAX", "roles": ["build"],
37
+ "quota_pool": None, "quota_used_pct": 4.0,
38
+ "quota_resets_at": None, "quota_as_of": "2026-10-07T17:00:00Z",
39
+ "unavailable_until": None, "note": None,
40
+ "updated_by": "seed #1061", "updated_at": "t"},
41
+ {"peer": "grok-researcher", "model": None, "effort": None, "roles": None,
42
+ "quota_pool": None, "quota_used_pct": None,
43
+ "quota_resets_at": None, "quota_as_of": None,
44
+ "unavailable_until": "2026-10-09T22:37:00Z", "note": None,
45
+ "updated_by": "seed #1061", "updated_at": "t"},
46
+ ]}
47
+
48
+
49
+ def test_list_prints_one_line_per_peer(monkeypatch, capsys):
50
+ _env(monkeypatch)
51
+ _fake_get(monkeypatch, ROWS)
52
+ assert roster.run_roster([]) == 0
53
+ out = capsys.readouterr().out.splitlines()
54
+ assert len(out) == 2
55
+ assert out[0].startswith("meta-muse") and "roles=build" in out[0]
56
+ assert "out-until=2026-10-09T22:37:00Z" in out[1]
57
+
58
+
59
+ def test_list_peer_filter_and_missing(monkeypatch, capsys):
60
+ _env(monkeypatch)
61
+ _fake_get(monkeypatch, ROWS)
62
+ assert roster.run_roster(["--peer", "grok-researcher"]) == 0
63
+ assert capsys.readouterr().out.startswith("grok-researcher")
64
+ assert roster.run_roster(["--peer", "nobody"]) == 1
65
+
66
+
67
+ def test_list_gateway_error_is_exit_1(monkeypatch, capsys):
68
+ _env(monkeypatch)
69
+ _fake_get(monkeypatch, {"detail": "nope"}, status=403)
70
+ assert roster.run_roster([]) == 1
71
+ assert "403" in capsys.readouterr().err
72
+
73
+
74
+ def test_set_sends_partial_body(monkeypatch, capsys):
75
+ _env(monkeypatch)
76
+ calls = _fake_put(monkeypatch)
77
+ rc = roster.run_roster(["set", "grok-researcher",
78
+ "--until", "2026-10-09T22:37Z",
79
+ "--note", "quota out"])
80
+ assert rc == 0
81
+ url, body, token = calls[0]
82
+ assert url == "http://gw.test:8788/roster/grok-researcher"
83
+ assert body == {"unavailable_until": "2026-10-09T22:37Z",
84
+ "note": "quota out"}
85
+ assert token == "tok"
86
+ assert "shared-token" in capsys.readouterr().out
87
+
88
+
89
+ def test_set_clear_until_sends_null(monkeypatch):
90
+ _env(monkeypatch)
91
+ calls = _fake_put(monkeypatch)
92
+ assert roster.run_roster(["set", "grok-researcher", "--clear-until"]) == 0
93
+ assert calls[0][1] == {"unavailable_until": None}
94
+
95
+
96
+ def test_set_quota_without_as_of_refused_client_side(monkeypatch, capsys):
97
+ _env(monkeypatch)
98
+ calls = _fake_put(monkeypatch)
99
+ assert roster.run_roster(["set", "p", "--quota-used", "70"]) == 2
100
+ assert roster.run_roster(["set", "p", "--resets", "2026-10-13"]) == 2
101
+ assert calls == [] # refused before any transport
102
+ assert "as-of" in capsys.readouterr().err
103
+
104
+
105
+ def test_set_quota_with_as_of_sends_all_three(monkeypatch):
106
+ _env(monkeypatch)
107
+ calls = _fake_put(monkeypatch)
108
+ assert roster.run_roster(["set", "cursor-lin", "--quota-pool", "Cursor",
109
+ "--quota-used", "70",
110
+ "--quota-as-of", "2026-10-07T17:00:00Z",
111
+ "--resets", "2026-10-13"]) == 0
112
+ assert calls[0][1] == {"quota_pool": "Cursor", "quota_used_pct": 70.0,
113
+ "quota_as_of": "2026-10-07T17:00:00Z",
114
+ "quota_resets_at": "2026-10-13"}
115
+
116
+
117
+ def test_set_unknown_role_refused_client_side(monkeypatch, capsys):
118
+ _env(monkeypatch)
119
+ calls = _fake_put(monkeypatch)
120
+ assert roster.run_roster(["set", "p", "--roles", "build,pilot"]) == 2
121
+ assert calls == []
122
+ assert "pilot" in capsys.readouterr().err
123
+
124
+
125
+ def test_set_gateway_403_names_the_gate(monkeypatch, capsys):
126
+ _env(monkeypatch)
127
+ _fake_put(monkeypatch, {"detail": "roster PUT requires an operator"},
128
+ status=403)
129
+ assert roster.run_roster(["set", "p", "--model", "M"]) == 1
130
+ assert "403" in capsys.readouterr().err
131
+
132
+
133
+ def test_set_with_no_fields_is_usage_error(monkeypatch, capsys):
134
+ _env(monkeypatch)
135
+ calls = _fake_put(monkeypatch)
136
+ assert roster.run_roster(["set", "p"]) == 2
137
+ assert calls == []