swarph-cli 0.72.18__tar.gz → 0.72.20__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 (509) hide show
  1. {swarph_cli-0.72.18/src/swarph_cli.egg-info → swarph_cli-0.72.20}/PKG-INFO +1 -1
  2. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/pyproject.toml +1 -1
  3. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/__init__.py +1 -1
  4. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/providers.py +20 -0
  5. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/validate.py +57 -6
  6. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/bench.py +3 -16
  7. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/wake_watchdog.py +41 -2
  8. {swarph_cli-0.72.18 → swarph_cli-0.72.20/src/swarph_cli.egg-info}/PKG-INFO +1 -1
  9. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_729_wake_watchdog.py +51 -0
  10. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_validate.py +141 -1
  11. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/LICENSE +0 -0
  12. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/README.md +0 -0
  13. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/setup.cfg +0 -0
  14. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/__main__.py +0 -0
  15. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/__init__.py +0 -0
  16. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/backends.py +0 -0
  17. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/claude_cli.py +0 -0
  18. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/codex_cli.py +0 -0
  19. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/pack.py +0 -0
  20. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/prices.py +0 -0
  21. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/quality.py +0 -0
  22. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/refresh_prices.py +0 -0
  23. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/rules.py +0 -0
  24. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/runner.py +0 -0
  25. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/signal_score.py +0 -0
  26. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/caller.py +0 -0
  27. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/__init__.py +0 -0
  28. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/harden.py +0 -0
  29. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/lineage.py +0 -0
  30. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/liveness.py +0 -0
  31. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/manifest.py +0 -0
  32. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/paths.py +0 -0
  33. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/verify.py +0 -0
  34. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/cell.py +0 -0
  35. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/chain_token.py +0 -0
  36. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/channel.py +0 -0
  37. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/__init__.py +0 -0
  38. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/_content.py +0 -0
  39. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/_display.py +0 -0
  40. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/_gateway_client.py +0 -0
  41. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/add.py +0 -0
  42. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/board.py +0 -0
  43. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/board_merge_check.py +0 -0
  44. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/brain.py +0 -0
  45. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/brain_ask.py +0 -0
  46. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/cell.py +0 -0
  47. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/cell_probe.py +0 -0
  48. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  49. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/channel.py +0 -0
  50. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/chat.py +0 -0
  51. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/codegraph.py +0 -0
  52. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/codegraph_hook.py +0 -0
  53. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  54. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/codex_waker.py +0 -0
  55. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/compress.py +0 -0
  56. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/daemon.py +0 -0
  57. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/dreaming.py +0 -0
  58. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/event.py +0 -0
  59. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/gateway.py +0 -0
  60. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/gh_route.py +0 -0
  61. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/group.py +0 -0
  62. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/guide.py +0 -0
  63. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/highlight.py +0 -0
  64. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/hook_interpreter.py +0 -0
  65. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/hook_output.py +0 -0
  66. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/hooks.py +0 -0
  67. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/import_session.py +0 -0
  68. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/init.py +0 -0
  69. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  70. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_hook.py +0 -0
  71. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  72. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
  73. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
  74. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  75. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/lane.py +0 -0
  76. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/mcp_server.py +0 -0
  77. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/memory.py +0 -0
  78. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
  79. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/memory_sync.py +0 -0
  80. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/mesh.py +0 -0
  81. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/monitor.py +0 -0
  82. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/okf_links.py +0 -0
  83. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/onboard.py +0 -0
  84. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  85. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  86. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/protocol_handler.py +0 -0
  87. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/ratify.py +0 -0
  88. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/roster.py +0 -0
  89. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/rowclear_hook.py +0 -0
  90. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/schedule.py +0 -0
  91. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/security.py +0 -0
  92. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/service.py +0 -0
  93. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/spawn.py +0 -0
  94. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/sweep.py +0 -0
  95. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/timeline.py +0 -0
  96. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/triage.py +0 -0
  97. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/version.py +0 -0
  98. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/wake_hook_output.py +0 -0
  99. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/watchdog.py +0 -0
  100. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/compress/__init__.py +0 -0
  101. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/compress/levers.py +0 -0
  102. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/compress/marker.py +0 -0
  103. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/compress/verify.py +0 -0
  104. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/console_safe.py +0 -0
  105. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/delivery_queue.py +0 -0
  106. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dm_frame.py +0 -0
  107. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/__init__.py +0 -0
  108. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/candidates.py +0 -0
  109. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/clone.py +0 -0
  110. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/enrich.py +0 -0
  111. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/index_check.py +0 -0
  112. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/notify.py +0 -0
  113. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/organize.py +0 -0
  114. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/probes.py +0 -0
  115. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/report.py +0 -0
  116. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/run.py +0 -0
  117. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/slm.py +0 -0
  118. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/transcripts.py +0 -0
  119. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/verify.py +0 -0
  120. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/__init__.py +0 -0
  121. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/feature_registry.py +0 -0
  122. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/lanes_control.py +0 -0
  123. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/schema.sql +0 -0
  124. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/server.py +0 -0
  125. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/services_control.py +0 -0
  126. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway_default.py +0 -0
  127. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gh_identity.py +0 -0
  128. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/guide/GUIDE.md +0 -0
  129. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/identity.py +0 -0
  130. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/main.py +0 -0
  131. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/multiplexer.py +0 -0
  132. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/__init__.py +0 -0
  133. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/__main__.py +0 -0
  134. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/api.py +0 -0
  135. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/cli.py +0 -0
  136. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/config.py +0 -0
  137. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/fmt.py +0 -0
  138. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/orphan_daemons.py +0 -0
  139. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/pane_probe.py +0 -0
  140. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/parsers/__init__.py +0 -0
  141. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/parsers/claude.py +0 -0
  142. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
  143. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  144. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  145. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  146. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  147. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  148. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  149. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  150. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  151. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  152. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  153. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  154. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_executor.py +0 -0
  155. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_executor_windows.py +0 -0
  156. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_reconciliation.py +0 -0
  157. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_reply_outbox.py +0 -0
  158. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_service_host.py +0 -0
  159. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_service_payload.py +0 -0
  160. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_service_reply.py +0 -0
  161. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_staging.py +0 -0
  162. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/query_filters.py +0 -0
  163. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/quota_sync.py +0 -0
  164. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/rowclear.py +0 -0
  165. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/__init__.py +0 -0
  166. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  167. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  168. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  169. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  170. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scrub.py +0 -0
  171. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/service/__init__.py +0 -0
  172. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/service/app.py +0 -0
  173. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/service/providers.py +0 -0
  174. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/session_bridge.py +0 -0
  175. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  176. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  177. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/source_text.py +0 -0
  178. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/stall_alert.py +0 -0
  179. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/codex-waker.default +0 -0
  180. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  181. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  182. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  183. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  184. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  185. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
  186. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
  187. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  188. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  189. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  190. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
  191. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
  192. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-triage.service +0 -0
  193. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
  194. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  195. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  196. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  197. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/timeline_paths.py +0 -0
  198. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/tokens.py +0 -0
  199. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/__init__.py +0 -0
  200. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/backend.py +0 -0
  201. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/job.py +0 -0
  202. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/owners.json +0 -0
  203. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/router.py +0 -0
  204. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/rows.py +0 -0
  205. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/sensor.py +0 -0
  206. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli.egg-info/SOURCES.txt +0 -0
  207. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  208. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  209. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli.egg-info/requires.txt +0 -0
  210. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli.egg-info/top_level.txt +0 -0
  211. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1006_board_publisher.py +0 -0
  212. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1006_session_board.py +0 -0
  213. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1010_strand_only.py +0 -0
  214. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1013_spawn_channel.py +0 -0
  215. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1017_muse_tui.py +0 -0
  216. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1050_surrogate_wake.py +0 -0
  217. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1052_opencode_deaf.py +0 -0
  218. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1059_watchdog_unread_env.py +0 -0
  219. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1061_roster_cli.py +0 -0
  220. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1064_stuck_sweep.py +0 -0
  221. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1065_release.py +0 -0
  222. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1066_quiet_wakes.py +0 -0
  223. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1068_structured_accept_cli.py +0 -0
  224. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1071_quota_sync.py +0 -0
  225. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1073_triage.py +0 -0
  226. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1073_triage_board.py +0 -0
  227. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1073_wheel_install.py +0 -0
  228. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1075_task_cli.py +0 -0
  229. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1083_openai_decisions.py +0 -0
  230. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_124_register_merge.py +0 -0
  231. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_126_pending_from_complete.py +0 -0
  232. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  233. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_138_memory_navigate.py +0 -0
  234. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_139_tool_probe.py +0 -0
  235. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_183_card_anchor.py +0 -0
  236. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_184_notify_honesty.py +0 -0
  237. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_201_win32_bash_refusal.py +0 -0
  238. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_243_onboard_per_peer_token.py +0 -0
  239. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_307_task4_ask_reply.py +0 -0
  240. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  241. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_319_refusal_exit_codes.py +0 -0
  242. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_323_mistral_backend.py +0 -0
  243. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_332_report_organize_findings.py +0 -0
  244. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_356_query_filters.py +0 -0
  245. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_397_gh_identity_router.py +0 -0
  246. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_397_router_preflight.py +0 -0
  247. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_402_one_identity_resolver.py +0 -0
  248. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_432_rowclear.py +0 -0
  249. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_467b_onboard_operator_credential.py +0 -0
  250. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_472_register_caller_binding.py +0 -0
  251. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_484_codex_queue_sink.py +0 -0
  252. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_523_guide.py +0 -0
  253. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_524_conftest_hermeticity.py +0 -0
  254. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_532_accept_flag.py +0 -0
  255. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_535_version_capability.py +0 -0
  256. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_538_signal_bench.py +0 -0
  257. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_546_default_gateway.py +0 -0
  258. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_547_verbs_from_registry.py +0 -0
  259. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_548_gateway_remainder.py +0 -0
  260. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_552_codegraph_gateway.py +0 -0
  261. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_555_relay_row_shape.py +0 -0
  262. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_556_relay_freshness.py +0 -0
  263. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_559_edges_truncated.py +0 -0
  264. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_564_bootstrap_first_peer.py +0 -0
  265. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  266. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_579_register_bootstrap_message.py +0 -0
  267. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_591_cli_step_graph.py +0 -0
  268. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_644_monitor_supervision.py +0 -0
  269. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_648_install_unit.py +0 -0
  270. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_654_reexec.py +0 -0
  271. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_656_owned_slm.py +0 -0
  272. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_684_dreaming_verb.py +0 -0
  273. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_689_pkg_version_order.py +0 -0
  274. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_715_grok_wake.py +0 -0
  275. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_716_timeline_one_path.py +0 -0
  276. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_723_grok_0251.py +0 -0
  277. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_724_ps1_ascii_or_bom.py +0 -0
  278. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_725_stdio_reconfigure.py +0 -0
  279. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_726_grok_limit_screen.py +0 -0
  280. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_729_arm_check_delivery_gap.py +0 -0
  281. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_729_dm_once.py +0 -0
  282. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_734_dreaming_enrich_degrade.py +0 -0
  283. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_735_dm_mcp_tools.py +0 -0
  284. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_739_wake_writer.py +0 -0
  285. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_740_edit_project.py +0 -0
  286. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_762_cards_edit_priority.py +0 -0
  287. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_764_enrich_collapse.py +0 -0
  288. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_801_confirm_flow_cli.py +0 -0
  289. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_802_stage_history.py +0 -0
  290. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_825_codegraph_hook_noise.py +0 -0
  291. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_825_install_posttooluse_only.py +0 -0
  292. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_825_remaining_cap_shred_bind.py +0 -0
  293. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_829_counterfactual_column.py +0 -0
  294. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_830_hook_binding_version.py +0 -0
  295. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_84_cli_labels.py +0 -0
  296. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_866_doctrine_guide.py +0 -0
  297. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_872_identity_refuses_not_warns.py +0 -0
  298. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_874_source_text.py +0 -0
  299. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
  300. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_937_dreaming_notify.py +0 -0
  301. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_938_organize_line_limit.py +0 -0
  302. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_941_bench_backends.py +0 -0
  303. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_941_harness_342.py +0 -0
  304. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_945_same_line_pairing.py +0 -0
  305. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_955_prompt_audit.py +0 -0
  306. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_957_auth_http.py +0 -0
  307. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_959_venv_interpreter.py +0 -0
  308. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_960_channel.py +0 -0
  309. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
  310. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_961_cursor_grok_footer.py +0 -0
  311. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_961_loud_stop.py +0 -0
  312. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_963_plugin_manifest.py +0 -0
  313. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_964_channel_cell.py +0 -0
  314. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_965_mesh_wait.py +0 -0
  315. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_975_channel_hop.py +0 -0
  316. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_add_security_gate.py +0 -0
  317. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_add.py +0 -0
  318. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_hash.py +0 -0
  319. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_lib.py +0 -0
  320. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_mcp.py +0 -0
  321. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_skill.py +0 -0
  322. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_tool.py +0 -0
  323. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_uri.py +0 -0
  324. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_backends.py +0 -0
  325. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_claude_cli.py +0 -0
  326. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_codex_cli.py +0 -0
  327. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_command.py +0 -0
  328. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_pack.py +0 -0
  329. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_prices.py +0 -0
  330. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_quality.py +0 -0
  331. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_runner.py +0 -0
  332. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_board_card_thread.py +0 -0
  333. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_board_command.py +0 -0
  334. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_board_merge_check.py +0 -0
  335. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_board_obligation_close.py +0 -0
  336. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_brain_ask_command.py +0 -0
  337. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_brain_ask_env_diagnosis.py +0 -0
  338. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_brain_ask_identity_explicitness.py +0 -0
  339. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_brain_command.py +0 -0
  340. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_caller_meta_guard.py +0 -0
  341. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_capture_lineage.py +0 -0
  342. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_capture_liveness.py +0 -0
  343. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_capture_manifest.py +0 -0
  344. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_capture_paths.py +0 -0
  345. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_capture_security.py +0 -0
  346. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cell_command_dispatch.py +0 -0
  347. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cell_harden.py +0 -0
  348. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cell_loader.py +0 -0
  349. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cell_selfcheck.py +0 -0
  350. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cell_verify.py +0 -0
  351. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_chain_token.py +0 -0
  352. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_channel_command.py +0 -0
  353. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  354. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_channel_post.py +0 -0
  355. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_channel_wake_policy_filter.py +0 -0
  356. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_chat_command.py +0 -0
  357. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_claude_parser.py +0 -0
  358. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_claude_tmux_template.py +0 -0
  359. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_codegraph_caller_scope.py +0 -0
  360. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_codegraph_command.py +0 -0
  361. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_codegraph_hook.py +0 -0
  362. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_codegraph_mcp.py +0 -0
  363. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_codex_waker.py +0 -0
  364. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_compress_caller_convention.py +0 -0
  365. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_compress_command.py +0 -0
  366. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_compress_levers.py +0 -0
  367. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_compress_marker.py +0 -0
  368. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_compress_verify.py +0 -0
  369. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_console_encoding_e2e.py +0 -0
  370. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_content_composition.py +0 -0
  371. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_copilot_membrane.py +0 -0
  372. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_copilot_pane_reader.py +0 -0
  373. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cursor_membrane.py +0 -0
  374. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_daemon_command.py +0 -0
  375. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_daemon_console_encoding.py +0 -0
  376. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_daemon_delivery.py +0 -0
  377. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_delivery_queue.py +0 -0
  378. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_display_sanitize.py +0 -0
  379. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  380. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_event_emit.py +0 -0
  381. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_feature_to_uri.py +0 -0
  382. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_gateway_brain.py +0 -0
  383. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_gateway_client.py +0 -0
  384. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_gateway_command.py +0 -0
  385. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_gateway_message_idempotency.py +0 -0
  386. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  387. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_group_command.py +0 -0
  388. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_guide_commands_parse.py +0 -0
  389. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_guide_selfcheck.py +0 -0
  390. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_heartbeat_check.py +0 -0
  391. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_highlight_command.py +0 -0
  392. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hook_output.py +0 -0
  393. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_activity_marker.py +0 -0
  394. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_add.py +0 -0
  395. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_bundle.py +0 -0
  396. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_init.py +0 -0
  397. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_legacy_generation_removal.py +0 -0
  398. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_lifecycle.py +0 -0
  399. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_merge.py +0 -0
  400. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_verify.py +0 -0
  401. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  402. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_win32_command_path.py +0 -0
  403. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_import_command.py +0 -0
  404. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_inbox_identity_provenance.py +0 -0
  405. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_init_command.py +0 -0
  406. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_init_provider_menu.py +0 -0
  407. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_install_codex_hooks.py +0 -0
  408. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_install_hook.py +0 -0
  409. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_install_multiplexer_command.py +0 -0
  410. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_install_postcompact_hook.py +0 -0
  411. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_install_wake_hook.py +0 -0
  412. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_lane_command.py +0 -0
  413. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_main.py +0 -0
  414. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_main_unknown_verb_guard.py +0 -0
  415. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mcp_missing_hint.py +0 -0
  416. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mcp_server.py +0 -0
  417. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_memory_command.py +0 -0
  418. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_memory_emit_snippet.py +0 -0
  419. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_memory_gateway.py +0 -0
  420. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_memory_sync.py +0 -0
  421. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_memory_sync_membrane.py +0 -0
  422. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_command.py +0 -0
  423. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_inbox_mark_read.py +0 -0
  424. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_inbox_sanitize.py +0 -0
  425. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_originate_thread_623.py +0 -0
  426. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_send_unknown_peer.py +0 -0
  427. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_sidecar.py +0 -0
  428. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  429. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_sidecar_muse_sink.py +0 -0
  430. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  431. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_meta_edge_identity.py +0 -0
  432. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_monitor_channel_poll.py +0 -0
  433. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_monitor_cli.py +0 -0
  434. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_monitor_daemon_collision.py +0 -0
  435. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_monitor_self_name_verification.py +0 -0
  436. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_monitor_state_split.py +0 -0
  437. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_multiplexer.py +0 -0
  438. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_muse_membrane.py +0 -0
  439. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_muse_own_cli.py +0 -0
  440. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_obligation_close_is_surfaced.py +0 -0
  441. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_okf_links.py +0 -0
  442. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_onboard_command.py +0 -0
  443. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_opencode_membrane.py +0 -0
  444. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_opencode_plugin.py +0 -0
  445. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_operator_me.py +0 -0
  446. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_orphan_daemons.py +0 -0
  447. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_packaged_artifacts_exist.py +0 -0
  448. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_packaged_skills.py +0 -0
  449. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_executor.py +0 -0
  450. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_executor_windows.py +0 -0
  451. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_reply_drain_command.py +0 -0
  452. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_reply_drain_supervisor.py +0 -0
  453. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_reply_outbox.py +0 -0
  454. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_reply_transport.py +0 -0
  455. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_service_e2e.py +0 -0
  456. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_service_host.py +0 -0
  457. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_service_payload.py +0 -0
  458. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_service_reply.py +0 -0
  459. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_postcompact_recall.py +0 -0
  460. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_process_liveness.py +0 -0
  461. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_protocol_handler.py +0 -0
  462. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_providers_isolation.py +0 -0
  463. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_ratify_command.py +0 -0
  464. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_readme_claims_no_gateway_default.py +0 -0
  465. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_repl_caller_convention.py +0 -0
  466. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_schedule_command.py +0 -0
  467. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_schedule_create_contract.py +0 -0
  468. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_scrub.py +0 -0
  469. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_security.py +0 -0
  470. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_service_app.py +0 -0
  471. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_service_command.py +0 -0
  472. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_service_providers.py +0 -0
  473. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_session_bridge_inject.py +0 -0
  474. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_session_bridge_probe.py +0 -0
  475. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_session_bridge_resolve.py +0 -0
  476. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_session_path_role_gate.py +0 -0
  477. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_shipped_units_match_the_cli.py +0 -0
  478. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_smoke_chat.py +0 -0
  479. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_smoke_one_shot.py +0 -0
  480. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_smoke_phase_5_5.py +0 -0
  481. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_base_hoist.py +0 -0
  482. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_command.py +0 -0
  483. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_identity_stamp.py +0 -0
  484. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_live_pin.py +0 -0
  485. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_mitosis_lineage.py +0 -0
  486. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_tmux_session.py +0 -0
  487. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_windows_relaunch.py +0 -0
  488. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_stall_alert.py +0 -0
  489. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_subprocess_decode_encoding.py +0 -0
  490. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_timeline_command.py +0 -0
  491. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_tmux_wake_runstate_defer.py +0 -0
  492. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_tmux_wake_session_reanchor.py +0 -0
  493. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_tmux_wake_stale.py +0 -0
  494. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_tmux_wake_submit_verify.py +0 -0
  495. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_token_file_one_parser.py +0 -0
  496. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_token_precedence_explicit_first.py +0 -0
  497. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_unified_token_resolver.py +0 -0
  498. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_version_command.py +0 -0
  499. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_version_consistency.py +0 -0
  500. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_vibe_membrane.py +0 -0
  501. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog.py +0 -0
  502. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_dm_wake.py +0 -0
  503. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  504. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  505. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_emit_health.py +0 -0
  506. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_install_flags.py +0 -0
  507. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_model_rung.py +0 -0
  508. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_stale_peers.py +0 -0
  509. {swarph_cli-0.72.18 → swarph_cli-0.72.20}/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.18
3
+ Version: 0.72.20
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.18"
7
+ version = "0.72.20"
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.18"
19
+ __version__ = "0.72.20"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -99,3 +99,23 @@ def load_registry(path: str | Path | None) -> dict[str, dict]:
99
99
  raw = Path(path).read_text(encoding="utf-8")
100
100
  data = tomllib.loads(raw)
101
101
  return {name: _check(name, entry) for name, entry in data.items()}
102
+
103
+
104
+ def provider_arm(name: str, entry: dict, noul_threshold):
105
+ """The registry arm for ``provider:<name>``.
106
+
107
+ ``kind = "decisions"`` is the OpenAI Decisions translator. ``typed`` and
108
+ ``semantic`` stay on :class:`~swarph_cli.bench.backends.HttpBackend`,
109
+ which posts a typed pack body unchanged.
110
+ """
111
+ from .backends import DecisionsBackend, HttpBackend
112
+
113
+ common = dict(
114
+ name=name, base_url=entry["base_url"], path=entry["path"],
115
+ auth=entry.get("auth"), usage=entry.get("usage"),
116
+ price=entry.get("price"), egress=entry["egress"],
117
+ noul_threshold=noul_threshold,
118
+ )
119
+ if entry["kind"] == "decisions":
120
+ return DecisionsBackend(**common)
121
+ return HttpBackend(kind=entry["kind"], **common)
@@ -22,7 +22,7 @@ import json
22
22
  from .backends import Backend
23
23
  from .pack import validate_schema
24
24
  from .quality import d_text
25
- from .runner import ModelSpec, preflight, run_pack
25
+ from .runner import ModelSpec, parse_models, preflight, run_pack
26
26
 
27
27
  DISCRIMINATION_MIN_SPREAD = 0.05 # min stdev of mean_distance across reference models
28
28
  # Conservative: text prompts and their expected answers naturally share topical
@@ -199,13 +199,48 @@ CALIBRATION_NOTICE = (
199
199
  )
200
200
 
201
201
 
202
- def gate_calibration(pack: dict, backends: Optional[dict[str, Backend]] = None) -> list[str]:
202
+ def _calibration_spec(model: str, pack: dict, registry: Optional[dict]):
203
+ """One spec from the same grammar ``--models`` uses.
204
+
205
+ ``provider:<name>`` is not runnable until its registry arm is attached.
206
+ A bare id stays on the metered default, which is what ``parse_models``
207
+ already does — this does not reimplement that split.
208
+ """
209
+ from .providers import RegistryError, load_registry, provider_arm, registry_path
210
+
211
+ specs = parse_models(model)
212
+ if len(specs) != 1:
213
+ return None
214
+ spec = specs[0]
215
+ if spec.backend != "provider":
216
+ return spec
217
+ try:
218
+ if registry is None:
219
+ registry = load_registry(registry_path())
220
+ except (OSError, RegistryError) as exc:
221
+ raise RegistryError(str(exc)) from exc
222
+ entry = (registry or {}).get(spec.provider)
223
+ if entry is not None:
224
+ spec.arm = provider_arm(spec.provider, entry, pack.get("noul_threshold"))
225
+ return spec
226
+
227
+
228
+ def gate_calibration(
229
+ pack: dict,
230
+ backends: Optional[dict[str, Backend]] = None,
231
+ *,
232
+ registry: Optional[dict] = None,
233
+ ) -> list[str]:
203
234
  """ALWAYS emits the context-calibration requirement as a warning (§5d is
204
235
  guidance, not automatable in full). If the pack declares
205
236
  ``meta.calibration`` ({model, task_ids, expected_mean_distance_max}),
206
237
  additionally checks that the declared model+system reproduces it — full
207
238
  standardization of this format is DEFERRED (decision #4); this is the
208
- minimal v1 check."""
239
+ minimal v1 check.
240
+
241
+ ``meta.calibration.model`` is one ``parse_models`` token: ``id[:backend[:label]]``
242
+ or ``provider:<name>``. A bare id keeps the metered backend.
243
+ """
209
244
  warnings = [CALIBRATION_NOTICE]
210
245
  calib = (pack.get("meta") or {}).get("calibration")
211
246
  if not calib:
@@ -214,7 +249,7 @@ def gate_calibration(pack: dict, backends: Optional[dict[str, Backend]] = None)
214
249
  model = calib.get("model")
215
250
  task_ids = calib.get("task_ids")
216
251
  expected_max = calib.get("expected_mean_distance_max")
217
- if not (model and task_ids and expected_max is not None):
252
+ if not (isinstance(model, str) and model.strip() and task_ids and expected_max is not None):
218
253
  warnings.append(
219
254
  "meta.calibration is present but malformed (need model, task_ids, "
220
255
  "expected_mean_distance_max) — skipping the reproduction check"
@@ -229,10 +264,26 @@ def gate_calibration(pack: dict, backends: Optional[dict[str, Backend]] = None)
229
264
  )
230
265
  return warnings
231
266
 
232
- runnable, preflight_warnings = preflight([ModelSpec(id=model)], backends)
267
+ from .providers import RegistryError
268
+
269
+ try:
270
+ spec = _calibration_spec(model, pack, registry)
271
+ except RegistryError as exc:
272
+ warnings.append(f"meta.calibration provider registry unreadable: {exc}")
273
+ return warnings
274
+ if spec is None:
275
+ warnings.append(
276
+ f"meta.calibration model={model!r} must be one model spec "
277
+ f"(id[:backend[:label]] or provider:<name>) — skipping the reproduction check"
278
+ )
279
+ return warnings
280
+
281
+ runnable, preflight_warnings = preflight([spec], backends, pack=pack)
233
282
  warnings.extend(preflight_warnings)
234
283
  if not runnable:
235
- warnings.append(f"meta.calibration check could not run: {model!r} lacks credentials")
284
+ # The preflight warning already names the refusal (credentials, kind
285
+ # mismatch, on_box_only egress). A second "lacks credentials" line
286
+ # mislabels every other refusal as a missing key.
236
287
  return warnings
237
288
 
238
289
  result = run_pack(runnable, pack, backends, task_ids=task_ids)
@@ -32,7 +32,6 @@ from swarph_cli.bench.backends import (
32
32
  SubscriptionBackend,
33
33
  TypedHttpBackend,
34
34
  HttpBackend,
35
- DecisionsBackend,
36
35
  )
37
36
  from swarph_cli.bench.pack import PackError, load_pack, slugify_theme, validate_schema
38
37
  from swarph_cli.bench.providers import RegistryError, load_registry, registry_path
@@ -223,21 +222,9 @@ def _default_packs_dir() -> Path:
223
222
 
224
223
 
225
224
  def _provider_arm(name: str, entry: dict, noul_threshold):
226
- """The registry arm for ``provider:<name>``.
227
-
228
- ``kind = "decisions"`` is the OpenAI Decisions translator. ``typed`` and
229
- ``semantic`` stay on :class:`HttpBackend`, which posts a typed pack body
230
- unchanged.
231
- """
232
- common = dict(
233
- name=name, base_url=entry["base_url"], path=entry["path"],
234
- auth=entry.get("auth"), usage=entry.get("usage"),
235
- price=entry.get("price"), egress=entry["egress"],
236
- noul_threshold=noul_threshold,
237
- )
238
- if entry["kind"] == "decisions":
239
- return DecisionsBackend(**common)
240
- return HttpBackend(kind=entry["kind"], **common)
225
+ """The registry arm for ``provider:<name>``. Same constructor validate uses."""
226
+ from swarph_cli.bench.providers import provider_arm
227
+ return provider_arm(name, entry, noul_threshold)
241
228
 
242
229
 
243
230
  # ── dispatch ───────────────────────────────────────────────────────────────
@@ -14,6 +14,7 @@ from pathlib import Path
14
14
  from typing import Iterable
15
15
 
16
16
  GAP_SECONDS = 60
17
+ WAIT_REARM_GRACE = 600
17
18
 
18
19
 
19
20
  def writer_verdict(*, reader_alive: bool, monitor_rc: int) -> str:
@@ -132,16 +133,33 @@ def _channel_alive(inbox: str, now: float | None = None) -> bool:
132
133
  return (time.time() if now is None else now) - ts < 180
133
134
 
134
135
 
136
+ def _waiter_just_delivered(inbox: str, now: float | None = None) -> bool:
137
+ """`swarph mesh wait --once` writes wait_cursor.json beside the inbox when it
138
+ delivers, then exits. The cell re-arms only after acting on the DM, which can
139
+ take minutes; inside that window no waiter is running but the wake is not dead.
140
+ """
141
+ try:
142
+ mtime = (Path(inbox).parent / "wait_cursor.json").stat().st_mtime
143
+ except OSError:
144
+ return False
145
+ age = (time.time() if now is None else now) - mtime
146
+ return 0 <= age < WAIT_REARM_GRACE # a future mtime is not a delivery
147
+
148
+
135
149
  def _watching(inbox: str, cmdlines: Iterable[str]) -> bool:
136
150
  """A reader is tail or dm_notify_filter with the inbox path as its own argument,
137
- or a channel server whose heartbeat is fresh.
151
+ a channel server whose heartbeat is fresh, or a one-shot `swarph mesh wait`
152
+ for this cell (running, or delivered within WAIT_REARM_GRACE).
138
153
 
139
154
  A process that merely mentions the path (a prompt, a log line) is not a reader.
140
155
  """
141
- if _channel_alive(inbox):
156
+ if _channel_alive(inbox) or _waiter_just_delivered(inbox):
142
157
  return True
158
+ cell = Path(inbox).parent.parent.name
143
159
  for cmd in cmdlines:
144
160
  parts = cmd.split()
161
+ if _waits_on(parts, cell):
162
+ return True
145
163
  if inbox not in parts:
146
164
  continue
147
165
  if any(os.path.basename(p) == "tail" for p in parts):
@@ -151,6 +169,27 @@ def _watching(inbox: str, cmdlines: Iterable[str]) -> bool:
151
169
  return False
152
170
 
153
171
 
172
+ def _waits_on(parts: list[str], cell: str) -> bool:
173
+ """`swarph mesh wait --once --as <cell>` names the cell, not the inbox path.
174
+
175
+ copilot wakes on this waiter's exit (card #387). The process must BE swarph
176
+ (argv[0], or argv[1] after an interpreter), so a prompt that quotes the
177
+ command is not a reader.
178
+ """
179
+ for i in (0, 1):
180
+ if len(parts) < i + 3 or os.path.basename(parts[i]) != "swarph":
181
+ continue
182
+ if i == 1 and not os.path.basename(parts[0]).startswith("python"):
183
+ continue
184
+ if parts[i + 1:i + 3] != ["mesh", "wait"]:
185
+ continue
186
+ rest = parts[i + 3:]
187
+ named = f"--as={cell}" in rest or any(
188
+ a == "--as" and b == cell for a, b in zip(rest, rest[1:]))
189
+ return "--once" in rest and named
190
+ return False
191
+
192
+
154
193
  def _cron_watched(name: str, crontab: str) -> bool:
155
194
  """An active crontab line that runs dm_wake.py for this cell is its poller."""
156
195
  for line in crontab.splitlines():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swarph-cli
3
- Version: 0.72.18
3
+ Version: 0.72.20
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
@@ -240,3 +240,54 @@ def test_a_channel_cell_with_a_fresh_heartbeat_is_watched(tmp_path):
240
240
  hb.write_text(json.dumps({"pid": 1, "ts": _t.time() - 600})) # server died 10 min ago
241
241
  assert scan(cells, channel_ps, state, now=130) == []
242
242
  assert scan(cells, channel_ps, state, now=200) == ["drop"]
243
+
244
+
245
+ def test_a_one_shot_mesh_wait_for_the_cell_is_a_watcher(tmp_path):
246
+ """Live 2026-10-12 23:34Z: copilot wakes on `swarph mesh wait --once` exiting (card #387,
247
+ probe 69717), and that command line names the cell, not the inbox path, so the watchdog
248
+ paged copilot 'DM wake is dead' (msgs 69720/69721). Fails on main.
249
+ tmp_path, not the live path: a live wait_cursor.json would count as watched."""
250
+ inbox = str(tmp_path / "copilot" / "mesh-sidecar" / "inbox.log")
251
+ cells = {"copilot": inbox}
252
+ waiter = ["/usr/bin/python3 /home/ubuntu/.local/bin/swarph mesh wait --once --as copilot --max-wait-s 1500"]
253
+ state = {}
254
+ assert scan(cells, waiter, state, now=0) == []
255
+ assert scan(cells, waiter, state, now=120) == []
256
+ assert scan(cells, ["swarph mesh wait --once --as=copilot"], {}, now=120) == []
257
+ other = ["/usr/bin/python3 /home/ubuntu/.local/bin/swarph mesh wait --once --as lab-ovh"]
258
+ quoted = ["claude -p run swarph mesh wait --once --as copilot then reply"]
259
+ no_once = ["/home/ubuntu/.local/bin/swarph mesh wait --as copilot"]
260
+ # drop-on-meta-edge #1682: argv[1] counted without checking argv[0] is an interpreter.
261
+ echo = ["echo swarph mesh wait --once --as copilot"]
262
+ grep = ["grep swarph mesh wait --once --as copilot notes.txt"]
263
+ claude = ["claude swarph mesh wait --once --as copilot and report"]
264
+ for listing in (other, quoted, no_once, echo, grep, claude):
265
+ st = {}
266
+ assert scan(cells, listing, st, now=0) == []
267
+ assert scan(cells, listing, st, now=120) == ["copilot"], listing
268
+
269
+
270
+ def test_the_re_arm_gap_after_a_one_shot_delivery_is_not_an_outage(tmp_path):
271
+ """The waiter exits on delivery and copilot re-arms only after acting on the DM;
272
+ a turn longer than GAP_SECONDS paged copilot under the waiter-only fix. A cursor
273
+ written 30 s ago covers the gap; one written 700 s ago does not."""
274
+ import os, time
275
+ inbox = tmp_path / "copilot" / "mesh-sidecar" / "inbox.log"
276
+ inbox.parent.mkdir(parents=True)
277
+ inbox.write_text("")
278
+ cursor = inbox.parent / "wait_cursor.json"
279
+ cursor.write_text('{"last_delivered_id": 69717}')
280
+ cells = {"copilot": str(inbox)}
281
+ t = time.time()
282
+ os.utime(cursor, (t - 30, t - 30))
283
+ st = {}
284
+ assert scan(cells, [], st, now=0) == []
285
+ assert scan(cells, [], st, now=120) == []
286
+ os.utime(cursor, (t - 700, t - 700))
287
+ st = {}
288
+ assert scan(cells, [], st, now=0) == []
289
+ assert scan(cells, [], st, now=120) == ["copilot"]
290
+ os.utime(cursor, (t + 3600, t + 3600)) # #1682: a future mtime hid the outage unboundedly
291
+ st = {}
292
+ assert scan(cells, [], st, now=0) == []
293
+ assert scan(cells, [], st, now=120) == ["copilot"]
@@ -294,7 +294,147 @@ def test_calibration_missing_creds_flagged_gracefully():
294
294
  return ["SOME_KEY"]
295
295
 
296
296
  warnings = gate_calibration(p, backends={"metered": NoCreds()})
297
- assert any("lacks credentials" in w for w in warnings)
297
+ assert any("requires SOME_KEY" in w and "skipped" in w for w in warnings)
298
+ assert not any("lacks credentials" in w for w in warnings)
299
+
300
+
301
+ class _Recording:
302
+ def __init__(self, inner):
303
+ self.inner = inner
304
+ self.calls = []
305
+
306
+ def generate(self, model_id, prompt, system=""):
307
+ self.calls.append(model_id)
308
+ return self.inner.generate(model_id, prompt, system)
309
+
310
+ def missing_creds(self):
311
+ return []
312
+
313
+
314
+ def test_calibration_subscription_backend_is_called():
315
+ p = _pack(meta={"calibration": {
316
+ "model": "m:subscription",
317
+ "task_ids": ["arith_mult"],
318
+ "expected_mean_distance_max": 0.1,
319
+ }})
320
+ subscription = _Recording(ScriptedBackend(PERFECT_ANSWERS))
321
+ metered = _Recording(ScriptedBackend({}))
322
+ warnings = gate_calibration(p, backends={"subscription": subscription, "metered": metered})
323
+ assert subscription.calls == ["m"]
324
+ assert metered.calls == []
325
+ assert any("meta.calibration OK" in w or "MISMATCH" in w for w in warnings)
326
+ assert not any("could not run" in w for w in warnings)
327
+
328
+
329
+ def test_calibration_bare_id_binds_metered_backend():
330
+ p = _pack(meta={"calibration": {
331
+ "model": "bare-id",
332
+ "task_ids": ["arith_mult"],
333
+ "expected_mean_distance_max": 0.1,
334
+ }})
335
+ subscription = _Recording(ScriptedBackend(PERFECT_ANSWERS))
336
+ metered = _Recording(ScriptedBackend(PERFECT_ANSWERS))
337
+ warnings = gate_calibration(p, backends={"subscription": subscription, "metered": metered})
338
+ assert metered.calls == ["bare-id"]
339
+ assert subscription.calls == []
340
+ assert any("meta.calibration OK" in w for w in warnings)
341
+
342
+
343
+ def test_calibration_provider_resolves_registry_arm(monkeypatch):
344
+ from swarph_cli.bench import providers as providers_mod
345
+ from swarph_cli.bench.backends import HttpBackend
346
+
347
+ built = []
348
+ seen = []
349
+ real = providers_mod.provider_arm
350
+
351
+ def wrapped(name, entry, noul):
352
+ arm = real(name, entry, noul)
353
+ built.append((name, entry, arm))
354
+ inner = ScriptedBackend(PERFECT_ANSWERS)
355
+
356
+ def generate(model_id, prompt, system=""):
357
+ seen.append(model_id)
358
+ return inner.generate(model_id, prompt, system)
359
+
360
+ arm.generate = generate
361
+ return arm
362
+
363
+ monkeypatch.setattr(providers_mod, "provider_arm", wrapped)
364
+ entry = {
365
+ "kind": "typed",
366
+ "base_url": "http://127.0.0.1:9",
367
+ "path": "/v1/systemone",
368
+ "egress": "local",
369
+ }
370
+ p = _pack(meta={"calibration": {
371
+ "model": "provider:openai",
372
+ "task_ids": ["arith_mult"],
373
+ "expected_mean_distance_max": 0.1,
374
+ }})
375
+ metered = _Recording(ScriptedBackend(PERFECT_ANSWERS))
376
+ warnings = gate_calibration(
377
+ p, backends={"metered": metered}, registry={"openai": entry},
378
+ )
379
+ assert built and built[0][0] == "openai" and built[0][1] is entry
380
+ assert isinstance(built[0][2], HttpBackend)
381
+ assert seen == ["openai"]
382
+ assert metered.calls == []
383
+ assert any("meta.calibration OK" in w or "MISMATCH" in w for w in warnings)
384
+ assert not any("could not run" in w for w in warnings)
385
+
386
+
387
+ def test_calibration_on_box_only_refuses_external_provider(monkeypatch):
388
+ from swarph_cli.bench import providers as providers_mod
389
+
390
+ calls = []
391
+ real = providers_mod.provider_arm
392
+
393
+ def wrapped(name, entry, noul):
394
+ arm = real(name, entry, noul)
395
+
396
+ def generate(model_id, prompt, system=""):
397
+ calls.append(model_id)
398
+ raise AssertionError("external arm must not be dispatched")
399
+
400
+ arm.generate = generate
401
+ return arm
402
+
403
+ monkeypatch.setattr(providers_mod, "provider_arm", wrapped)
404
+ entry = {
405
+ "kind": "typed",
406
+ "base_url": "https://api.example.com",
407
+ "path": "/v1/systemone",
408
+ "egress": "external",
409
+ }
410
+ p = _pack(
411
+ egress="on_box_only",
412
+ meta={"calibration": {
413
+ "model": "provider:openai",
414
+ "task_ids": ["arith_mult"],
415
+ "expected_mean_distance_max": 0.1,
416
+ }},
417
+ )
418
+ warnings = gate_calibration(p, backends={}, registry={"openai": entry})
419
+ assert calls == []
420
+ assert any("on_box_only" in w and "external" in w for w in warnings)
421
+ assert not any("lacks credentials" in w for w in warnings)
422
+
423
+
424
+ def test_calibration_kind_mismatch_refuses_the_arm():
425
+ p = _pack(
426
+ request_kind="typed",
427
+ meta={"calibration": {
428
+ "model": "m:subscription",
429
+ "task_ids": ["arith_mult"],
430
+ "expected_mean_distance_max": 0.1,
431
+ }},
432
+ )
433
+ subscription = _Recording(ScriptedBackend(PERFECT_ANSWERS))
434
+ warnings = gate_calibration(p, backends={"subscription": subscription})
435
+ assert subscription.calls == []
436
+ assert any("kind mismatch: pack=typed arm=semantic" in w for w in warnings)
437
+ assert not any("lacks credentials" in w for w in warnings)
298
438
 
299
439
 
300
440
  # ── orchestration: validate_pack ───────────────────────────────────────────
File without changes
File without changes
File without changes