swarph-cli 0.65.0__tar.gz → 0.66.0__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 (423) hide show
  1. {swarph_cli-0.65.0/src/swarph_cli.egg-info → swarph_cli-0.66.0}/PKG-INFO +2 -2
  2. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/README.md +1 -1
  3. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/pyproject.toml +1 -1
  4. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/__init__.py +1 -1
  5. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/bench/backends.py +223 -2
  6. swarph_cli-0.66.0/src/swarph_cli/bench/rules.py +40 -0
  7. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/bench/runner.py +12 -5
  8. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/bench.py +4 -0
  9. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/board.py +3 -1
  10. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/brain_ask.py +1 -1
  11. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/mcp_server.py +194 -15
  12. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/monitor.py +84 -22
  13. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/wake_hook_output.py +3 -5
  14. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/compress/levers.py +1 -1
  15. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/compress/verify.py +9 -5
  16. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/candidates.py +19 -5
  17. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-monitor-reexec.path +5 -0
  18. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-monitor-reexec.service +8 -1
  19. {swarph_cli-0.65.0 → swarph_cli-0.66.0/src/swarph_cli.egg-info}/PKG-INFO +2 -2
  20. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli.egg-info/SOURCES.txt +6 -0
  21. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_654_reexec.py +154 -20
  22. swarph_cli-0.66.0/tests/test_735_dm_mcp_tools.py +173 -0
  23. swarph_cli-0.66.0/tests/test_941_bench_backends.py +136 -0
  24. swarph_cli-0.66.0/tests/test_941_harness_342.py +114 -0
  25. swarph_cli-0.66.0/tests/test_945_same_line_pairing.py +116 -0
  26. swarph_cli-0.66.0/tests/test_955_prompt_audit.py +60 -0
  27. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_board_command.py +13 -1
  28. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/LICENSE +0 -0
  29. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/setup.cfg +0 -0
  30. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/__main__.py +0 -0
  31. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/bench/__init__.py +0 -0
  32. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/bench/pack.py +0 -0
  33. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/bench/prices.py +0 -0
  34. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/bench/quality.py +0 -0
  35. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/bench/refresh_prices.py +0 -0
  36. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/bench/validate.py +0 -0
  37. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/caller.py +0 -0
  38. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/capture/__init__.py +0 -0
  39. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/capture/harden.py +0 -0
  40. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/capture/lineage.py +0 -0
  41. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/capture/liveness.py +0 -0
  42. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/capture/manifest.py +0 -0
  43. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/capture/paths.py +0 -0
  44. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/capture/verify.py +0 -0
  45. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/cell.py +0 -0
  46. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/chain_token.py +0 -0
  47. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/__init__.py +0 -0
  48. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/_content.py +0 -0
  49. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/_display.py +0 -0
  50. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/_gateway_client.py +0 -0
  51. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/add.py +0 -0
  52. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/board_merge_check.py +0 -0
  53. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/brain.py +0 -0
  54. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/cell.py +0 -0
  55. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/cell_probe.py +0 -0
  56. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  57. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/channel.py +0 -0
  58. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/chat.py +0 -0
  59. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/codegraph.py +0 -0
  60. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/codegraph_hook.py +0 -0
  61. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  62. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/codex_waker.py +0 -0
  63. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/compress.py +0 -0
  64. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/daemon.py +0 -0
  65. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/dreaming.py +0 -0
  66. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/event.py +0 -0
  67. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/gateway.py +0 -0
  68. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/gh_route.py +0 -0
  69. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/group.py +0 -0
  70. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/guide.py +0 -0
  71. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/highlight.py +0 -0
  72. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/hook_output.py +0 -0
  73. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/hooks.py +0 -0
  74. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/import_session.py +0 -0
  75. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/init.py +0 -0
  76. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  77. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/install_hook.py +0 -0
  78. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  79. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
  80. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
  81. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  82. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/lane.py +0 -0
  83. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/memory.py +0 -0
  84. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
  85. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/memory_sync.py +0 -0
  86. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/mesh.py +0 -0
  87. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/okf_links.py +0 -0
  88. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/onboard.py +0 -0
  89. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  90. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  91. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/protocol_handler.py +0 -0
  92. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/ratify.py +0 -0
  93. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/schedule.py +0 -0
  94. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/security.py +0 -0
  95. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/service.py +0 -0
  96. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/spawn.py +0 -0
  97. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/timeline.py +0 -0
  98. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/version.py +0 -0
  99. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/commands/watchdog.py +0 -0
  100. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/compress/__init__.py +0 -0
  101. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/compress/marker.py +0 -0
  102. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/console_safe.py +0 -0
  103. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/delivery_queue.py +0 -0
  104. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/__init__.py +0 -0
  105. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/clone.py +0 -0
  106. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/enrich.py +0 -0
  107. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/index_check.py +0 -0
  108. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/notify.py +0 -0
  109. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/organize.py +0 -0
  110. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/probes.py +0 -0
  111. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/report.py +0 -0
  112. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/run.py +0 -0
  113. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/slm.py +0 -0
  114. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/transcripts.py +0 -0
  115. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/dreaming/verify.py +0 -0
  116. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/gateway/__init__.py +0 -0
  117. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/gateway/feature_registry.py +0 -0
  118. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/gateway/lanes_control.py +0 -0
  119. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/gateway/schema.sql +0 -0
  120. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/gateway/server.py +0 -0
  121. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/gateway/services_control.py +0 -0
  122. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/gateway_default.py +0 -0
  123. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/gh_identity.py +0 -0
  124. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/guide/GUIDE.md +0 -0
  125. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/main.py +0 -0
  126. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/multiplexer.py +0 -0
  127. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/orphan_daemons.py +0 -0
  128. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/pane_probe.py +0 -0
  129. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/parsers/__init__.py +0 -0
  130. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/parsers/claude.py +0 -0
  131. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
  132. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  133. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  134. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  135. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  136. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  137. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  138. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  139. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  140. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  141. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  142. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  143. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/peer_executor.py +0 -0
  144. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/peer_executor_windows.py +0 -0
  145. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/peer_reconciliation.py +0 -0
  146. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/peer_reply_outbox.py +0 -0
  147. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/peer_service_host.py +0 -0
  148. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/peer_service_payload.py +0 -0
  149. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/peer_service_reply.py +0 -0
  150. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/peer_staging.py +0 -0
  151. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/query_filters.py +0 -0
  152. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/scripts/__init__.py +0 -0
  153. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  154. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  155. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  156. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  157. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/service/__init__.py +0 -0
  158. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/service/app.py +0 -0
  159. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/service/providers.py +0 -0
  160. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/session_bridge.py +0 -0
  161. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  162. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  163. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/source_text.py +0 -0
  164. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/stall_alert.py +0 -0
  165. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/codex-waker.default +0 -0
  166. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  167. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  168. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  169. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  170. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  171. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  172. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  173. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  174. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  175. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  176. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  177. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/timeline_paths.py +0 -0
  178. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli/tokens.py +0 -0
  179. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  180. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  181. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli.egg-info/requires.txt +0 -0
  182. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/src/swarph_cli.egg-info/top_level.txt +0 -0
  183. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_124_register_merge.py +0 -0
  184. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_126_pending_from_complete.py +0 -0
  185. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  186. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_139_tool_probe.py +0 -0
  187. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_183_card_anchor.py +0 -0
  188. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_201_win32_bash_refusal.py +0 -0
  189. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_243_onboard_per_peer_token.py +0 -0
  190. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_307_task4_ask_reply.py +0 -0
  191. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  192. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_319_refusal_exit_codes.py +0 -0
  193. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_323_mistral_backend.py +0 -0
  194. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_332_report_organize_findings.py +0 -0
  195. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_356_query_filters.py +0 -0
  196. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_397_gh_identity_router.py +0 -0
  197. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_397_router_preflight.py +0 -0
  198. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_467b_onboard_operator_credential.py +0 -0
  199. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_523_guide.py +0 -0
  200. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_524_conftest_hermeticity.py +0 -0
  201. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_532_accept_flag.py +0 -0
  202. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_535_version_capability.py +0 -0
  203. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_546_default_gateway.py +0 -0
  204. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_547_verbs_from_registry.py +0 -0
  205. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_548_gateway_remainder.py +0 -0
  206. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_552_codegraph_gateway.py +0 -0
  207. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_555_relay_row_shape.py +0 -0
  208. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_556_relay_freshness.py +0 -0
  209. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_564_bootstrap_first_peer.py +0 -0
  210. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  211. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_579_register_bootstrap_message.py +0 -0
  212. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_591_cli_step_graph.py +0 -0
  213. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_644_monitor_supervision.py +0 -0
  214. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_648_install_unit.py +0 -0
  215. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_656_owned_slm.py +0 -0
  216. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_684_dreaming_verb.py +0 -0
  217. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_689_pkg_version_order.py +0 -0
  218. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_716_timeline_one_path.py +0 -0
  219. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_724_ps1_ascii_or_bom.py +0 -0
  220. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_725_stdio_reconfigure.py +0 -0
  221. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_734_dreaming_enrich_degrade.py +0 -0
  222. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_740_edit_project.py +0 -0
  223. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_762_cards_edit_priority.py +0 -0
  224. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_764_enrich_collapse.py +0 -0
  225. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_801_confirm_flow_cli.py +0 -0
  226. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_802_stage_history.py +0 -0
  227. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_825_codegraph_hook_noise.py +0 -0
  228. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_825_remaining_cap_shred_bind.py +0 -0
  229. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_829_counterfactual_column.py +0 -0
  230. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_830_hook_binding_version.py +0 -0
  231. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_84_cli_labels.py +0 -0
  232. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_866_doctrine_guide.py +0 -0
  233. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_872_identity_refuses_not_warns.py +0 -0
  234. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_874_source_text.py +0 -0
  235. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
  236. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_937_dreaming_notify.py +0 -0
  237. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_938_organize_line_limit.py +0 -0
  238. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_add_security_gate.py +0 -0
  239. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_artifact_add.py +0 -0
  240. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_artifact_hash.py +0 -0
  241. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_artifact_lib.py +0 -0
  242. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_artifact_mcp.py +0 -0
  243. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_artifact_skill.py +0 -0
  244. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_artifact_tool.py +0 -0
  245. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_artifact_uri.py +0 -0
  246. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_bench_backends.py +0 -0
  247. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_bench_command.py +0 -0
  248. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_bench_pack.py +0 -0
  249. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_bench_prices.py +0 -0
  250. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_bench_quality.py +0 -0
  251. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_bench_runner.py +0 -0
  252. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_bench_validate.py +0 -0
  253. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_board_card_thread.py +0 -0
  254. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_board_merge_check.py +0 -0
  255. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_board_obligation_close.py +0 -0
  256. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_brain_ask_command.py +0 -0
  257. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_brain_ask_env_diagnosis.py +0 -0
  258. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_brain_ask_identity_explicitness.py +0 -0
  259. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_brain_command.py +0 -0
  260. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_caller_meta_guard.py +0 -0
  261. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_capture_lineage.py +0 -0
  262. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_capture_liveness.py +0 -0
  263. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_capture_manifest.py +0 -0
  264. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_capture_paths.py +0 -0
  265. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_capture_security.py +0 -0
  266. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_cell_command_dispatch.py +0 -0
  267. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_cell_harden.py +0 -0
  268. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_cell_loader.py +0 -0
  269. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_cell_selfcheck.py +0 -0
  270. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_cell_verify.py +0 -0
  271. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_chain_token.py +0 -0
  272. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_channel_command.py +0 -0
  273. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  274. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_channel_post.py +0 -0
  275. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_channel_wake_policy_filter.py +0 -0
  276. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_chat_command.py +0 -0
  277. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_claude_parser.py +0 -0
  278. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_claude_tmux_template.py +0 -0
  279. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_codegraph_caller_scope.py +0 -0
  280. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_codegraph_command.py +0 -0
  281. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_codegraph_hook.py +0 -0
  282. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_codegraph_mcp.py +0 -0
  283. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_codex_waker.py +0 -0
  284. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_compress_caller_convention.py +0 -0
  285. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_compress_command.py +0 -0
  286. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_compress_levers.py +0 -0
  287. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_compress_marker.py +0 -0
  288. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_compress_verify.py +0 -0
  289. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_console_encoding_e2e.py +0 -0
  290. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_content_composition.py +0 -0
  291. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_cursor_membrane.py +0 -0
  292. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_daemon_command.py +0 -0
  293. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_daemon_console_encoding.py +0 -0
  294. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_daemon_delivery.py +0 -0
  295. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_delivery_queue.py +0 -0
  296. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_display_sanitize.py +0 -0
  297. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  298. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_event_emit.py +0 -0
  299. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_feature_to_uri.py +0 -0
  300. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_gateway_brain.py +0 -0
  301. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_gateway_client.py +0 -0
  302. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_gateway_command.py +0 -0
  303. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_gateway_message_idempotency.py +0 -0
  304. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  305. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_group_command.py +0 -0
  306. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_guide_commands_parse.py +0 -0
  307. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_guide_selfcheck.py +0 -0
  308. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_heartbeat_check.py +0 -0
  309. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_highlight_command.py +0 -0
  310. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hook_output.py +0 -0
  311. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hooks_activity_marker.py +0 -0
  312. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hooks_add.py +0 -0
  313. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hooks_bundle.py +0 -0
  314. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hooks_init.py +0 -0
  315. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hooks_legacy_generation_removal.py +0 -0
  316. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hooks_lifecycle.py +0 -0
  317. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hooks_merge.py +0 -0
  318. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hooks_verify.py +0 -0
  319. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  320. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_hooks_win32_command_path.py +0 -0
  321. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_import_command.py +0 -0
  322. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_inbox_identity_provenance.py +0 -0
  323. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_init_command.py +0 -0
  324. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_init_provider_menu.py +0 -0
  325. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_install_codex_hooks.py +0 -0
  326. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_install_hook.py +0 -0
  327. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_install_multiplexer_command.py +0 -0
  328. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_install_postcompact_hook.py +0 -0
  329. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_install_wake_hook.py +0 -0
  330. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_lane_command.py +0 -0
  331. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_main.py +0 -0
  332. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_main_unknown_verb_guard.py +0 -0
  333. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_mcp_missing_hint.py +0 -0
  334. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_mcp_server.py +0 -0
  335. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_memory_command.py +0 -0
  336. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_memory_emit_snippet.py +0 -0
  337. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_memory_gateway.py +0 -0
  338. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_memory_sync.py +0 -0
  339. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_memory_sync_membrane.py +0 -0
  340. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_mesh_command.py +0 -0
  341. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_mesh_inbox_mark_read.py +0 -0
  342. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_mesh_inbox_sanitize.py +0 -0
  343. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_mesh_send_unknown_peer.py +0 -0
  344. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_mesh_sidecar.py +0 -0
  345. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  346. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  347. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_meta_edge_identity.py +0 -0
  348. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_monitor_channel_poll.py +0 -0
  349. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_monitor_cli.py +0 -0
  350. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_monitor_daemon_collision.py +0 -0
  351. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_monitor_self_name_verification.py +0 -0
  352. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_monitor_state_split.py +0 -0
  353. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_multiplexer.py +0 -0
  354. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_muse_membrane.py +0 -0
  355. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_muse_own_cli.py +0 -0
  356. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_obligation_close_is_surfaced.py +0 -0
  357. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_okf_links.py +0 -0
  358. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_onboard_command.py +0 -0
  359. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_opencode_membrane.py +0 -0
  360. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_opencode_plugin.py +0 -0
  361. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_orphan_daemons.py +0 -0
  362. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_packaged_artifacts_exist.py +0 -0
  363. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_packaged_skills.py +0 -0
  364. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_peer_executor.py +0 -0
  365. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_peer_executor_windows.py +0 -0
  366. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_peer_reply_drain_command.py +0 -0
  367. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_peer_reply_drain_supervisor.py +0 -0
  368. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_peer_reply_outbox.py +0 -0
  369. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_peer_reply_transport.py +0 -0
  370. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_peer_service_e2e.py +0 -0
  371. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_peer_service_host.py +0 -0
  372. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_peer_service_payload.py +0 -0
  373. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_peer_service_reply.py +0 -0
  374. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_postcompact_recall.py +0 -0
  375. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_process_liveness.py +0 -0
  376. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_protocol_handler.py +0 -0
  377. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_providers_isolation.py +0 -0
  378. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_ratify_command.py +0 -0
  379. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_readme_claims_no_gateway_default.py +0 -0
  380. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_repl_caller_convention.py +0 -0
  381. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_schedule_command.py +0 -0
  382. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_schedule_create_contract.py +0 -0
  383. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_security.py +0 -0
  384. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_service_app.py +0 -0
  385. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_service_command.py +0 -0
  386. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_service_providers.py +0 -0
  387. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_session_bridge_inject.py +0 -0
  388. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_session_bridge_probe.py +0 -0
  389. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_session_bridge_resolve.py +0 -0
  390. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_session_path_role_gate.py +0 -0
  391. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_shipped_units_match_the_cli.py +0 -0
  392. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_smoke_chat.py +0 -0
  393. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_smoke_one_shot.py +0 -0
  394. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_smoke_phase_5_5.py +0 -0
  395. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_spawn_base_hoist.py +0 -0
  396. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_spawn_command.py +0 -0
  397. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_spawn_identity_stamp.py +0 -0
  398. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_spawn_live_pin.py +0 -0
  399. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_spawn_mitosis_lineage.py +0 -0
  400. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_spawn_tmux_session.py +0 -0
  401. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_spawn_windows_relaunch.py +0 -0
  402. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_stall_alert.py +0 -0
  403. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_subprocess_decode_encoding.py +0 -0
  404. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_timeline_command.py +0 -0
  405. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_tmux_wake_runstate_defer.py +0 -0
  406. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_tmux_wake_session_reanchor.py +0 -0
  407. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_tmux_wake_stale.py +0 -0
  408. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_tmux_wake_submit_verify.py +0 -0
  409. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_token_file_one_parser.py +0 -0
  410. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_token_precedence_explicit_first.py +0 -0
  411. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_unified_token_resolver.py +0 -0
  412. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_version_command.py +0 -0
  413. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_version_consistency.py +0 -0
  414. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_vibe_membrane.py +0 -0
  415. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_watchdog.py +0 -0
  416. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_watchdog_dm_wake.py +0 -0
  417. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  418. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  419. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_watchdog_emit_health.py +0 -0
  420. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_watchdog_install_flags.py +0 -0
  421. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_watchdog_model_rung.py +0 -0
  422. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/tests/test_watchdog_stale_peers.py +0 -0
  423. {swarph_cli-0.65.0 → swarph_cli-0.66.0}/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.65.0
3
+ Version: 0.66.0
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
@@ -347,7 +347,7 @@ $ swarph codegraph "cron expression validator" --json --limit 5
347
347
 
348
348
  It queries a locally-built index at `~/.swarph/codegraph/index.db` (override with `--index` or `SWARPH_CODEGRAPH_INDEX`); the index is built out-of-band from your repos (tree-sitter → SQLite FTS5, BM25-ranked). If no index is present the verb simply returns no matches — it never touches the network and never reads code it wasn't pointed at. Results are scoped by an owner-allowlist gate (`--caller-cell` / `SWARPH_CELL`, default: your cell): public repos are always visible; private repos are visible to the owning cell.
349
349
 
350
- The same capability is exposed as an **MCP tool** — running `swarph mcp-server` publishes `swarph_codegraph_query` alongside `swarph_search`/`swarph_add`/`swarph_describe`, so any MCP host's agent auto-discovers it and can reach for code-structure lookups while reading, writing, or debugging code. (Why a tool and not an always-on retrieval lane? Because *intent* to consult code structure lives with the calling agent — which already knows it's working on code — not in a similarity score.)
350
+ The same capability is exposed as an **MCP tool** — running `swarph mcp-server` publishes `swarph_codegraph_query` alongside `swarph_search`/`swarph_add`/`swarph_describe` (and the mesh DM tools `swarph_dm_unread`, which returns every unread DM with full bodies in one call without marking them read; `swarph_dm_reply`, which replies by message id and marks that message read; and `swarph_dm_thread`, which returns a DM's whole conversation), so any MCP host's agent auto-discovers it and can reach for code-structure lookups while reading, writing, or debugging code. (Why a tool and not an always-on retrieval lane? Because *intent* to consult code structure lives with the calling agent — which already knows it's working on code — not in a similarity score.)
351
351
 
352
352
  ### `swarph gateway`
353
353
 
@@ -299,7 +299,7 @@ $ swarph codegraph "cron expression validator" --json --limit 5
299
299
 
300
300
  It queries a locally-built index at `~/.swarph/codegraph/index.db` (override with `--index` or `SWARPH_CODEGRAPH_INDEX`); the index is built out-of-band from your repos (tree-sitter → SQLite FTS5, BM25-ranked). If no index is present the verb simply returns no matches — it never touches the network and never reads code it wasn't pointed at. Results are scoped by an owner-allowlist gate (`--caller-cell` / `SWARPH_CELL`, default: your cell): public repos are always visible; private repos are visible to the owning cell.
301
301
 
302
- The same capability is exposed as an **MCP tool** — running `swarph mcp-server` publishes `swarph_codegraph_query` alongside `swarph_search`/`swarph_add`/`swarph_describe`, so any MCP host's agent auto-discovers it and can reach for code-structure lookups while reading, writing, or debugging code. (Why a tool and not an always-on retrieval lane? Because *intent* to consult code structure lives with the calling agent — which already knows it's working on code — not in a similarity score.)
302
+ The same capability is exposed as an **MCP tool** — running `swarph mcp-server` publishes `swarph_codegraph_query` alongside `swarph_search`/`swarph_add`/`swarph_describe` (and the mesh DM tools `swarph_dm_unread`, which returns every unread DM with full bodies in one call without marking them read; `swarph_dm_reply`, which replies by message id and marks that message read; and `swarph_dm_thread`, which returns a DM's whole conversation), so any MCP host's agent auto-discovers it and can reach for code-structure lookups while reading, writing, or debugging code. (Why a tool and not an always-on retrieval lane? Because *intent* to consult code structure lives with the calling agent — which already knows it's working on code — not in a similarity score.)
303
303
 
304
304
  ### `swarph gateway`
305
305
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swarph-cli"
7
- version = "0.65.0"
7
+ version = "0.66.0"
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.65.0"
19
+ __version__ = "0.66.0"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -7,7 +7,7 @@ thought / out, latency, text, whether tokens are ESTIMATED). ``system``
7
7
  threads to every backend (metered: ``system_instruction``; a CLI-shelling
8
8
  backend would prepend it — see :class:`SubscriptionBackend`).
9
9
 
10
- Ships two backends:
10
+ Ships these backends:
11
11
 
12
12
  - :class:`MeteredGeminiBackend` — google-genai Developer API, DEFAULT for v1
13
13
  (real ``usage_metadata``: prompt/candidates/thoughts tokens). CRITICAL:
@@ -19,13 +19,21 @@ Ships two backends:
19
19
  NOT couple to any specific subscription lane map; a caller wires an actual
20
20
  $0 CLI/OIDC path in by passing ``call_fn``. Not exercised against a live
21
21
  provider anywhere in this package.
22
+ - :class:`RuleBackend` — in-process ``rule:<module:callable>``. No credentials.
23
+ - :class:`TypedHttpBackend` — POST to a Jev-compatible ``/v1/systemone``
24
+ (laya-serve). No credentials; per-item latency is the HTTP round trip.
22
25
  """
23
26
  from __future__ import annotations
24
27
 
28
+ import importlib
29
+ import inspect
30
+ import json
25
31
  import os
26
32
  import time
33
+ import urllib.error
34
+ import urllib.request
27
35
  from dataclasses import dataclass
28
- from typing import Callable, Optional, Protocol
36
+ from typing import Any, Callable, Optional, Protocol
29
37
 
30
38
 
31
39
  @dataclass
@@ -275,3 +283,216 @@ class SubscriptionBackend:
275
283
  latency_s=latency_s,
276
284
  estimated=True,
277
285
  )
286
+
287
+
288
+ def _load_rule(spec: str) -> Callable[..., Any]:
289
+ """``module:callable`` -> the callable. The module path uses dots; the
290
+ callable name is the segment after the last colon."""
291
+ mod_name, sep, fn_name = spec.rpartition(":")
292
+ if not sep or not mod_name or not fn_name:
293
+ raise ValueError(f"rule model id must be module:callable, got {spec!r}")
294
+ fn = getattr(importlib.import_module(mod_name), fn_name)
295
+ if not callable(fn):
296
+ raise TypeError(f"{spec} is not callable")
297
+ return fn
298
+
299
+
300
+ def _rule_subject(prompt: str) -> Any:
301
+ """A JSON bench prompt is the systemone template. The rule sees its
302
+ ``state`` (the item), not the question text. A plain prompt is unchanged.
303
+ """
304
+ try:
305
+ parsed = json.loads(prompt) if isinstance(prompt, str) else None
306
+ except json.JSONDecodeError:
307
+ parsed = None
308
+ if isinstance(parsed, dict) and "state" in parsed:
309
+ return parsed["state"]
310
+ return prompt
311
+
312
+
313
+ def _call_rule(fn: Callable[..., Any], prompt: Any, system: str) -> Any:
314
+ params = inspect.signature(fn).parameters
315
+ if len(params) >= 2:
316
+ return fn(prompt, system)
317
+ return fn(prompt)
318
+
319
+
320
+ def _request_body(prompt: str, system: str) -> dict:
321
+ """The POST body for ``/v1/systemone``.
322
+
323
+ A prompt that is itself a JSON object with ``state`` and ``questions``
324
+ is sent unchanged. That is how a pack carries a pre-registered template
325
+ (question type, instructions, criteria) without this backend inventing
326
+ them. Anything else is wrapped as one choice question whose instructions
327
+ are the prompt. That wrapper has no criteria, so a live laya-serve
328
+ rejects it; the gold packs must send the JSON form.
329
+ """
330
+ try:
331
+ parsed = json.loads(prompt) if isinstance(prompt, str) else None
332
+ except json.JSONDecodeError:
333
+ parsed = None
334
+ if isinstance(parsed, dict) and "state" in parsed and "questions" in parsed:
335
+ return parsed
336
+ return {
337
+ "state": {"system": system, "prompt": prompt},
338
+ "questions": {
339
+ "answer": {"type": "choice", "instructions": prompt},
340
+ },
341
+ }
342
+
343
+
344
+ def _systemone_url(model_id: str) -> str:
345
+ url = (model_id or "").strip()
346
+ if not url:
347
+ raise ValueError("typed-http model id is empty")
348
+ if url.rstrip("/").endswith("/v1/systemone"):
349
+ return url.rstrip("/")
350
+ return url.rstrip("/") + "/v1/systemone"
351
+
352
+
353
+ # Frozen on card #941 (lab-ovh msg 48915): the verdict uses 0.50 only.
354
+ _NOUL_THRESHOLD = 0.50
355
+
356
+
357
+ def _noul_question(body: dict) -> Optional[dict]:
358
+ questions = body.get("questions") if isinstance(body, dict) else None
359
+ if not isinstance(questions, dict):
360
+ return None
361
+ named = questions.get("answer")
362
+ if isinstance(named, dict) and named.get("type") == "noul":
363
+ return named
364
+ for block in questions.values():
365
+ if isinstance(block, dict) and block.get("type") == "noul":
366
+ return block
367
+ return None
368
+
369
+
370
+ def _noul_labels(question: Optional[dict]) -> tuple[str, str]:
371
+ """Positive and negative labels named on the template.
372
+
373
+ ``labels.true`` / ``labels.false`` when the pack set them. Otherwise the
374
+ frozen S1 pair YES / NO (msg 48915: P(true) >= 0.50 -> YES).
375
+ """
376
+ labels = {}
377
+ if isinstance(question, dict) and isinstance(question.get("labels"), dict):
378
+ labels = question["labels"]
379
+ pos = labels.get("true")
380
+ neg = labels.get("false")
381
+ return (
382
+ str(pos) if pos is not None else "YES",
383
+ str(neg) if neg is not None else "NO",
384
+ )
385
+
386
+
387
+ def _typed_value(payload: dict, request: Optional[dict] = None) -> tuple[Any, Optional[float]]:
388
+ """Pull the typed answer out of a Jev /v1/systemone response.
389
+
390
+ Prefers the question named ``answer``; otherwise the first question.
391
+ ``choice``, ``noul``, ``yes``, then ``score``. A ``noul`` value is
392
+ P(true): >= 0.50 maps to the template's positive label, below that to
393
+ the negative. The raw probability is returned alongside the label.
394
+ Choice and score are returned as the server sent them.
395
+ """
396
+ answers = payload.get("answers")
397
+ if not isinstance(answers, dict) or not answers:
398
+ raise ValueError("systemone response has no answers")
399
+ block = answers.get("answer")
400
+ if not isinstance(block, dict):
401
+ block = next(iter(answers.values()))
402
+ if not isinstance(block, dict):
403
+ raise ValueError("systemone answer is not an object")
404
+ for key in ("choice", "noul", "yes", "score"):
405
+ if key in block and block[key] is not None:
406
+ if key == "noul":
407
+ p_true = float(block[key])
408
+ pos, neg = _noul_labels(_noul_question(request or {}))
409
+ label = pos if p_true >= _NOUL_THRESHOLD else neg
410
+ return label, p_true
411
+ return block[key], None
412
+ raise ValueError("systemone answer has no choice, noul, yes, or score")
413
+
414
+
415
+ class RuleBackend:
416
+ """In-process callable. ``model_id`` is ``module:callable``.
417
+
418
+ The callable receives ``(prompt, system)`` when it takes two arguments,
419
+ otherwise ``(prompt)``. A JSON prompt with ``state`` is unwrapped first:
420
+ the callable sees that state, not the template. Its return value is the
421
+ categorical label. No credentials. Latency is the call itself.
422
+ """
423
+
424
+ def missing_creds(self) -> list[str]:
425
+ return []
426
+
427
+ def generate(self, model_id: str, prompt: str, system: str = "") -> BackendResult:
428
+ t0 = time.perf_counter()
429
+ try:
430
+ label = _call_rule(_load_rule(model_id), _rule_subject(prompt), system)
431
+ text = json.dumps({"answer": label})
432
+ except Exception as exc:
433
+ return BackendResult(
434
+ text="", tokens_in=0, tokens_thought=0, tokens_out=0,
435
+ latency_s=round(time.perf_counter() - t0, 6),
436
+ estimated=False, error=str(exc),
437
+ )
438
+ return BackendResult(
439
+ text=text,
440
+ tokens_in=0,
441
+ tokens_thought=0,
442
+ tokens_out=0,
443
+ latency_s=round(time.perf_counter() - t0, 6),
444
+ estimated=False,
445
+ )
446
+
447
+
448
+ class TypedHttpBackend:
449
+ """POST a bench item to a Jev-compatible ``/v1/systemone`` server.
450
+
451
+ ``model_id`` is the server base (``http://127.0.0.1:<port>``) or a full
452
+ ``.../v1/systemone`` URL. A prompt that is a JSON object with ``state``
453
+ and ``questions`` is the POST body, unchanged — that is the pre-registered
454
+ template. No API key is read or sent. Latency is the round trip.
455
+ A ``noul`` answer is P(true): >= 0.50 becomes the template's positive
456
+ label and below 0.50 the negative. The raw P(true) stays in the result
457
+ text. Choice answers are the server's label, unthresholded.
458
+ """
459
+
460
+ def missing_creds(self) -> list[str]:
461
+ return []
462
+
463
+ def generate(self, model_id: str, prompt: str, system: str = "") -> BackendResult:
464
+ t0 = time.perf_counter()
465
+ try:
466
+ endpoint = _systemone_url(model_id)
467
+ body = _request_body(prompt, system)
468
+ req = urllib.request.Request(
469
+ endpoint,
470
+ data=json.dumps(body).encode(),
471
+ headers={"Content-Type": "application/json"},
472
+ method="POST",
473
+ )
474
+ with urllib.request.urlopen(req, timeout=60) as resp:
475
+ raw = resp.read()
476
+ payload = json.loads(raw.decode() or "{}")
477
+ if not isinstance(payload, dict):
478
+ raise ValueError("systemone response is not an object")
479
+ label, p_true = _typed_value(payload, body)
480
+ rendered = {"answer": label}
481
+ if p_true is not None:
482
+ rendered["p_true"] = p_true
483
+ text = json.dumps(rendered)
484
+ usage = payload.get("usage") if isinstance(payload.get("usage"), dict) else {}
485
+ except Exception as exc:
486
+ return BackendResult(
487
+ text="", tokens_in=0, tokens_thought=0, tokens_out=0,
488
+ latency_s=round(time.perf_counter() - t0, 6),
489
+ estimated=False, error=str(exc),
490
+ )
491
+ return BackendResult(
492
+ text=text,
493
+ tokens_in=int(usage.get("input_tokens") or 0),
494
+ tokens_thought=0,
495
+ tokens_out=int(usage.get("output_tokens") or 0),
496
+ latency_s=round(time.perf_counter() - t0, 6),
497
+ estimated=False,
498
+ )
@@ -0,0 +1,40 @@
1
+ """Thin adapters from the rules the mesh runs today to card #941's labels.
2
+
3
+ Frozen by lab-ovh (card #941, msg 48944). Each function calls the current
4
+ rule and adds no decision of its own. That message's closing line says the
5
+ rubric (science-claude, msg 48930) wins where the two vocabularies differ,
6
+ so claim/mention are returned as CLAIM/MENTION and act-now/routine as
7
+ ACT/ROUTINE. S1's YES/NO already matches the rubric.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ from swarph_cli.commands.codegraph_hook import prompt_has_coding_keywords
12
+ from swarph_cli.dreaming.verify import _is_dated_record, _is_superseded
13
+ from swarph_cli.scripts.dm_notify_filter import _format_dm
14
+
15
+
16
+ def s1_code_question(state) -> str:
17
+ """YES when the live codegraph gate would keep the prompt."""
18
+ text = state["text"] if isinstance(state, dict) else state
19
+ return "YES" if prompt_has_coding_keywords(text) else "NO"
20
+
21
+
22
+ def s2_claim_vs_mention(state) -> str:
23
+ """mention when the extractor found no value, or the line is superseded
24
+ or a dated record; otherwise claim. verify.py's current decision.
25
+ """
26
+ text = state["text"]
27
+ asserted = state["asserted"]
28
+ mention = (
29
+ asserted is None
30
+ or _is_superseded(text)
31
+ or _is_dated_record(text, asserted)
32
+ )
33
+ return "MENTION" if mention else "CLAIM"
34
+
35
+
36
+ def s3_dm_triage(state) -> str:
37
+ """routine when today's notify filter would drop the DM; otherwise act-now."""
38
+ if _format_dm(state["dm"]) is None:
39
+ return "ROUTINE"
40
+ return "ACT"
@@ -40,11 +40,18 @@ def parse_models(arg: str) -> list[ModelSpec]:
40
40
  tok = tok.strip()
41
41
  if not tok:
42
42
  continue
43
- parts = tok.split(":")
44
- mid = parts[0]
45
- backend = parts[1] if len(parts) > 1 and parts[1] else "metered"
46
- label = parts[2] if len(parts) > 2 and parts[2] else mid
47
- specs.append(ModelSpec(id=mid, backend=backend, label=label))
43
+ # rule:<module:callable> and typed-http:<url> carry colons in the
44
+ # payload, so they cannot go through the id:backend:label split.
45
+ for prefix, backend in (("typed-http:", "typed-http"), ("rule:", "rule")):
46
+ if tok.startswith(prefix):
47
+ specs.append(ModelSpec(id=tok[len(prefix):], backend=backend, label=tok))
48
+ break
49
+ else:
50
+ parts = tok.split(":")
51
+ mid = parts[0]
52
+ backend = parts[1] if len(parts) > 1 and parts[1] else "metered"
53
+ label = parts[2] if len(parts) > 2 and parts[2] else mid
54
+ specs.append(ModelSpec(id=mid, backend=backend, label=label))
48
55
  return specs
49
56
 
50
57
 
@@ -26,7 +26,9 @@ from swarph_cli.bench.backends import (
26
26
  Backend,
27
27
  MeteredGeminiBackend,
28
28
  MeteredMistralBackend,
29
+ RuleBackend,
29
30
  SubscriptionBackend,
31
+ TypedHttpBackend,
30
32
  )
31
33
  from swarph_cli.bench.pack import PackError, load_pack, slugify_theme, validate_schema
32
34
  from swarph_cli.bench.runner import ModelSpec, parse_models, preflight, run_pack
@@ -53,6 +55,8 @@ def _default_backends() -> dict[str, Backend]:
53
55
  "metered": MeteredGeminiBackend(),
54
56
  "mistral": MeteredMistralBackend(),
55
57
  "subscription": SubscriptionBackend(),
58
+ "rule": RuleBackend(),
59
+ "typed-http": TypedHttpBackend(),
56
60
  }
57
61
 
58
62
 
@@ -165,7 +165,9 @@ def _card_edit_payload(actor, title, body, *, due_at=_SENTINEL, project_id=None,
165
165
  if body is not None:
166
166
  patch["body"] = body
167
167
  if due_at is not _SENTINEL:
168
- patch["due_at"] = _normalize_due_at(due_at) if due_at else None
168
+ # "" is the gateway's CLEAR sentinel; None means "not mentioned" and the
169
+ # write is skipped while the old date is echoed back (#901).
170
+ patch["due_at"] = _normalize_due_at(due_at) if due_at else ""
169
171
  if project_id is not None:
170
172
  patch["project_id"] = int(project_id) # #740: re-home; the gateway gates it (orchestrator + both owners)
171
173
  if priority is not None:
@@ -233,7 +233,7 @@ def _synthesize(facade_url: str, facade_token: str, question: str, chunks: list)
233
233
  body = {"model": os.environ.get("SWARPH_FACADE_MODEL", "claude"),
234
234
  "messages": [{"role": "system", "content": sys_prompt},
235
235
  {"role": "user", "content": user}],
236
- "max_tokens": 700, "temperature": 0.2}
236
+ }
237
237
  raw = _http_post(facade_url, body, facade_token, accept="application/json")
238
238
  doc = json.loads(raw)
239
239
  return doc["choices"][0]["message"]["content"].strip()