swarph-cli 0.53.2__tar.gz → 0.53.3__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 (362) hide show
  1. {swarph_cli-0.53.2/src/swarph_cli.egg-info → swarph_cli-0.53.3}/PKG-INFO +1 -1
  2. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/pyproject.toml +1 -1
  3. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/__init__.py +1 -1
  4. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/board.py +68 -7
  5. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/highlight.py +66 -13
  6. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/monitor.py +92 -26
  7. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/watchdog.py +11 -0
  8. swarph_cli-0.53.3/src/swarph_cli/orphan_daemons.py +448 -0
  9. {swarph_cli-0.53.2 → swarph_cli-0.53.3/src/swarph_cli.egg-info}/PKG-INFO +1 -1
  10. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli.egg-info/SOURCES.txt +2 -0
  11. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_654_reexec.py +32 -3
  12. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_board_command.py +57 -0
  13. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_highlight_command.py +63 -2
  14. swarph_cli-0.53.3/tests/test_orphan_daemons.py +238 -0
  15. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/LICENSE +0 -0
  16. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/README.md +0 -0
  17. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/setup.cfg +0 -0
  18. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/__main__.py +0 -0
  19. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/bench/__init__.py +0 -0
  20. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/bench/backends.py +0 -0
  21. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/bench/pack.py +0 -0
  22. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/bench/prices.py +0 -0
  23. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/bench/quality.py +0 -0
  24. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/bench/refresh_prices.py +0 -0
  25. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/bench/runner.py +0 -0
  26. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/bench/validate.py +0 -0
  27. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/caller.py +0 -0
  28. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/capture/__init__.py +0 -0
  29. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/capture/harden.py +0 -0
  30. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/capture/lineage.py +0 -0
  31. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/capture/liveness.py +0 -0
  32. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/capture/manifest.py +0 -0
  33. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/capture/paths.py +0 -0
  34. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/capture/verify.py +0 -0
  35. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/cell.py +0 -0
  36. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/chain_token.py +0 -0
  37. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/__init__.py +0 -0
  38. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/_content.py +0 -0
  39. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/_display.py +0 -0
  40. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/_gateway_client.py +0 -0
  41. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/add.py +0 -0
  42. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/bench.py +0 -0
  43. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/board_merge_check.py +0 -0
  44. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/brain.py +0 -0
  45. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/brain_ask.py +0 -0
  46. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/cell.py +0 -0
  47. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  48. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/channel.py +0 -0
  49. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/chat.py +0 -0
  50. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/codegraph.py +0 -0
  51. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/codegraph_hook.py +0 -0
  52. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  53. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/codex_waker.py +0 -0
  54. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/compress.py +0 -0
  55. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/daemon.py +0 -0
  56. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/event.py +0 -0
  57. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/gateway.py +0 -0
  58. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/gh_route.py +0 -0
  59. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/group.py +0 -0
  60. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/guide.py +0 -0
  61. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/hook_output.py +0 -0
  62. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/hooks.py +0 -0
  63. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/import_session.py +0 -0
  64. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/init.py +0 -0
  65. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  66. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/install_hook.py +0 -0
  67. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  68. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
  69. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  70. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/lane.py +0 -0
  71. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/mcp_server.py +0 -0
  72. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/memory.py +0 -0
  73. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
  74. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/memory_sync.py +0 -0
  75. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/mesh.py +0 -0
  76. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/okf_links.py +0 -0
  77. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/onboard.py +0 -0
  78. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  79. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  80. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/protocol_handler.py +0 -0
  81. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/ratify.py +0 -0
  82. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/schedule.py +0 -0
  83. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/security.py +0 -0
  84. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/service.py +0 -0
  85. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/spawn.py +0 -0
  86. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/timeline.py +0 -0
  87. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/version.py +0 -0
  88. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/commands/wake_hook_output.py +0 -0
  89. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/compress/__init__.py +0 -0
  90. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/compress/levers.py +0 -0
  91. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/compress/marker.py +0 -0
  92. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/compress/verify.py +0 -0
  93. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/console_safe.py +0 -0
  94. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/delivery_queue.py +0 -0
  95. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/gateway/__init__.py +0 -0
  96. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/gateway/feature_registry.py +0 -0
  97. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/gateway/lanes_control.py +0 -0
  98. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/gateway/schema.sql +0 -0
  99. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/gateway/server.py +0 -0
  100. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/gateway/services_control.py +0 -0
  101. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/gateway_default.py +0 -0
  102. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/gh_identity.py +0 -0
  103. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/guide/GUIDE.md +0 -0
  104. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/main.py +0 -0
  105. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/multiplexer.py +0 -0
  106. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/parsers/__init__.py +0 -0
  107. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/parsers/claude.py +0 -0
  108. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  109. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  110. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  111. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  112. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  113. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  114. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  115. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  116. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  117. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  118. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  119. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/peer_executor.py +0 -0
  120. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/peer_executor_windows.py +0 -0
  121. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/peer_reconciliation.py +0 -0
  122. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/peer_reply_outbox.py +0 -0
  123. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/peer_service_host.py +0 -0
  124. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/peer_service_payload.py +0 -0
  125. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/peer_service_reply.py +0 -0
  126. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/peer_staging.py +0 -0
  127. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/scripts/__init__.py +0 -0
  128. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  129. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  130. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  131. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  132. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/service/__init__.py +0 -0
  133. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/service/app.py +0 -0
  134. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/service/providers.py +0 -0
  135. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/session_bridge.py +0 -0
  136. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  137. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  138. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/stall_alert.py +0 -0
  139. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/codex-waker.default +0 -0
  140. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  141. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  142. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  143. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  144. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  145. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
  146. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
  147. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  148. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  149. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  150. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  151. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  152. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  153. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli/tokens.py +0 -0
  154. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  155. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  156. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli.egg-info/requires.txt +0 -0
  157. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/src/swarph_cli.egg-info/top_level.txt +0 -0
  158. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_124_register_merge.py +0 -0
  159. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  160. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_201_win32_bash_refusal.py +0 -0
  161. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_243_onboard_per_peer_token.py +0 -0
  162. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_307_task4_ask_reply.py +0 -0
  163. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  164. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_319_refusal_exit_codes.py +0 -0
  165. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_323_mistral_backend.py +0 -0
  166. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_397_gh_identity_router.py +0 -0
  167. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_397_router_preflight.py +0 -0
  168. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_467b_onboard_operator_credential.py +0 -0
  169. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_523_guide.py +0 -0
  170. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_524_conftest_hermeticity.py +0 -0
  171. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_532_accept_flag.py +0 -0
  172. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_535_version_capability.py +0 -0
  173. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_546_default_gateway.py +0 -0
  174. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_548_gateway_remainder.py +0 -0
  175. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_552_codegraph_gateway.py +0 -0
  176. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_555_relay_row_shape.py +0 -0
  177. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_556_relay_freshness.py +0 -0
  178. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  179. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_579_register_bootstrap_message.py +0 -0
  180. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_644_monitor_supervision.py +0 -0
  181. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_648_install_unit.py +0 -0
  182. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_84_cli_labels.py +0 -0
  183. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_add_security_gate.py +0 -0
  184. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_artifact_add.py +0 -0
  185. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_artifact_hash.py +0 -0
  186. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_artifact_lib.py +0 -0
  187. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_artifact_mcp.py +0 -0
  188. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_artifact_skill.py +0 -0
  189. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_artifact_tool.py +0 -0
  190. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_artifact_uri.py +0 -0
  191. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_bench_backends.py +0 -0
  192. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_bench_command.py +0 -0
  193. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_bench_pack.py +0 -0
  194. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_bench_prices.py +0 -0
  195. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_bench_quality.py +0 -0
  196. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_bench_runner.py +0 -0
  197. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_bench_validate.py +0 -0
  198. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_board_card_thread.py +0 -0
  199. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_board_merge_check.py +0 -0
  200. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_board_obligation_close.py +0 -0
  201. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_brain_ask_command.py +0 -0
  202. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_brain_ask_env_diagnosis.py +0 -0
  203. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_brain_ask_identity_explicitness.py +0 -0
  204. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_brain_command.py +0 -0
  205. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_caller_meta_guard.py +0 -0
  206. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_capture_lineage.py +0 -0
  207. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_capture_liveness.py +0 -0
  208. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_capture_manifest.py +0 -0
  209. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_capture_paths.py +0 -0
  210. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_capture_security.py +0 -0
  211. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_cell_command_dispatch.py +0 -0
  212. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_cell_harden.py +0 -0
  213. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_cell_loader.py +0 -0
  214. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_cell_selfcheck.py +0 -0
  215. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_cell_verify.py +0 -0
  216. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_chain_token.py +0 -0
  217. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_channel_command.py +0 -0
  218. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  219. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_channel_post.py +0 -0
  220. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_channel_wake_policy_filter.py +0 -0
  221. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_chat_command.py +0 -0
  222. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_claude_parser.py +0 -0
  223. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_claude_tmux_template.py +0 -0
  224. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_codegraph_caller_scope.py +0 -0
  225. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_codegraph_command.py +0 -0
  226. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_codegraph_hook.py +0 -0
  227. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_codegraph_mcp.py +0 -0
  228. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_codex_waker.py +0 -0
  229. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_compress_caller_convention.py +0 -0
  230. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_compress_command.py +0 -0
  231. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_compress_levers.py +0 -0
  232. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_compress_marker.py +0 -0
  233. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_compress_verify.py +0 -0
  234. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_console_encoding_e2e.py +0 -0
  235. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_content_composition.py +0 -0
  236. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_cursor_membrane.py +0 -0
  237. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_daemon_command.py +0 -0
  238. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_daemon_console_encoding.py +0 -0
  239. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_daemon_delivery.py +0 -0
  240. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_delivery_queue.py +0 -0
  241. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_display_sanitize.py +0 -0
  242. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  243. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_event_emit.py +0 -0
  244. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_feature_to_uri.py +0 -0
  245. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_gateway_brain.py +0 -0
  246. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_gateway_client.py +0 -0
  247. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_gateway_command.py +0 -0
  248. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_gateway_message_idempotency.py +0 -0
  249. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  250. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_group_command.py +0 -0
  251. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_guide_commands_parse.py +0 -0
  252. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_guide_selfcheck.py +0 -0
  253. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_heartbeat_check.py +0 -0
  254. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hook_output.py +0 -0
  255. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hooks_activity_marker.py +0 -0
  256. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hooks_add.py +0 -0
  257. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hooks_bundle.py +0 -0
  258. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hooks_init.py +0 -0
  259. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hooks_legacy_generation_removal.py +0 -0
  260. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hooks_lifecycle.py +0 -0
  261. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hooks_merge.py +0 -0
  262. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hooks_verify.py +0 -0
  263. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  264. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_hooks_win32_command_path.py +0 -0
  265. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_import_command.py +0 -0
  266. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_inbox_identity_provenance.py +0 -0
  267. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_init_command.py +0 -0
  268. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_init_provider_menu.py +0 -0
  269. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_install_codex_hooks.py +0 -0
  270. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_install_hook.py +0 -0
  271. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_install_multiplexer_command.py +0 -0
  272. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_install_postcompact_hook.py +0 -0
  273. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_install_wake_hook.py +0 -0
  274. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_lane_command.py +0 -0
  275. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_main.py +0 -0
  276. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_main_unknown_verb_guard.py +0 -0
  277. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_mcp_server.py +0 -0
  278. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_memory_command.py +0 -0
  279. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_memory_gateway.py +0 -0
  280. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_memory_sync.py +0 -0
  281. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_memory_sync_membrane.py +0 -0
  282. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_mesh_command.py +0 -0
  283. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_mesh_inbox_mark_read.py +0 -0
  284. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_mesh_inbox_sanitize.py +0 -0
  285. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_mesh_send_unknown_peer.py +0 -0
  286. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_mesh_sidecar.py +0 -0
  287. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  288. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  289. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_meta_edge_identity.py +0 -0
  290. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_monitor_channel_poll.py +0 -0
  291. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_monitor_cli.py +0 -0
  292. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_monitor_daemon_collision.py +0 -0
  293. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_monitor_self_name_verification.py +0 -0
  294. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_monitor_state_split.py +0 -0
  295. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_multiplexer.py +0 -0
  296. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_muse_membrane.py +0 -0
  297. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_muse_own_cli.py +0 -0
  298. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_obligation_close_is_surfaced.py +0 -0
  299. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_okf_links.py +0 -0
  300. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_onboard_command.py +0 -0
  301. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_packaged_artifacts_exist.py +0 -0
  302. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_packaged_skills.py +0 -0
  303. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_peer_executor.py +0 -0
  304. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_peer_executor_windows.py +0 -0
  305. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_peer_reply_drain_command.py +0 -0
  306. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_peer_reply_drain_supervisor.py +0 -0
  307. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_peer_reply_outbox.py +0 -0
  308. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_peer_reply_transport.py +0 -0
  309. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_peer_service_e2e.py +0 -0
  310. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_peer_service_host.py +0 -0
  311. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_peer_service_payload.py +0 -0
  312. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_peer_service_reply.py +0 -0
  313. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_postcompact_recall.py +0 -0
  314. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_process_liveness.py +0 -0
  315. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_protocol_handler.py +0 -0
  316. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_providers_isolation.py +0 -0
  317. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_ratify_command.py +0 -0
  318. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_readme_claims_no_gateway_default.py +0 -0
  319. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_repl_caller_convention.py +0 -0
  320. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_schedule_command.py +0 -0
  321. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_schedule_create_contract.py +0 -0
  322. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_security.py +0 -0
  323. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_service_app.py +0 -0
  324. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_service_command.py +0 -0
  325. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_service_providers.py +0 -0
  326. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_session_bridge_inject.py +0 -0
  327. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_session_bridge_probe.py +0 -0
  328. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_session_bridge_resolve.py +0 -0
  329. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_session_path_role_gate.py +0 -0
  330. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_shipped_units_match_the_cli.py +0 -0
  331. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_smoke_chat.py +0 -0
  332. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_smoke_one_shot.py +0 -0
  333. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_smoke_phase_5_5.py +0 -0
  334. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_spawn_base_hoist.py +0 -0
  335. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_spawn_command.py +0 -0
  336. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_spawn_identity_stamp.py +0 -0
  337. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_spawn_live_pin.py +0 -0
  338. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_spawn_mitosis_lineage.py +0 -0
  339. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_spawn_tmux_session.py +0 -0
  340. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_spawn_windows_relaunch.py +0 -0
  341. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_stall_alert.py +0 -0
  342. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_subprocess_decode_encoding.py +0 -0
  343. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_timeline_command.py +0 -0
  344. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_tmux_wake_runstate_defer.py +0 -0
  345. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_tmux_wake_session_reanchor.py +0 -0
  346. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_tmux_wake_stale.py +0 -0
  347. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_tmux_wake_submit_verify.py +0 -0
  348. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_token_file_one_parser.py +0 -0
  349. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_token_precedence_explicit_first.py +0 -0
  350. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_unified_token_resolver.py +0 -0
  351. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_version_command.py +0 -0
  352. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_version_consistency.py +0 -0
  353. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_vibe_membrane.py +0 -0
  354. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_watchdog.py +0 -0
  355. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_watchdog_dm_wake.py +0 -0
  356. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  357. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  358. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_watchdog_emit_health.py +0 -0
  359. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_watchdog_install_flags.py +0 -0
  360. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_watchdog_model_rung.py +0 -0
  361. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/tests/test_watchdog_stale_peers.py +0 -0
  362. {swarph_cli-0.53.2 → swarph_cli-0.53.3}/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.53.2
3
+ Version: 0.53.3
4
4
  Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
5
5
  Author: Pierre Samson, Claude Opus
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swarph-cli"
7
- version = "0.53.2"
7
+ version = "0.53.3"
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.53.2"
19
+ __version__ = "0.53.3"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -199,16 +199,77 @@ def _cards_of(data):
199
199
  return data.get("cards", []) if isinstance(data, dict) else (data or [])
200
200
 
201
201
 
202
+ def _rel_due(days_until) -> str:
203
+ """Spell the relative age — a bare date makes the reader compute (#145)."""
204
+ if days_until is None:
205
+ return "?"
206
+ n = int(days_until)
207
+ if n < 0:
208
+ d = -n
209
+ return "1 day ago" if d == 1 else f"{d} days ago"
210
+ if n == 0:
211
+ return "today"
212
+ return "in 1 day" if n == 1 else f"in {n} days"
213
+
214
+
215
+ def _format_due_head(data) -> list[str]:
216
+ """Render the list endpoint's `due` summary + dated cards at the head.
217
+
218
+ Built ONLY from the LIST response (#661: GET /board/cards/{id} returns
219
+ due_state=None even when due_at is set — a single-card readout would
220
+ report zero overdue forever with no error).
221
+ """
222
+ if not isinstance(data, dict):
223
+ return []
224
+ due = data.get("due")
225
+ if not isinstance(due, dict):
226
+ return []
227
+ lines = [
228
+ f"due: overdue={due.get('overdue', 0)} today={due.get('today', 0)} "
229
+ f"upcoming={due.get('upcoming', 0)} undated={due.get('undated', 0)}"
230
+ ]
231
+ # Prefer overdue, then today, then upcoming — sorted by days_until ascending
232
+ # so the most overdue sits first. Pull rows from the cards array (the due
233
+ # block itself is counts only).
234
+ dated = [c for c in _cards_of(data)
235
+ if c.get("due_state") in ("overdue", "today", "upcoming")]
236
+ order = {"overdue": 0, "today": 1, "upcoming": 2}
237
+ dated.sort(key=lambda c: (
238
+ order.get(c.get("due_state"), 9),
239
+ c.get("days_until") is None,
240
+ c.get("days_until") if c.get("days_until") is not None else 0,
241
+ ))
242
+ for c in dated:
243
+ title = _s(c.get("title") or "")
244
+ if len(title) > 60:
245
+ title = title[:57] + "..."
246
+ lines.append(
247
+ f" #{c.get('id')} {c.get('due_state'):<9} "
248
+ f"{_rel_due(c.get('days_until')):<14} {title}"
249
+ )
250
+ if not dated and (due.get("overdue") or due.get("today") or due.get("upcoming")):
251
+ # Counts say something is dated but this page's cards don't carry them
252
+ # (filtered list / pagination). Say so — silent empty is the #145 lie.
253
+ lines.append(" (dated cards not in this page — widen the list filter)")
254
+ elif not dated:
255
+ lines.append(" (none dated in this list)")
256
+ return lines
257
+
258
+
202
259
  def _format_cards(data) -> str:
260
+ head = _format_due_head(data)
203
261
  rows = _cards_of(data)
204
262
  if not rows:
205
- return "(no cards)"
206
- lines = [f"{'ID':>4} {'STAGE':<9} {'PRJ':>4} {'AI²':<3} TITLE"]
207
- for c in rows:
208
- ai2 = "AI²" if c.get("ai2") else ""
209
- lines.append(f"{c.get('id',''):>4} {c.get('stage',''):<9} "
210
- f"{c.get('project_id',''):>4} {ai2:<3} {_s(c.get('title'))}")
211
- return "\n".join(lines)
263
+ body = ["(no cards)"]
264
+ else:
265
+ body = [f"{'ID':>4} {'STAGE':<9} {'PRJ':>4} {'AI²':<3} TITLE"]
266
+ for c in rows:
267
+ ai2 = "AI²" if c.get("ai2") else ""
268
+ body.append(f"{c.get('id',''):>4} {c.get('stage',''):<9} "
269
+ f"{c.get('project_id',''):>4} {ai2:<3} {_s(c.get('title'))}")
270
+ if head:
271
+ return "\n".join(head + [""] + body)
272
+ return "\n".join(body)
212
273
 
213
274
 
214
275
  def _format_card(card: dict) -> str:
@@ -12,7 +12,9 @@ Usage:
12
12
 
13
13
  Timeline dir: ``--timeline-dir`` > ``SWARPH_TIMELINE_DIR`` > ``~/.swarph/timeline``
14
14
  (auto-created + ``git init``'d + given a ``merge=union`` .gitattributes if absent).
15
- Cell identity: ``--cell`` > ``SWARPH_CELL`` > git user.name > hostname.
15
+ Cell identity (#657 / house order #332): ``--cell`` > ``SWARPH_SELF`` >
16
+ ``SWARPH_CELL`` > git user.name > hostname. SELF outranks CELL — psmux leaks
17
+ ``SWARPH_CELL`` (#538), so CELL-first posts under another cell's name.
16
18
  Push: only if an ``origin`` remote exists and ``--no-push`` is not set; otherwise
17
19
  the highlight is committed locally (solo/offline timelines work).
18
20
  """
@@ -44,8 +46,47 @@ def _resolve_gateway(arg: str | None) -> str:
44
46
  or "").strip()
45
47
 
46
48
 
49
+ def _peer_token_near_match(name: str) -> str | None:
50
+ """Case-insensitive near-match against on-disk peer tokens (#657 / #510 shape).
51
+
52
+ When the resolved cell name has no credential, suggesting `mesh register`
53
+ mints a DUPLICATE peer if the real name differs only in case (Lab-ovh vs
54
+ lab-ovh). Prefer "did you mean …" over that advice.
55
+ """
56
+ root = Path.home() / ".config" / "swarph"
57
+ if not root.is_dir():
58
+ return None
59
+ want = name.casefold()
60
+ for path in sorted(root.glob("*.peer_token")):
61
+ peer = path.name[: -len(".peer_token")]
62
+ if peer.casefold() == want and peer != name:
63
+ return peer
64
+ return None
65
+
66
+
67
+ def _credential_error(cell: str, source: str, exc: RuntimeError) -> str:
68
+ """Name WHERE the cell identity came from; never push register on a near-match."""
69
+ near = _peer_token_near_match(cell)
70
+ header = (
71
+ f"swarph highlight: cannot resolve a mesh credential for {cell!r} "
72
+ f"(resolved from {source})"
73
+ )
74
+ if near is not None:
75
+ return (
76
+ f"{header}.\n"
77
+ f" did you mean {near!r}? A peer token exists at "
78
+ f"{Path.home() / '.config' / 'swarph' / (near + '.peer_token')}.\n"
79
+ f" Do NOT `swarph mesh register` under {cell!r} — that mints a "
80
+ f"second identity for a cell that already has one (#657)."
81
+ )
82
+ # No near-match: keep the underlying resolver text (includes register advice
83
+ # for a genuinely unknown name).
84
+ return f"swarph highlight: {exc}"
85
+
86
+
47
87
  def _log_via_gateway(gateway: str, cell: str, highlight: str,
48
- memory: str, when: str, token_file: str | None) -> int:
88
+ memory: str, when: str, token_file: str | None,
89
+ *, cell_source: str = "unknown") -> int:
49
90
  """POST the highlight to the gateway `/highlights` — the gateway holds the git
50
91
  push credential, so the cell needs only its mesh peer token (no GitHub PAT).
51
92
  Fail-loud: a non-200 or connection error returns 1 (never a silent git double-write)."""
@@ -58,7 +99,7 @@ def _log_via_gateway(gateway: str, cell: str, highlight: str,
58
99
  try:
59
100
  token = _resolve_token(cell, token_file)
60
101
  except RuntimeError as exc:
61
- print(f"swarph highlight: {exc}", file=sys.stderr)
102
+ print(_credential_error(cell, cell_source, exc), file=sys.stderr)
62
103
  return 1
63
104
  status, resp = _post_json(url, body, token)
64
105
  if status == 200:
@@ -109,17 +150,27 @@ def _is_git_repo(repo: Path) -> bool:
109
150
  return r.returncode == 0 and r.stdout.strip() == "true"
110
151
 
111
152
 
112
- def _resolve_cell(arg, repo: Path) -> str:
153
+ def _resolve_cell(arg, repo: Path) -> tuple[str, str]:
154
+ """Return ``(cell, source)``.
155
+
156
+ Order is the house rule (#332 / #538 / #657), matching
157
+ ``memory_emit_hook._cell``: flag, then SWARPH_SELF, then SWARPH_CELL, then
158
+ git user.name, then hostname. NEVER case-fold — the FAIL condition on #657
159
+ is normalising case instead of fixing this order.
160
+ """
113
161
  if arg:
114
- return _collapse(arg)
115
- env = os.environ.get("SWARPH_CELL")
116
- if env:
117
- return _collapse(env)
162
+ return _collapse(arg), "--cell"
163
+ self_env = os.environ.get("SWARPH_SELF")
164
+ if self_env:
165
+ return _collapse(self_env), "$SWARPH_SELF"
166
+ cell_env = os.environ.get("SWARPH_CELL")
167
+ if cell_env:
168
+ return _collapse(cell_env), "$SWARPH_CELL"
118
169
  if _is_git_repo(repo):
119
170
  r = _git(repo, "config", "user.name")
120
171
  if r.returncode == 0 and r.stdout.strip():
121
- return _collapse(r.stdout.strip())
122
- return socket.gethostname()
172
+ return _collapse(r.stdout.strip()), "git user.name"
173
+ return socket.gethostname(), "hostname"
123
174
 
124
175
 
125
176
  def _ensure_timeline(repo: Path, cell: str) -> None:
@@ -158,7 +209,8 @@ def run_highlight(argv: list) -> int:
158
209
  p.add_argument("memory", nargs="?", default="",
159
210
  help="optional memory pointer, e.g. [[some-memory]]")
160
211
  p.add_argument("--cell", default=None,
161
- help="cell identity (else SWARPH_CELL / git user / hostname)")
212
+ help="cell identity (else SWARPH_SELF / SWARPH_CELL / "
213
+ "git user / hostname)")
162
214
  p.add_argument("--timeline-dir", default=None,
163
215
  help="timeline repo (else SWARPH_TIMELINE_DIR / ~/.swarph/timeline)")
164
216
  p.add_argument("--when", default=None,
@@ -175,7 +227,7 @@ def run_highlight(argv: list) -> int:
175
227
  args = p.parse_args(argv)
176
228
 
177
229
  repo = _resolve_dir(args.timeline_dir)
178
- cell = _resolve_cell(args.cell, repo)
230
+ cell, cell_source = _resolve_cell(args.cell, repo)
179
231
  highlight = _collapse(args.highlight)
180
232
  memory = _collapse(args.memory)
181
233
  when = _collapse(args.when) if args.when else ""
@@ -186,7 +238,8 @@ def run_highlight(argv: list) -> int:
186
238
  # path too, so existing solo/offline timelines are unaffected.
187
239
  gateway = "" if args.local else _resolve_gateway(args.gateway)
188
240
  if gateway:
189
- return _log_via_gateway(gateway, cell, highlight, memory, when, args.token_file)
241
+ return _log_via_gateway(gateway, cell, highlight, memory, when,
242
+ args.token_file, cell_source=cell_source)
190
243
 
191
244
  _ensure_timeline(repo, cell)
192
245
  ts = when or _now_ts()
@@ -1500,15 +1500,39 @@ def _sleep(seconds: float) -> None:
1500
1500
  time.sleep(seconds)
1501
1501
 
1502
1502
 
1503
- def _unit_owned_instances() -> "list[str]":
1504
- """The peers whose monitor systemd is running RIGHT NOW, from systemd's own
1505
- registry — the property, not a process pattern (#517's lesson: a pattern
1506
- matches what you expect the world to look like; this asks the owner).
1507
- Empty when systemctl cannot answer, and the CALLER hears why via the
1508
- exception — an unreadable registry must not render as an empty fleet."""
1503
+ def _peer_from_monitor_unit(unit: str) -> "str | None":
1504
+ """Mesh peer for a running ``swarph-monitor*.service`` unit.
1505
+
1506
+ Template instances encode the peer in the unit name; bespoke units carry
1507
+ it in ``ExecStart --as`` (#665).
1508
+ """
1509
+ if unit.startswith("swarph-monitor@") and unit.endswith(".service"):
1510
+ return unit[len("swarph-monitor@"):-len(".service")]
1511
+ try:
1512
+ proc = subprocess.run(
1513
+ ["systemctl", "show", unit, "-p", "ExecStart", "--value"],
1514
+ capture_output=True, text=True, check=True,
1515
+ encoding="utf-8", errors="replace", timeout=10,
1516
+ )
1517
+ except (OSError, subprocess.CalledProcessError, subprocess.TimeoutExpired):
1518
+ return None
1519
+ text = proc.stdout.strip()
1520
+ if "monitor start" not in text:
1521
+ return None
1522
+ m = re.search(r"--as\s+(\S+)", text)
1523
+ return m.group(1) if m else None
1524
+
1525
+
1526
+ def _supervised_monitor_units() -> "list[tuple[str, str]]":
1527
+ """Every running swarph-monitor unit → ``(peer, unit.service)``.
1528
+
1529
+ Lists ``swarph-monitor*`` from systemd — template AND bespoke names — and
1530
+ confirms each unit's ExecStart is ``monitor start``. The old
1531
+ ``swarph-monitor@*`` glob alone missed bespoke-named units (#665).
1532
+ """
1509
1533
  try:
1510
1534
  out = subprocess.run(
1511
- ["systemctl", "list-units", "swarph-monitor@*", "--state=running",
1535
+ ["systemctl", "list-units", "swarph-monitor*", "--state=running",
1512
1536
  "--no-legend", "--no-pager", "--plain"],
1513
1537
  capture_output=True, text=True, check=True,
1514
1538
  encoding="utf-8", errors="replace").stdout
@@ -1516,12 +1540,40 @@ def _unit_owned_instances() -> "list[str]":
1516
1540
  raise RuntimeError(
1517
1541
  "systemctl cannot list running swarph-monitor instances"
1518
1542
  ) from exc
1519
- peers = []
1543
+ by_peer: dict[str, str] = {}
1520
1544
  for line in out.splitlines():
1521
- first = line.split()[0] if line.split() else ""
1522
- if first.startswith("swarph-monitor@") and first.endswith(".service"):
1523
- peers.append(first[len("swarph-monitor@"):-len(".service")])
1524
- return sorted(peers)
1545
+ unit = line.split()[0] if line.split() else ""
1546
+ if not unit.endswith(".service"):
1547
+ continue
1548
+ if unit == "swarph-monitor-reexec.service":
1549
+ continue
1550
+ if not unit.startswith("swarph-monitor"):
1551
+ continue
1552
+ peer = _peer_from_monitor_unit(unit)
1553
+ if peer:
1554
+ by_peer[peer] = unit
1555
+ return sorted(by_peer.items(), key=lambda t: t[0])
1556
+
1557
+
1558
+ def _unit_owned_instances() -> "list[str]":
1559
+ """Peer names whose monitor is running under a systemd unit RIGHT NOW."""
1560
+ return [peer for peer, _ in _supervised_monitor_units()]
1561
+
1562
+
1563
+ def _count_pidfile_state_dirs(state_root: Path) -> int:
1564
+ """State dirs that have ever claimed a monitor pidfile (#665 denominator)."""
1565
+ if not state_root.is_dir():
1566
+ return 0
1567
+ n = 0
1568
+ for peer_dir in state_root.iterdir():
1569
+ if peer_dir.is_dir() and (peer_dir / "mesh-sidecar" / mesh._MONITOR_PIDFILE).exists():
1570
+ n += 1
1571
+ return n
1572
+
1573
+
1574
+ def _is_swarph_monitor_unit_name(unit_leaf: str) -> bool:
1575
+ """True when a cgroup-derived unit leaf names a swarph monitor service."""
1576
+ return unit_leaf.startswith("swarph-monitor") and unit_leaf.endswith(".service")
1525
1577
 
1526
1578
 
1527
1579
  def _cmd_reexec_on_change(args: argparse.Namespace) -> int:
@@ -1540,49 +1592,61 @@ def _cmd_reexec_on_change(args: argparse.Namespace) -> int:
1540
1592
  print(" note: a RUNNING process's build is unknowable from outside "
1541
1593
  "(#649) — 'running since' is the honest old-side coordinate")
1542
1594
 
1543
- unit_owned = _unit_owned_instances()
1595
+ supervised = _supervised_monitor_units()
1596
+ supervised_peers = {peer for peer, _ in supervised}
1597
+ pidfile_dirs = _count_pidfile_state_dirs(state_root)
1544
1598
  held, out_of_scope, not_running, failed = [], [], [], []
1545
- plan = [] # (peer, since-string)
1546
- for peer in unit_owned:
1599
+ plan = [] # (peer, unit.service, since-string)
1600
+ for peer, unit in supervised:
1547
1601
  state_dir = state_root / peer / "mesh-sidecar"
1548
1602
  hold = _read_reexec_hold(state_dir)
1549
1603
  if hold:
1550
- held.append(f"{peer} — {_fmt_reexec_hold(hold)}")
1604
+ held.append(f"{peer} ({unit}) — {_fmt_reexec_hold(hold)}")
1551
1605
  continue
1552
1606
  pstatus, rec = mesh.pidfile_status(state_dir / mesh._MONITOR_PIDFILE)
1553
1607
  since = (_proc_start_iso(rec["pid"]) if pstatus == "live_ours"
1554
1608
  else None) or f"unknown (pidfile {pstatus})"
1555
- plan.append((peer, since))
1609
+ plan.append((peer, unit, since))
1556
1610
 
1557
1611
  # R6: monitors with a LIVE pidfile that no unit owns — tmux-scoped or
1558
1612
  # hand-started — are named, never omitted.
1559
1613
  if state_root.is_dir():
1560
1614
  for peer_dir in sorted(state_root.iterdir()):
1561
1615
  peer = peer_dir.name
1562
- if peer in unit_owned or not peer_dir.is_dir():
1616
+ if peer in supervised_peers or not peer_dir.is_dir():
1563
1617
  continue
1564
1618
  state_dir = peer_dir / "mesh-sidecar"
1565
1619
  pstatus, rec = mesh.pidfile_status(state_dir / mesh._MONITOR_PIDFILE)
1566
1620
  if pstatus == "live_ours":
1621
+ derived = _derive_systemd_unit(rec["pid"])
1567
1622
  cgroup = _read_cgroup(rec["pid"]) or ""
1568
1623
  scope = next((p for p in reversed(cgroup.replace("\n", " ").split("/"))
1569
1624
  if p), "unreadable cgroup")
1570
- out_of_scope.append(f"{peer} (pid {rec['pid']} in {scope})")
1625
+ if derived and _is_swarph_monitor_unit_name(f"{derived}.service"):
1626
+ # Enumerator missed a unit-owned monitor — name it loudly.
1627
+ out_of_scope.append(
1628
+ f"{peer} (pid {rec['pid']} in {derived}.service — "
1629
+ f"unit-owned but not enumerated; fix the enumerator)"
1630
+ )
1631
+ else:
1632
+ out_of_scope.append(f"{peer} (pid {rec['pid']} in {scope})")
1571
1633
  elif pstatus in ("stale", "foreign"):
1572
1634
  not_running.append(f"{peer} (pidfile {pstatus} — revival is "
1573
1635
  f"the watchdog's job, not this verb's)")
1574
1636
 
1575
- for i, (peer, since) in enumerate(plan):
1637
+ restarted_n = 0
1638
+ for i, (peer, unit, since) in enumerate(plan):
1576
1639
  if not args.apply:
1577
- print(f" would restart: {peer} (running since {since})")
1640
+ print(f" would restart: {peer} via {unit} (running since {since})")
1578
1641
  continue
1579
- rc = _systemctl_run(["restart", f"swarph-monitor@{peer}.service"])
1642
+ rc = _systemctl_run(["restart", unit])
1580
1643
  if rc == 0:
1581
- print(f" reexec: {peer} restarted onto {version} "
1644
+ restarted_n += 1
1645
+ print(f" reexec: {peer} restarted onto {version} via {unit} "
1582
1646
  f"(was running since {since})")
1583
1647
  else:
1584
- failed.append(f"{peer} (systemctl restart rc={rc})")
1585
- print(f" reexec FAILED: {peer} (systemctl rc={rc})")
1648
+ failed.append(f"{peer} ({unit}, systemctl restart rc={rc})")
1649
+ print(f" reexec FAILED: {peer} ({unit}, systemctl rc={rc})")
1586
1650
  if i < len(plan) - 1:
1587
1651
  _sleep(args.stagger_s) # R3: serial, never simultaneous
1588
1652
 
@@ -1593,8 +1657,10 @@ def _cmd_reexec_on_change(args: argparse.Namespace) -> int:
1593
1657
  # R6: the report is where out-of-scope cells exist at all.
1594
1658
  for line in out_of_scope:
1595
1659
  print(f" OUT OF SCOPE (not unit-owned; cannot be re-exec'd here): {line}")
1596
- print(f"reexec-on-change: {len(plan)} restarted"
1660
+ action = "restarted" if args.apply else "would restart"
1661
+ print(f"reexec-on-change: {restarted_n if args.apply else len(plan)} {action}"
1597
1662
  f"{'' if args.apply else ' (DRY RUN — pass --apply to act)'}, "
1663
+ f"{len(supervised)} unit-supervised, {pidfile_dirs} state dirs with pidfile, "
1598
1664
  f"{len(held)} held, {len(out_of_scope)} out of scope, "
1599
1665
  f"{len(not_running)} not running, {len(failed)} failed")
1600
1666
  return 1 if failed else 0
@@ -162,6 +162,7 @@ Usage:
162
162
  [--peer-health-window-sec SEC]
163
163
  [--peer-health-recovery-threshold SEC]
164
164
  [--log PATH] [--verbose]
165
+ swarph watchdog --orphan-daemons
165
166
  swarph watchdog --install-service [--cell ROLE] [--dry-run]
166
167
 
167
168
  Detects stranded Claude sessions (API throttle / harness death) and attempts
@@ -1916,6 +1917,12 @@ def _build_parser() -> argparse.ArgumentParser:
1916
1917
  "--check", action="store_true",
1917
1918
  help="One-shot check (cron-callable; exits with status code).",
1918
1919
  )
1920
+ p.add_argument(
1921
+ "--orphan-daemons", action="store_true",
1922
+ help="#666 T1: read-only scan for orphaned `claude daemon run` "
1923
+ "processes (spawner dead + tmux-spawn scope gone). Prints a "
1924
+ "report; never signals. UNKNOWN ≠ ORPHANED.",
1925
+ )
1919
1926
  p.add_argument(
1920
1927
  "--install-service", action="store_true",
1921
1928
  help="Install systemd timer + service for periodic --check invocation. "
@@ -2093,6 +2100,10 @@ def run_watchdog(argv: Optional[list[str]] = None) -> int:
2093
2100
  if args.install_service:
2094
2101
  return run_install_service(args)
2095
2102
 
2103
+ if args.orphan_daemons:
2104
+ from swarph_cli.orphan_daemons import run_orphan_daemons_report
2105
+ return run_orphan_daemons_report()
2106
+
2096
2107
  if not args.check:
2097
2108
  print(_USAGE, file=sys.stderr)
2098
2109
  return 4