swarph-cli 0.63.0__tar.gz → 0.64.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 (414) hide show
  1. {swarph_cli-0.63.0/src/swarph_cli.egg-info → swarph_cli-0.64.0}/PKG-INFO +5 -2
  2. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/README.md +4 -1
  3. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/pyproject.toml +1 -1
  4. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/__init__.py +1 -1
  5. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codegraph_hook.py +24 -1
  6. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/dreaming.py +8 -0
  7. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/hooks.py +59 -34
  8. swarph_cli-0.64.0/src/swarph_cli/dreaming/notify.py +96 -0
  9. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/run.py +14 -0
  10. {swarph_cli-0.63.0 → swarph_cli-0.64.0/src/swarph_cli.egg-info}/PKG-INFO +5 -2
  11. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/SOURCES.txt +3 -0
  12. swarph_cli-0.64.0/tests/test_825_remaining_cap_shred_bind.py +165 -0
  13. swarph_cli-0.64.0/tests/test_937_dreaming_notify.py +120 -0
  14. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_codegraph_hook.py +1 -1
  15. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/LICENSE +0 -0
  16. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/setup.cfg +0 -0
  17. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/__main__.py +0 -0
  18. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/__init__.py +0 -0
  19. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/backends.py +0 -0
  20. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/pack.py +0 -0
  21. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/prices.py +0 -0
  22. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/quality.py +0 -0
  23. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/refresh_prices.py +0 -0
  24. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/runner.py +0 -0
  25. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/validate.py +0 -0
  26. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/caller.py +0 -0
  27. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/__init__.py +0 -0
  28. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/harden.py +0 -0
  29. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/lineage.py +0 -0
  30. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/liveness.py +0 -0
  31. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/manifest.py +0 -0
  32. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/paths.py +0 -0
  33. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/verify.py +0 -0
  34. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/cell.py +0 -0
  35. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/chain_token.py +0 -0
  36. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/__init__.py +0 -0
  37. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/_content.py +0 -0
  38. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/_display.py +0 -0
  39. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/_gateway_client.py +0 -0
  40. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/add.py +0 -0
  41. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/bench.py +0 -0
  42. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/board.py +0 -0
  43. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/board_merge_check.py +0 -0
  44. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/brain.py +0 -0
  45. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/brain_ask.py +0 -0
  46. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/cell.py +0 -0
  47. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/cell_probe.py +0 -0
  48. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  49. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/channel.py +0 -0
  50. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/chat.py +0 -0
  51. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codegraph.py +0 -0
  52. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  53. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codex_waker.py +0 -0
  54. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/compress.py +0 -0
  55. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/daemon.py +0 -0
  56. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/event.py +0 -0
  57. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/gateway.py +0 -0
  58. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/gh_route.py +0 -0
  59. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/group.py +0 -0
  60. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/guide.py +0 -0
  61. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/highlight.py +0 -0
  62. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/hook_output.py +0 -0
  63. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/import_session.py +0 -0
  64. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/init.py +0 -0
  65. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  66. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_hook.py +0 -0
  67. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  68. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
  69. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
  70. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  71. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/lane.py +0 -0
  72. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/mcp_server.py +0 -0
  73. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/memory.py +0 -0
  74. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
  75. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/memory_sync.py +0 -0
  76. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/mesh.py +0 -0
  77. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/monitor.py +0 -0
  78. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/okf_links.py +0 -0
  79. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/onboard.py +0 -0
  80. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  81. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  82. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/protocol_handler.py +0 -0
  83. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/ratify.py +0 -0
  84. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/schedule.py +0 -0
  85. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/security.py +0 -0
  86. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/service.py +0 -0
  87. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/spawn.py +0 -0
  88. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/timeline.py +0 -0
  89. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/version.py +0 -0
  90. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/wake_hook_output.py +0 -0
  91. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/watchdog.py +0 -0
  92. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/__init__.py +0 -0
  93. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/levers.py +0 -0
  94. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/marker.py +0 -0
  95. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/verify.py +0 -0
  96. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/console_safe.py +0 -0
  97. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/delivery_queue.py +0 -0
  98. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/__init__.py +0 -0
  99. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/candidates.py +0 -0
  100. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/clone.py +0 -0
  101. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/enrich.py +0 -0
  102. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/index_check.py +0 -0
  103. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/organize.py +0 -0
  104. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/probes.py +0 -0
  105. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/report.py +0 -0
  106. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/slm.py +0 -0
  107. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/transcripts.py +0 -0
  108. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/verify.py +0 -0
  109. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/__init__.py +0 -0
  110. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/feature_registry.py +0 -0
  111. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/lanes_control.py +0 -0
  112. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/schema.sql +0 -0
  113. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/server.py +0 -0
  114. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/services_control.py +0 -0
  115. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway_default.py +0 -0
  116. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gh_identity.py +0 -0
  117. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/guide/GUIDE.md +0 -0
  118. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/main.py +0 -0
  119. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/multiplexer.py +0 -0
  120. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/orphan_daemons.py +0 -0
  121. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/pane_probe.py +0 -0
  122. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/parsers/__init__.py +0 -0
  123. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/parsers/claude.py +0 -0
  124. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
  125. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  126. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  127. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  128. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  129. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  130. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  131. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  132. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  133. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  134. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  135. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  136. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_executor.py +0 -0
  137. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_executor_windows.py +0 -0
  138. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_reconciliation.py +0 -0
  139. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_reply_outbox.py +0 -0
  140. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_service_host.py +0 -0
  141. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_service_payload.py +0 -0
  142. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_service_reply.py +0 -0
  143. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_staging.py +0 -0
  144. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/query_filters.py +0 -0
  145. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/__init__.py +0 -0
  146. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  147. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  148. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  149. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  150. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/service/__init__.py +0 -0
  151. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/service/app.py +0 -0
  152. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/service/providers.py +0 -0
  153. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/session_bridge.py +0 -0
  154. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  155. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  156. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/source_text.py +0 -0
  157. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/stall_alert.py +0 -0
  158. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/codex-waker.default +0 -0
  159. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  160. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  161. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  162. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  163. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  164. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
  165. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
  166. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  167. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  168. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  169. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  170. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  171. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  172. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/timeline_paths.py +0 -0
  173. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/tokens.py +0 -0
  174. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  175. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  176. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/requires.txt +0 -0
  177. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/top_level.txt +0 -0
  178. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_124_register_merge.py +0 -0
  179. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_126_pending_from_complete.py +0 -0
  180. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  181. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_139_tool_probe.py +0 -0
  182. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_183_card_anchor.py +0 -0
  183. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_201_win32_bash_refusal.py +0 -0
  184. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_243_onboard_per_peer_token.py +0 -0
  185. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_307_task4_ask_reply.py +0 -0
  186. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  187. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_319_refusal_exit_codes.py +0 -0
  188. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_323_mistral_backend.py +0 -0
  189. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_356_query_filters.py +0 -0
  190. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_397_gh_identity_router.py +0 -0
  191. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_397_router_preflight.py +0 -0
  192. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_467b_onboard_operator_credential.py +0 -0
  193. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_523_guide.py +0 -0
  194. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_524_conftest_hermeticity.py +0 -0
  195. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_532_accept_flag.py +0 -0
  196. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_535_version_capability.py +0 -0
  197. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_546_default_gateway.py +0 -0
  198. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_547_verbs_from_registry.py +0 -0
  199. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_548_gateway_remainder.py +0 -0
  200. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_552_codegraph_gateway.py +0 -0
  201. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_555_relay_row_shape.py +0 -0
  202. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_556_relay_freshness.py +0 -0
  203. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_564_bootstrap_first_peer.py +0 -0
  204. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  205. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_579_register_bootstrap_message.py +0 -0
  206. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_591_cli_step_graph.py +0 -0
  207. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_644_monitor_supervision.py +0 -0
  208. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_648_install_unit.py +0 -0
  209. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_654_reexec.py +0 -0
  210. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_656_owned_slm.py +0 -0
  211. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_684_dreaming_verb.py +0 -0
  212. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_689_pkg_version_order.py +0 -0
  213. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_716_timeline_one_path.py +0 -0
  214. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_724_ps1_ascii_or_bom.py +0 -0
  215. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_725_stdio_reconfigure.py +0 -0
  216. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_734_dreaming_enrich_degrade.py +0 -0
  217. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_740_edit_project.py +0 -0
  218. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_762_cards_edit_priority.py +0 -0
  219. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_801_confirm_flow_cli.py +0 -0
  220. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_802_stage_history.py +0 -0
  221. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_825_codegraph_hook_noise.py +0 -0
  222. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_829_counterfactual_column.py +0 -0
  223. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_830_hook_binding_version.py +0 -0
  224. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_84_cli_labels.py +0 -0
  225. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_866_doctrine_guide.py +0 -0
  226. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_872_identity_refuses_not_warns.py +0 -0
  227. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_874_source_text.py +0 -0
  228. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
  229. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_add_security_gate.py +0 -0
  230. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_add.py +0 -0
  231. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_hash.py +0 -0
  232. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_lib.py +0 -0
  233. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_mcp.py +0 -0
  234. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_skill.py +0 -0
  235. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_tool.py +0 -0
  236. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_uri.py +0 -0
  237. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_backends.py +0 -0
  238. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_command.py +0 -0
  239. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_pack.py +0 -0
  240. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_prices.py +0 -0
  241. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_quality.py +0 -0
  242. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_runner.py +0 -0
  243. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_validate.py +0 -0
  244. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_board_card_thread.py +0 -0
  245. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_board_command.py +0 -0
  246. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_board_merge_check.py +0 -0
  247. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_board_obligation_close.py +0 -0
  248. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_brain_ask_command.py +0 -0
  249. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_brain_ask_env_diagnosis.py +0 -0
  250. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_brain_ask_identity_explicitness.py +0 -0
  251. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_brain_command.py +0 -0
  252. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_caller_meta_guard.py +0 -0
  253. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_capture_lineage.py +0 -0
  254. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_capture_liveness.py +0 -0
  255. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_capture_manifest.py +0 -0
  256. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_capture_paths.py +0 -0
  257. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_capture_security.py +0 -0
  258. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cell_command_dispatch.py +0 -0
  259. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cell_harden.py +0 -0
  260. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cell_loader.py +0 -0
  261. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cell_selfcheck.py +0 -0
  262. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cell_verify.py +0 -0
  263. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_chain_token.py +0 -0
  264. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_channel_command.py +0 -0
  265. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  266. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_channel_post.py +0 -0
  267. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_channel_wake_policy_filter.py +0 -0
  268. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_chat_command.py +0 -0
  269. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_claude_parser.py +0 -0
  270. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_claude_tmux_template.py +0 -0
  271. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_codegraph_caller_scope.py +0 -0
  272. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_codegraph_command.py +0 -0
  273. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_codegraph_mcp.py +0 -0
  274. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_codex_waker.py +0 -0
  275. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_compress_caller_convention.py +0 -0
  276. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_compress_command.py +0 -0
  277. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_compress_levers.py +0 -0
  278. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_compress_marker.py +0 -0
  279. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_compress_verify.py +0 -0
  280. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_console_encoding_e2e.py +0 -0
  281. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_content_composition.py +0 -0
  282. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cursor_membrane.py +0 -0
  283. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_daemon_command.py +0 -0
  284. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_daemon_console_encoding.py +0 -0
  285. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_daemon_delivery.py +0 -0
  286. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_delivery_queue.py +0 -0
  287. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_display_sanitize.py +0 -0
  288. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  289. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_event_emit.py +0 -0
  290. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_feature_to_uri.py +0 -0
  291. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_gateway_brain.py +0 -0
  292. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_gateway_client.py +0 -0
  293. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_gateway_command.py +0 -0
  294. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_gateway_message_idempotency.py +0 -0
  295. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  296. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_group_command.py +0 -0
  297. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_guide_commands_parse.py +0 -0
  298. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_guide_selfcheck.py +0 -0
  299. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_heartbeat_check.py +0 -0
  300. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_highlight_command.py +0 -0
  301. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hook_output.py +0 -0
  302. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_activity_marker.py +0 -0
  303. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_add.py +0 -0
  304. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_bundle.py +0 -0
  305. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_init.py +0 -0
  306. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_legacy_generation_removal.py +0 -0
  307. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_lifecycle.py +0 -0
  308. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_merge.py +0 -0
  309. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_verify.py +0 -0
  310. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  311. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_win32_command_path.py +0 -0
  312. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_import_command.py +0 -0
  313. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_inbox_identity_provenance.py +0 -0
  314. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_init_command.py +0 -0
  315. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_init_provider_menu.py +0 -0
  316. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_install_codex_hooks.py +0 -0
  317. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_install_hook.py +0 -0
  318. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_install_multiplexer_command.py +0 -0
  319. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_install_postcompact_hook.py +0 -0
  320. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_install_wake_hook.py +0 -0
  321. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_lane_command.py +0 -0
  322. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_main.py +0 -0
  323. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_main_unknown_verb_guard.py +0 -0
  324. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mcp_missing_hint.py +0 -0
  325. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mcp_server.py +0 -0
  326. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_memory_command.py +0 -0
  327. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_memory_emit_snippet.py +0 -0
  328. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_memory_gateway.py +0 -0
  329. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_memory_sync.py +0 -0
  330. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_memory_sync_membrane.py +0 -0
  331. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_command.py +0 -0
  332. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_inbox_mark_read.py +0 -0
  333. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_inbox_sanitize.py +0 -0
  334. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_send_unknown_peer.py +0 -0
  335. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_sidecar.py +0 -0
  336. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  337. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  338. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_meta_edge_identity.py +0 -0
  339. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_monitor_channel_poll.py +0 -0
  340. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_monitor_cli.py +0 -0
  341. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_monitor_daemon_collision.py +0 -0
  342. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_monitor_self_name_verification.py +0 -0
  343. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_monitor_state_split.py +0 -0
  344. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_multiplexer.py +0 -0
  345. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_muse_membrane.py +0 -0
  346. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_muse_own_cli.py +0 -0
  347. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_obligation_close_is_surfaced.py +0 -0
  348. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_okf_links.py +0 -0
  349. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_onboard_command.py +0 -0
  350. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_opencode_membrane.py +0 -0
  351. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_opencode_plugin.py +0 -0
  352. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_orphan_daemons.py +0 -0
  353. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_packaged_artifacts_exist.py +0 -0
  354. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_packaged_skills.py +0 -0
  355. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_executor.py +0 -0
  356. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_executor_windows.py +0 -0
  357. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_reply_drain_command.py +0 -0
  358. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_reply_drain_supervisor.py +0 -0
  359. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_reply_outbox.py +0 -0
  360. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_reply_transport.py +0 -0
  361. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_service_e2e.py +0 -0
  362. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_service_host.py +0 -0
  363. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_service_payload.py +0 -0
  364. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_service_reply.py +0 -0
  365. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_postcompact_recall.py +0 -0
  366. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_process_liveness.py +0 -0
  367. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_protocol_handler.py +0 -0
  368. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_providers_isolation.py +0 -0
  369. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_ratify_command.py +0 -0
  370. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_readme_claims_no_gateway_default.py +0 -0
  371. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_repl_caller_convention.py +0 -0
  372. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_schedule_command.py +0 -0
  373. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_schedule_create_contract.py +0 -0
  374. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_security.py +0 -0
  375. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_service_app.py +0 -0
  376. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_service_command.py +0 -0
  377. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_service_providers.py +0 -0
  378. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_session_bridge_inject.py +0 -0
  379. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_session_bridge_probe.py +0 -0
  380. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_session_bridge_resolve.py +0 -0
  381. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_session_path_role_gate.py +0 -0
  382. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_shipped_units_match_the_cli.py +0 -0
  383. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_smoke_chat.py +0 -0
  384. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_smoke_one_shot.py +0 -0
  385. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_smoke_phase_5_5.py +0 -0
  386. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_base_hoist.py +0 -0
  387. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_command.py +0 -0
  388. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_identity_stamp.py +0 -0
  389. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_live_pin.py +0 -0
  390. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_mitosis_lineage.py +0 -0
  391. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_tmux_session.py +0 -0
  392. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_windows_relaunch.py +0 -0
  393. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_stall_alert.py +0 -0
  394. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_subprocess_decode_encoding.py +0 -0
  395. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_timeline_command.py +0 -0
  396. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_runstate_defer.py +0 -0
  397. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_session_reanchor.py +0 -0
  398. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_stale.py +0 -0
  399. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_submit_verify.py +0 -0
  400. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_token_file_one_parser.py +0 -0
  401. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_token_precedence_explicit_first.py +0 -0
  402. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_unified_token_resolver.py +0 -0
  403. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_version_command.py +0 -0
  404. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_version_consistency.py +0 -0
  405. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_vibe_membrane.py +0 -0
  406. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog.py +0 -0
  407. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_dm_wake.py +0 -0
  408. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  409. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  410. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_emit_health.py +0 -0
  411. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_install_flags.py +0 -0
  412. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_model_rung.py +0 -0
  413. {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_stale_peers.py +0 -0
  414. {swarph_cli-0.63.0 → swarph_cli-0.64.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.63.0
3
+ Version: 0.64.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
@@ -292,9 +292,12 @@ Between-sessions memory pass: **VERIFY · ORGANIZE · ENRICH** against a **CLONE
292
292
  ```
293
293
  $ swarph dreaming run --corpus ~/.claude/projects/.../memory --out /tmp/dreaming-out
294
294
  $ swarph dreaming run --corpus <dir> --out <dir> --verify-only
295
- $ echo $? # 0 clean-and-adjudicated | 1 findings | 2 refused | 3 ran-but-adjudicated-nothing
295
+ $ swarph dreaming run --corpus <dir> --out <dir> --notify <cell>
296
+ $ echo $? # 0 clean-and-adjudicated | 1 findings | 2 refused | 3 ran-but-adjudicated-nothing | 4 notify send failed
296
297
  ```
297
298
 
299
+ `--notify <cell>` (#937) sends one mesh DM to `<cell>` **only when the finding set changes** (new and cleared findings named, with counts); an unchanged set sends nothing. State lives in `.last-findings.json` beside the `--out` dir and advances only after a successful send, so a failed send (exit 4) retries on the next run.
300
+
298
301
  **Scope is single-cell:** your corpus and your local transcripts. This is not the cross-agent multi-transcript dreaming from the Anthropic talk — that needs a shared transcript surface this release does not claim.
299
302
 
300
303
  #### The AI Router (why a tool, not a hook)
@@ -244,9 +244,12 @@ Between-sessions memory pass: **VERIFY · ORGANIZE · ENRICH** against a **CLONE
244
244
  ```
245
245
  $ swarph dreaming run --corpus ~/.claude/projects/.../memory --out /tmp/dreaming-out
246
246
  $ swarph dreaming run --corpus <dir> --out <dir> --verify-only
247
- $ echo $? # 0 clean-and-adjudicated | 1 findings | 2 refused | 3 ran-but-adjudicated-nothing
247
+ $ swarph dreaming run --corpus <dir> --out <dir> --notify <cell>
248
+ $ echo $? # 0 clean-and-adjudicated | 1 findings | 2 refused | 3 ran-but-adjudicated-nothing | 4 notify send failed
248
249
  ```
249
250
 
251
+ `--notify <cell>` (#937) sends one mesh DM to `<cell>` **only when the finding set changes** (new and cleared findings named, with counts); an unchanged set sends nothing. State lives in `.last-findings.json` beside the `--out` dir and advances only after a successful send, so a failed send (exit 4) retries on the next run.
252
+
250
253
  **Scope is single-cell:** your corpus and your local transcripts. This is not the cross-agent multi-transcript dreaming from the Anthropic talk — that needs a shared transcript surface this release does not claim.
251
254
 
252
255
  #### The AI Router (why a tool, not a hook)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swarph-cli"
7
- version = "0.63.0"
7
+ version = "0.64.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.63.0"
19
+ __version__ = "0.64.0"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -37,6 +37,10 @@ from swarph_cli.gateway_default import env_gateway
37
37
 
38
38
  TIMEOUT_S = 6
39
39
  MAX_ROWS = 6
40
+ # Probe one past the display cap so audit can tell "exactly 6" from "hit the
41
+ # clamp" (#825 / lab 48145: 90.5% of rows sat on match_count==6 because the
42
+ # query limit WAS the count).
43
+ _PROBE_LIMIT = MAX_ROWS + 1
40
44
 
41
45
  # Identifier token — used for prompt terms and for the Bash shred skip (no
42
46
  # useful symbol-shaped token left after cleaning).
@@ -89,6 +93,12 @@ def extract_raw_and_cleaned(cmd: str) -> Optional[tuple[str, str]]:
89
93
  if tok.startswith("-"):
90
94
  continue
91
95
  raw = tok.strip("'\"")
96
+ # Prefer the longest identifier STILL VISIBLE in the raw pattern
97
+ # before the shredding re.sub (#825). `foo_bar.*[0-9]+` must yield
98
+ # `foo_bar`, not skip-as-shredded or query regex debris.
99
+ idents = [t for t in _IDENT_TOKEN.findall(raw) if len(t) >= 3]
100
+ if idents:
101
+ return (raw, max(idents, key=len))
92
102
  cleaned = re.sub(r"[^\w\s.]", " ", raw).strip()
93
103
  if not cleaned:
94
104
  return None
@@ -308,7 +318,8 @@ def resolve_pending_outcome(self_name: str, subsequent: str,
308
318
 
309
319
  # ── gateway query ─────────────────────────────────────────────────────────
310
320
 
311
- def query_gateway(term: str, gateway: str, token: str, limit: int = MAX_ROWS) -> dict:
321
+ def query_gateway(term: str, gateway: str, token: str,
322
+ limit: int = _PROBE_LIMIT) -> dict:
312
323
  if not (gateway or "").strip():
313
324
  return {"error": "MESH_GATEWAY_URL is not set and swarph ships no default "
314
325
  "gateway host (#578) — the graph was never asked"}
@@ -411,6 +422,9 @@ def _query_and_emit(self_name: str, gateway: str, term: str, *,
411
422
  return
412
423
  env = query_gateway(term, gateway, token)
413
424
  rows = env.get("results") or [] if "error" not in env else []
425
+ capped = len(rows) > MAX_ROWS
426
+ # Audit sees the probe length (MAX_ROWS+1 ⇒ at-least / capped). Display
427
+ # still truncates via render()'s rows[:MAX_ROWS].
414
428
  name_hit = any_symbol_name_contains_term(term, rows) if rows else False
415
429
  fid = firing_id or str(uuid.uuid4())
416
430
  write_audit(self_name, {
@@ -424,13 +438,22 @@ def _query_and_emit(self_name: str, gateway: str, term: str, *,
424
438
  "raw_term": raw_term or term,
425
439
  "skipped": False,
426
440
  "match_count": len(rows),
441
+ "match_count_capped": capped,
427
442
  "any_name_contains_term": name_hit,
428
443
  "error": env.get("error"),
429
444
  })
430
445
  if trigger == "prompt":
431
446
  register_pending_firing(self_name, fid, session_id)
447
+ # Render only the display window so the prompt is not flooded.
448
+ if capped and "error" not in env:
449
+ env = {**env, "results": rows[:MAX_ROWS], "match_count_capped": True}
432
450
  text = render(term, env)
433
451
  if text:
452
+ if capped:
453
+ text = text.rstrip() + (
454
+ f"\n (display capped at {MAX_ROWS}; audit match_count="
455
+ f"{len(rows)} match_count_capped=true)"
456
+ )
434
457
  _emit(text, event_name)
435
458
 
436
459
 
@@ -67,6 +67,12 @@ def _build_parser() -> argparse.ArgumentParser:
67
67
  help="require enrich; refuse (rc=2) if SLM client unavailable (#734)",
68
68
  )
69
69
  run.add_argument("--verify-only", action="store_true", help="verify only; skip organize/enrich")
70
+ run.add_argument(
71
+ "--notify",
72
+ default=None,
73
+ metavar="CELL",
74
+ help="DM CELL when the finding set changes; no DM when it is unchanged (#937)",
75
+ )
70
76
  return p
71
77
 
72
78
 
@@ -95,4 +101,6 @@ def run_dreaming(argv: list[str] | None = None) -> int:
95
101
  forwarded.append("--enrich")
96
102
  if args.verify_only:
97
103
  forwarded.append("--verify-only")
104
+ if getattr(args, "notify", None):
105
+ forwarded.extend(["--notify", args.notify])
98
106
  return dreaming_run.main(forwarded)
@@ -1005,36 +1005,47 @@ def uninstall_hook(
1005
1005
  return 0
1006
1006
 
1007
1007
 
1008
- def _is_installed(settings: dict, command: str, bundle: HookBundle) -> bool:
1009
- """True when ALL of ``bundle``'s bindings' commands are present in settings."""
1008
+ def _event_binding_present(
1009
+ settings: dict, command: str, binding: HookBinding,
1010
+ ) -> bool:
1011
+ """True when one specific event/matcher carries our command."""
1010
1012
  hooks = settings.get("hooks")
1011
1013
  if not isinstance(hooks, dict):
1012
1014
  return False
1015
+ event_list = hooks.get(binding.event)
1016
+ if not isinstance(event_list, list):
1017
+ return False
1018
+ _known = _command_variants_for(command)
1019
+ for entry in event_list:
1020
+ if entry.get("matcher", "") != binding.matcher:
1021
+ continue
1022
+ return any(a.get("command") in _known for a in entry.get("hooks", []))
1023
+ return False
1024
+
1025
+
1026
+ def binding_coverage(
1027
+ settings: dict, command: str, bundle: HookBundle,
1028
+ ) -> tuple[list[str], list[str]]:
1029
+ """Return (present_events, missing_events) for ``bundle``'s bindings (#825).
1030
+
1031
+ A PostToolUse-only install of codegraph-on-grep used to report as plain
1032
+ ``available`` (not installed) while still firing 400 times — the steering
1033
+ half unbound and invisible. Coverage makes PARTIAL legible.
1034
+ """
1035
+ present, missing = [], []
1013
1036
  for b in bundle.bindings:
1014
- event_list = hooks.get(b.event)
1015
- if not isinstance(event_list, list):
1016
- return False
1017
- found = False
1018
- for entry in event_list:
1019
- if entry.get("matcher", "") == b.matcher:
1020
- # #216 review (Copilot, 2nd pass): THE THIRD SITE. Exact
1021
- # matching here makes a LEGACY backslash binding read as NOT
1022
- # INSTALLED, so a Windows cell's real, working hooks list as
1023
- # "unavailable" — the operator is told nothing is installed
1024
- # while the bindings sit right there in settings.json.
1025
- # The previous commit said "one helper, BOTH callers". There
1026
- # were THREE. A rule applied at N-1 sites is the defect this
1027
- # class keeps producing, and it produced it again inside the
1028
- # fix for it.
1029
- _known = _command_variants_for(command)
1030
- if any(
1031
- a.get("command") in _known for a in entry.get("hooks", [])
1032
- ):
1033
- found = True
1034
- break
1035
- if not found:
1036
- return False
1037
- return True
1037
+ label = b.event if not b.matcher else f"{b.event}:{b.matcher}"
1038
+ if _event_binding_present(settings, command, b):
1039
+ present.append(label)
1040
+ else:
1041
+ missing.append(label)
1042
+ return present, missing
1043
+
1044
+
1045
+ def _is_installed(settings: dict, command: str, bundle: HookBundle) -> bool:
1046
+ """True when ALL of ``bundle``'s bindings' commands are present in settings."""
1047
+ present, missing = binding_coverage(settings, command, bundle)
1048
+ return bool(present) and not missing
1038
1049
 
1039
1050
 
1040
1051
  def list_hooks(
@@ -1045,8 +1056,10 @@ def list_hooks(
1045
1056
  ) -> int:
1046
1057
  """List builtin hooks with install status. One greppable line per builtin::
1047
1058
 
1048
- name [installed|available] trust=builtin — description
1059
+ name [installed|partial|available] trust=builtin — description
1049
1060
 
1061
+ ``partial`` (#825): at least one binding present but not the full set —
1062
+ the lab-ovh codegraph case (PostToolUse only, UserPromptSubmit/Stop absent).
1050
1063
  When installed and the script carries a ``swarph-cli-bundle-version`` stamp
1051
1064
  (#830), a second line reports match / mismatch vs the running package.
1052
1065
  """
@@ -1054,14 +1067,26 @@ def list_hooks(
1054
1067
  hooks_home_p = Path(hooks_home).expanduser()
1055
1068
  for name in sorted(BUILTIN_HOOKS):
1056
1069
  bundle = BUILTIN_HOOKS[name]
1057
- command = _installed_command(bundle, hooks_home)
1058
- # Read side of the same ladder: a legacy install reported as "available"
1059
- # invites the reinstall that produces a DUPLICATE binding.
1060
- status = ("installed"
1061
- if any(_is_installed(settings, c, bundle)
1062
- for c in _installed_command_variants(bundle, hooks_home))
1063
- else "available")
1070
+ variants = _installed_command_variants(bundle, hooks_home)
1071
+ # Pick the first variant that has ANY binding coverage for reporting.
1072
+ present: list[str] = []
1073
+ missing: list[str] = [b.event for b in bundle.bindings]
1074
+ for c in variants:
1075
+ p, m = binding_coverage(settings, c, bundle)
1076
+ if len(p) > len(present):
1077
+ present, missing = p, m
1078
+ if present and not missing:
1079
+ status = "installed"
1080
+ elif present and missing:
1081
+ status = "partial"
1082
+ else:
1083
+ status = "available"
1064
1084
  out(f"{name} [{status}] trust=builtin — {bundle.description}")
1085
+ if status == "partial":
1086
+ out(f" bindings present: {', '.join(present) or '(none)'}")
1087
+ out(f" bindings MISSING: {', '.join(missing)} "
1088
+ f"— re-run: swarph hooks add {name} (#825 fleet bind)")
1089
+ continue
1065
1090
  if status != "installed":
1066
1091
  continue
1067
1092
  script = (hooks_home_p / bundle.script_name).expanduser()
@@ -0,0 +1,96 @@
1
+ """Notify the owning cell when the dreaming finding set changes (#937).
2
+
3
+ The finding set is disagree + surface_disagreement, keyed file:line:kind, plus
4
+ each non-empty organize finding keyed organize:<text>. State lives at
5
+ <out-parent>/.last-findings.json and is written only after a successful send.
6
+ An unchanged set sends nothing. A missing state file is a first run: send the
7
+ full set once.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ from pathlib import Path
13
+
14
+
15
+ class NotifySendError(Exception):
16
+ """The mesh send failed. Distinct from a findings exit."""
17
+
18
+
19
+ def finding_keys(verdicts, organized) -> list[str]:
20
+ keys: set[str] = set()
21
+ for v in verdicts or []:
22
+ if v.get("verdict") in ("disagree", "surface_disagreement"):
23
+ keys.add(f"{v.get('file')}:{v.get('line')}:{v.get('kind')}")
24
+ for line in (organized or {}).get("findings") or []:
25
+ text = str(line).strip()
26
+ if text:
27
+ keys.add(f"organize:{text}")
28
+ return sorted(keys)
29
+
30
+
31
+ def _load_previous(path: Path) -> list[str] | None:
32
+ if not path.exists():
33
+ return None
34
+ data = json.loads(path.read_text(encoding="utf-8"))
35
+ return list(data.get("keys") or [])
36
+
37
+
38
+ def _body(keys: list[str], previous: list[str] | None) -> str:
39
+ if previous is None:
40
+ lines = ["dreaming findings first run", f"counts: {len(keys)}"]
41
+ lines.extend(keys)
42
+ return "\n".join(lines)
43
+ prev = set(previous)
44
+ cur = set(keys)
45
+ new = sorted(cur - prev)
46
+ cleared = sorted(prev - cur)
47
+ lines = [
48
+ "dreaming findings changed",
49
+ "new: " + (", ".join(new) if new else "(none)"),
50
+ "cleared: " + (", ".join(cleared) if cleared else "(none)"),
51
+ f"counts: {len(keys)} was {len(previous)}",
52
+ ]
53
+ return "\n".join(lines)
54
+
55
+
56
+ def apply(out: Path, verdicts, organized, cell: str, sender) -> bool:
57
+ """Send one DM when the set changes. Return True if a DM was sent.
58
+
59
+ ``sender(cell, body)`` raises on failure. State is not written then.
60
+ """
61
+ out = Path(out)
62
+ keys = finding_keys(verdicts, organized)
63
+ state = out.parent / ".last-findings.json"
64
+ previous = _load_previous(state)
65
+ if previous is not None and sorted(previous) == keys:
66
+ return False
67
+ body = _body(keys, previous)
68
+ try:
69
+ sender(cell, body)
70
+ except NotifySendError:
71
+ raise
72
+ except Exception as exc:
73
+ raise NotifySendError(str(exc)) from exc
74
+ state.write_text(json.dumps({"keys": keys}, indent=2) + "\n", encoding="utf-8")
75
+ return True
76
+
77
+
78
+ def mesh_sender(cell: str, content: str) -> None:
79
+ """Same path as ``swarph mesh send``: one status DM, no second transport."""
80
+ import argparse
81
+
82
+ from swarph_cli.commands.mesh import _run_send
83
+ from swarph_cli.gateway_default import env_gateway
84
+
85
+ ns = argparse.Namespace(
86
+ to=cell,
87
+ kind="status",
88
+ content=content,
89
+ content_file=None,
90
+ self_name=None,
91
+ token_file=None,
92
+ gateway=env_gateway(),
93
+ )
94
+ rc = _run_send(ns)
95
+ if rc != 0:
96
+ raise NotifySendError(f"mesh send exited {rc}")
@@ -18,6 +18,12 @@ def main(argv=None) -> int:
18
18
  help="require enrich; refuse (rc=2) if SLM client is unavailable (#734)",
19
19
  )
20
20
  ap.add_argument("--verify-only", action="store_true")
21
+ ap.add_argument(
22
+ "--notify",
23
+ default=None,
24
+ metavar="CELL",
25
+ help="DM CELL when the finding set changes; unchanged set sends nothing (#937)",
26
+ )
21
27
  a = ap.parse_args(argv)
22
28
  if a.enrich and a.no_enrich:
23
29
  print("dreaming: refusing to run -- --enrich and --no-enrich conflict",
@@ -83,10 +89,18 @@ def main(argv=None) -> int:
83
89
  # 1 disagreements or surface_disagreements found — findings to read
84
90
  # 2 refused to run (dirty destination)
85
91
  # 3 RAN BUT ADJUDICATED NOTHING — not clean, not findings
92
+ # 4 notify send failed — instrument failure, not findings
86
93
  # `mention` is adjudicated (the artifact WAS compared to the world) but never
87
94
  # `bad`: the memory asserted nothing, so there is no finding to read.
88
95
  adjudicated = sum(1 for v in verdicts if v["verdict"] in ("agree", "disagree", "mention"))
89
96
  bad = [v for v in verdicts if v["verdict"] in ("disagree", "surface_disagreement")]
97
+ if getattr(a, "notify", None):
98
+ from swarph_cli.dreaming.notify import NotifySendError, apply, mesh_sender
99
+ try:
100
+ apply(out, verdicts, organized, a.notify, mesh_sender)
101
+ except NotifySendError as exc:
102
+ print("dreaming: notify failed -- %s" % exc, file=sys.stderr)
103
+ return 4
90
104
  if bad:
91
105
  return 1
92
106
  if adjudicated == 0:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swarph-cli
3
- Version: 0.63.0
3
+ Version: 0.64.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
@@ -292,9 +292,12 @@ Between-sessions memory pass: **VERIFY · ORGANIZE · ENRICH** against a **CLONE
292
292
  ```
293
293
  $ swarph dreaming run --corpus ~/.claude/projects/.../memory --out /tmp/dreaming-out
294
294
  $ swarph dreaming run --corpus <dir> --out <dir> --verify-only
295
- $ echo $? # 0 clean-and-adjudicated | 1 findings | 2 refused | 3 ran-but-adjudicated-nothing
295
+ $ swarph dreaming run --corpus <dir> --out <dir> --notify <cell>
296
+ $ echo $? # 0 clean-and-adjudicated | 1 findings | 2 refused | 3 ran-but-adjudicated-nothing | 4 notify send failed
296
297
  ```
297
298
 
299
+ `--notify <cell>` (#937) sends one mesh DM to `<cell>` **only when the finding set changes** (new and cleared findings named, with counts); an unchanged set sends nothing. State lives in `.last-findings.json` beside the `--out` dir and advances only after a successful send, so a failed send (exit 4) retries on the next run.
300
+
298
301
  **Scope is single-cell:** your corpus and your local transcripts. This is not the cross-agent multi-transcript dreaming from the Anthropic talk — that needs a shared transcript surface this release does not claim.
299
302
 
300
303
  #### The AI Router (why a tool, not a hook)
@@ -117,6 +117,7 @@ src/swarph_cli/dreaming/candidates.py
117
117
  src/swarph_cli/dreaming/clone.py
118
118
  src/swarph_cli/dreaming/enrich.py
119
119
  src/swarph_cli/dreaming/index_check.py
120
+ src/swarph_cli/dreaming/notify.py
120
121
  src/swarph_cli/dreaming/organize.py
121
122
  src/swarph_cli/dreaming/probes.py
122
123
  src/swarph_cli/dreaming/report.py
@@ -213,6 +214,7 @@ tests/test_762_cards_edit_priority.py
213
214
  tests/test_801_confirm_flow_cli.py
214
215
  tests/test_802_stage_history.py
215
216
  tests/test_825_codegraph_hook_noise.py
217
+ tests/test_825_remaining_cap_shred_bind.py
216
218
  tests/test_829_counterfactual_column.py
217
219
  tests/test_830_hook_binding_version.py
218
220
  tests/test_84_cli_labels.py
@@ -220,6 +222,7 @@ tests/test_866_doctrine_guide.py
220
222
  tests/test_872_identity_refuses_not_warns.py
221
223
  tests/test_874_source_text.py
222
224
  tests/test_888_opencode_data_dir_can_fail.py
225
+ tests/test_937_dreaming_notify.py
223
226
  tests/test_add_security_gate.py
224
227
  tests/test_artifact_add.py
225
228
  tests/test_artifact_hash.py
@@ -0,0 +1,165 @@
1
+ """#825 remaining — match_count cap honesty + recoverable-symbol extract + partial bind.
2
+
3
+ Can-fail traps: a 7-row probe must set match_count_capped; a raw pattern that
4
+ contains an identifier but used to shred must yield that identifier.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import json
9
+ from pathlib import Path
10
+
11
+ import pytest
12
+
13
+ from swarph_cli.commands import codegraph_hook as ch
14
+ from swarph_cli.commands import hooks
15
+
16
+
17
+ class _Stdin:
18
+ def __init__(self, s):
19
+ self._s = s
20
+
21
+ def read(self):
22
+ return self._s
23
+
24
+
25
+ def _home(monkeypatch, tmp_path, with_token=True):
26
+ home = tmp_path / "home"
27
+ if with_token:
28
+ (home / ".config" / "swarph").mkdir(parents=True)
29
+ (home / ".config" / "swarph" / "cursor-win.peer_token").write_text(
30
+ "tok", encoding="utf-8")
31
+ monkeypatch.setenv("HOME", str(home))
32
+ monkeypatch.setenv("USERPROFILE", str(home))
33
+ monkeypatch.setenv("SWARPH_SELF", "cursor-win")
34
+ return home
35
+
36
+
37
+ def _seven_rows():
38
+ return {
39
+ "results": [
40
+ {"repo": "r", "file_path": f"a{i}.py", "start_line": i,
41
+ "kind": "function", "name": f"_firejail_argv_{i}", "callers": i}
42
+ for i in range(7)
43
+ ],
44
+ "freshness": [{"index_age_hours": 1.0}],
45
+ }
46
+
47
+
48
+ def test_825_match_count_capped_when_probe_exceeds_display(
49
+ monkeypatch, capsys, tmp_path):
50
+ """Can-fail: today's code asked limit=MAX_ROWS so match_count could never
51
+ exceed 6 and 90.5% of live rows sat exactly on the clamp with no flag."""
52
+ home = _home(monkeypatch, tmp_path)
53
+ seen = {}
54
+
55
+ def _qg(term, gateway, token, limit=None):
56
+ seen["limit"] = limit if limit is not None else ch._PROBE_LIMIT
57
+ return _seven_rows()
58
+
59
+ monkeypatch.setattr(ch, "query_gateway", _qg)
60
+ monkeypatch.setattr("sys.stdin", _Stdin(json.dumps({
61
+ "hook_event_name": "PostToolUse",
62
+ "tool_input": {"command": r'grep -n "_firejail_argv" src/x.py'},
63
+ })))
64
+ assert ch.run_codegraph_hook([]) == 0
65
+ assert seen["limit"] == ch.MAX_ROWS + 1
66
+ audit = Path(home) / "swarph_state" / "cursor-win" / "codegraph-hook-audit.jsonl"
67
+ row = json.loads(audit.read_text(encoding="utf-8").splitlines()[0])
68
+ assert row["match_count"] == 7
69
+ assert row["match_count_capped"] is True
70
+ out = capsys.readouterr().out
71
+ assert "match_count_capped=true" in out
72
+
73
+
74
+ def test_825_match_count_uncapped_when_under_display(monkeypatch, tmp_path):
75
+ home = _home(monkeypatch, tmp_path)
76
+ env = {
77
+ "results": [
78
+ {"repo": "r", "file_path": "a.py", "start_line": 1,
79
+ "kind": "function", "name": "_firejail_argv", "callers": 9},
80
+ ],
81
+ "freshness": [{"index_age_hours": 1.0}],
82
+ }
83
+ monkeypatch.setattr(ch, "query_gateway", lambda *a, **k: env)
84
+ monkeypatch.setattr("sys.stdin", _Stdin(json.dumps({
85
+ "hook_event_name": "PostToolUse",
86
+ "tool_input": {"command": r'grep -n "_firejail_argv" src/x.py'},
87
+ })))
88
+ assert ch.run_codegraph_hook([]) == 0
89
+ audit = Path(home) / "swarph_state" / "cursor-win" / "codegraph-hook-audit.jsonl"
90
+ row = json.loads(audit.read_text(encoding="utf-8").splitlines()[0])
91
+ assert row["match_count"] == 1
92
+ assert row["match_count_capped"] is False
93
+
94
+
95
+ def test_825_recoverable_symbol_inside_regex_is_not_shredded():
96
+ """Live-shaped specimen: identifier still present inside a regex pattern.
97
+
98
+ OLD extract ran re.sub first and lost the symbol (or skip_reason=shredded).
99
+ NEW prefers the longest ident token in the raw pattern.
100
+ """
101
+ cmd = r"""grep -rn --include='*.py' '_firejail_argv\|legacy_name' src/"""
102
+ pair = ch.extract_raw_and_cleaned(cmd)
103
+ assert pair is not None
104
+ raw, cleaned = pair
105
+ assert cleaned == "_firejail_argv"
106
+ assert not ch.term_is_shredded(raw, cleaned)
107
+
108
+
109
+ def test_825_pure_regex_debris_still_shredded():
110
+ """Can-fail companion: no identifier ≥3 → still shredded (skip path)."""
111
+ cmd = r'grep -n "^\s*[0-9]+[-:]\s*[a-z_]+\s*:" src/x.py'
112
+ pair = ch.extract_raw_and_cleaned(cmd)
113
+ assert pair is not None
114
+ raw, cleaned = pair
115
+ # May recover 'a' from [a-z_] only as len<3 junk — must still shred.
116
+ assert ch.term_is_shredded(raw, cleaned) or len(cleaned) < 3 or cleaned in {
117
+ "a", "z_", "s",
118
+ }
119
+ # Stronger: if we only got short debris, shredded; if extract returned a
120
+ # long false ident from character class, that would be a NEW defect.
121
+ idents = [t for t in ch._IDENT_TOKEN.findall(raw) if len(t) >= 3]
122
+ if not idents:
123
+ assert ch.term_is_shredded(raw, cleaned)
124
+
125
+
126
+ def test_825_old_extract_would_miss_recoverable_symbol():
127
+ """Can-fail: verbatim OLD expression fails the fixture the NEW one passes."""
128
+ raw = r"_firejail_argv\|legacy_name"
129
+ old_cleaned = __import__("re").sub(r"[^\w\s.]", " ", raw).strip()
130
+ # Old shred leaves tokens but the chosen 'term' was the whole cleaned
131
+ # string — and term_is_shredded looked for idents in cleaned. Reconstruct
132
+ # the failure mode lab named: debris asked of the index.
133
+ assert "firejail" in old_cleaned or "_firejail_argv" in old_cleaned.split()
134
+ # NEW picks the symbol directly:
135
+ assert ch.extract_raw_and_cleaned(
136
+ f"grep -n '{raw}' src/x.py"
137
+ )[1] == "_firejail_argv"
138
+
139
+
140
+ def test_825_partial_bind_is_legible(tmp_path):
141
+ """PostToolUse-only install must list as partial, not available/installed."""
142
+ settings_path = tmp_path / "settings.json"
143
+ hooks_home = tmp_path / "hooks"
144
+ hooks_home.mkdir()
145
+ bundle = hooks.resolve_builtin("codegraph-on-grep")
146
+ script = hooks_home / bundle.script_name
147
+ script.write_text(bundle.script_body, encoding="utf-8")
148
+ cmd = hooks._installed_command(bundle, hooks_home)
149
+ settings = {
150
+ "hooks": {
151
+ "PostToolUse": [{
152
+ "matcher": "Bash",
153
+ "hooks": [{"type": "command", "command": cmd}],
154
+ }],
155
+ }
156
+ }
157
+ settings_path.write_text(json.dumps(settings), encoding="utf-8")
158
+ lines = []
159
+ hooks.list_hooks(
160
+ settings_path=settings_path, hooks_home=hooks_home, out=lines.append,
161
+ )
162
+ blob = "\n".join(lines)
163
+ assert "codegraph-on-grep [partial]" in blob
164
+ assert "UserPromptSubmit" in blob
165
+ assert "MISSING" in blob