swarph-cli 0.72.29__tar.gz → 0.72.30__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 (536) hide show
  1. {swarph_cli-0.72.29/src/swarph_cli.egg-info → swarph_cli-0.72.30}/PKG-INFO +1 -1
  2. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/pyproject.toml +1 -1
  3. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/__init__.py +1 -1
  4. swarph_cli-0.72.30/src/swarph_cli/bench/prices.py +284 -0
  5. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/refresh_prices.py +40 -7
  6. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/scripts/wake_watchdog.py +251 -26
  7. {swarph_cli-0.72.29 → swarph_cli-0.72.30/src/swarph_cli.egg-info}/PKG-INFO +1 -1
  8. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli.egg-info/SOURCES.txt +3 -0
  9. swarph_cli-0.72.30/tests/test_1248_ship_price_table.py +157 -0
  10. swarph_cli-0.72.30/tests/test_1250_price_cache.py +274 -0
  11. swarph_cli-0.72.30/tests/test_1256_commander_wake.py +172 -0
  12. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_729_wake_watchdog.py +45 -17
  13. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_739_wake_writer.py +27 -1
  14. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_960_channel.py +24 -5
  15. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_bench_command.py +4 -1
  16. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_bench_prices.py +6 -3
  17. swarph_cli-0.72.29/src/swarph_cli/bench/prices.py +0 -103
  18. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/LICENSE +0 -0
  19. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/README.md +0 -0
  20. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/setup.cfg +0 -0
  21. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/__main__.py +0 -0
  22. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/__init__.py +0 -0
  23. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/backends.py +0 -0
  24. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/claude_cli.py +0 -0
  25. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/codex_cli.py +0 -0
  26. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/pack.py +0 -0
  27. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/providers.py +0 -0
  28. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/quality.py +0 -0
  29. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/rules.py +0 -0
  30. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/runner.py +0 -0
  31. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/signal_score.py +0 -0
  32. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/bench/validate.py +0 -0
  33. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/caller.py +0 -0
  34. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/capture/__init__.py +0 -0
  35. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/capture/harden.py +0 -0
  36. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/capture/lineage.py +0 -0
  37. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/capture/liveness.py +0 -0
  38. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/capture/manifest.py +0 -0
  39. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/capture/paths.py +0 -0
  40. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/capture/verify.py +0 -0
  41. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/cell.py +0 -0
  42. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/chain_token.py +0 -0
  43. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/channel.py +0 -0
  44. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/__init__.py +0 -0
  45. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/_content.py +0 -0
  46. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/_display.py +0 -0
  47. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/_gateway_client.py +0 -0
  48. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/add.py +0 -0
  49. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/bench.py +0 -0
  50. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/board.py +0 -0
  51. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/board_merge_check.py +0 -0
  52. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/brain.py +0 -0
  53. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/brain_ask.py +0 -0
  54. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/cell.py +0 -0
  55. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/cell_probe.py +0 -0
  56. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  57. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/channel.py +0 -0
  58. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/chat.py +0 -0
  59. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/codegraph.py +0 -0
  60. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/codegraph_hook.py +0 -0
  61. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  62. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/codex_waker.py +0 -0
  63. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/compress.py +0 -0
  64. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/daemon.py +0 -0
  65. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/dreaming.py +0 -0
  66. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/event.py +0 -0
  67. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/gateway.py +0 -0
  68. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/gh_route.py +0 -0
  69. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/group.py +0 -0
  70. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/guide.py +0 -0
  71. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/highlight.py +0 -0
  72. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/hook_interpreter.py +0 -0
  73. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/hook_output.py +0 -0
  74. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/hooks.py +0 -0
  75. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/import_session.py +0 -0
  76. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/init.py +0 -0
  77. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  78. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/install_hook.py +0 -0
  79. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  80. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
  81. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
  82. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  83. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/lane.py +0 -0
  84. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/mcp_server.py +0 -0
  85. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/memory.py +0 -0
  86. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
  87. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/memory_sync.py +0 -0
  88. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/mesh.py +0 -0
  89. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/monitor.py +0 -0
  90. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/okf_links.py +0 -0
  91. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/onboard.py +0 -0
  92. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  93. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  94. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/protocol_handler.py +0 -0
  95. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/ratify.py +0 -0
  96. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/roster.py +0 -0
  97. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/rowclear_hook.py +0 -0
  98. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/schedule.py +0 -0
  99. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/security.py +0 -0
  100. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/service.py +0 -0
  101. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/spawn.py +0 -0
  102. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/sweep.py +0 -0
  103. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/timeline.py +0 -0
  104. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/triage.py +0 -0
  105. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/version.py +0 -0
  106. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/wake_hook_output.py +0 -0
  107. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/commands/watchdog.py +0 -0
  108. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/compress/__init__.py +0 -0
  109. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/compress/levers.py +0 -0
  110. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/compress/marker.py +0 -0
  111. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/compress/verify.py +0 -0
  112. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/console_safe.py +0 -0
  113. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/delivery_queue.py +0 -0
  114. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dm_frame.py +0 -0
  115. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/__init__.py +0 -0
  116. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/candidates.py +0 -0
  117. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/clone.py +0 -0
  118. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/enrich.py +0 -0
  119. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/index_check.py +0 -0
  120. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/notify.py +0 -0
  121. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/organize.py +0 -0
  122. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/probes.py +0 -0
  123. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/report.py +0 -0
  124. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/run.py +0 -0
  125. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/slm.py +0 -0
  126. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/transcripts.py +0 -0
  127. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/dreaming/verify.py +0 -0
  128. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/duplicate_session.py +0 -0
  129. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/gateway/__init__.py +0 -0
  130. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/gateway/feature_registry.py +0 -0
  131. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/gateway/lanes_control.py +0 -0
  132. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/gateway/schema.sql +0 -0
  133. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/gateway/server.py +0 -0
  134. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/gateway/services_control.py +0 -0
  135. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/gateway_default.py +0 -0
  136. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/gh_identity.py +0 -0
  137. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/guide/GUIDE.md +0 -0
  138. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/identity.py +0 -0
  139. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/launchd/swarph-codex-outbox.plist +0 -0
  140. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/launchd/swarph-codex-outbox.timer.plist +0 -0
  141. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/launchd/swarph-monitor.plist +0 -0
  142. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/launchd/swarph-watchdog.plist +0 -0
  143. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/launchd/swarph-watchdog.timer.plist +0 -0
  144. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/launchd_render.py +0 -0
  145. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/main.py +0 -0
  146. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/multiplexer.py +0 -0
  147. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/operator/__init__.py +0 -0
  148. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/operator/__main__.py +0 -0
  149. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/operator/api.py +0 -0
  150. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/operator/cli.py +0 -0
  151. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/operator/config.py +0 -0
  152. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/operator/fmt.py +0 -0
  153. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/orphan_daemons.py +0 -0
  154. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/pane_probe.py +0 -0
  155. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/parsers/__init__.py +0 -0
  156. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/parsers/claude.py +0 -0
  157. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
  158. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  159. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  160. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  161. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  162. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  163. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  164. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  165. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  166. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  167. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  168. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  169. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/peer_executor.py +0 -0
  170. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/peer_executor_windows.py +0 -0
  171. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/peer_reconciliation.py +0 -0
  172. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/peer_reply_outbox.py +0 -0
  173. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/peer_service_host.py +0 -0
  174. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/peer_service_payload.py +0 -0
  175. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/peer_service_reply.py +0 -0
  176. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/peer_staging.py +0 -0
  177. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/query_filters.py +0 -0
  178. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/quota_sync.py +0 -0
  179. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/rowclear.py +0 -0
  180. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/scripts/__init__.py +0 -0
  181. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  182. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  183. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  184. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  185. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/scrub.py +0 -0
  186. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/service/__init__.py +0 -0
  187. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/service/app.py +0 -0
  188. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/service/providers.py +0 -0
  189. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/session_bridge.py +0 -0
  190. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  191. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  192. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/source_text.py +0 -0
  193. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/stall_alert.py +0 -0
  194. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/codex-waker.default +0 -0
  195. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  196. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  197. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  198. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  199. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  200. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
  201. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
  202. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  203. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  204. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  205. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
  206. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
  207. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-triage.service +0 -0
  208. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
  209. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  210. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  211. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  212. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/the_ten.py +0 -0
  213. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/timeline_paths.py +0 -0
  214. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/tokens.py +0 -0
  215. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/triage/__init__.py +0 -0
  216. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/triage/backend.py +0 -0
  217. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/triage/job.py +0 -0
  218. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/triage/owners.json +0 -0
  219. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/triage/router.py +0 -0
  220. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/triage/rows.py +0 -0
  221. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli/triage/sensor.py +0 -0
  222. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  223. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  224. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli.egg-info/requires.txt +0 -0
  225. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/src/swarph_cli.egg-info/top_level.txt +0 -0
  226. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1006_board_publisher.py +0 -0
  227. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1006_session_board.py +0 -0
  228. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1010_strand_only.py +0 -0
  229. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1013_spawn_channel.py +0 -0
  230. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1017_muse_tui.py +0 -0
  231. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1034_copy_mode.py +0 -0
  232. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1050_surrogate_wake.py +0 -0
  233. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1052_opencode_deaf.py +0 -0
  234. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1059_watchdog_unread_env.py +0 -0
  235. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1061_roster_cli.py +0 -0
  236. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1064_stuck_sweep.py +0 -0
  237. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1065_release.py +0 -0
  238. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1066_quiet_wakes.py +0 -0
  239. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1068_structured_accept_cli.py +0 -0
  240. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1071_quota_sync.py +0 -0
  241. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1073_triage.py +0 -0
  242. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1073_triage_board.py +0 -0
  243. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1073_wheel_install.py +0 -0
  244. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1075_task_cli.py +0 -0
  245. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1083_openai_decisions.py +0 -0
  246. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1144_cell_yaml_github.py +0 -0
  247. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1197_commander_taps.py +0 -0
  248. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1203_swarph_me_refusal.py +0 -0
  249. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1206_offer_question.py +0 -0
  250. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1214_egress.py +0 -0
  251. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1219_egress_probe.py +0 -0
  252. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1221_quota_windows.py +0 -0
  253. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1222_maybe_start_cap.py +0 -0
  254. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1228_quota_reach.py +0 -0
  255. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_1243_the_ten.py +0 -0
  256. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_124_register_merge.py +0 -0
  257. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_126_pending_from_complete.py +0 -0
  258. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  259. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_138_memory_navigate.py +0 -0
  260. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_139_tool_probe.py +0 -0
  261. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_183_card_anchor.py +0 -0
  262. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_184_notify_honesty.py +0 -0
  263. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_201_win32_bash_refusal.py +0 -0
  264. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_243_onboard_per_peer_token.py +0 -0
  265. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_307_task4_ask_reply.py +0 -0
  266. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  267. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_319_refusal_exit_codes.py +0 -0
  268. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_323_mistral_backend.py +0 -0
  269. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_332_report_organize_findings.py +0 -0
  270. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_356_query_filters.py +0 -0
  271. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_397_gh_identity_router.py +0 -0
  272. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_397_router_preflight.py +0 -0
  273. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_402_one_identity_resolver.py +0 -0
  274. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_432_rowclear.py +0 -0
  275. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_467b_onboard_operator_credential.py +0 -0
  276. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_472_register_caller_binding.py +0 -0
  277. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_484_codex_queue_sink.py +0 -0
  278. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_513_duplicate_session.py +0 -0
  279. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_523_guide.py +0 -0
  280. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_524_conftest_hermeticity.py +0 -0
  281. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_532_accept_flag.py +0 -0
  282. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_535_version_capability.py +0 -0
  283. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_538_signal_bench.py +0 -0
  284. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_546_default_gateway.py +0 -0
  285. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_547_verbs_from_registry.py +0 -0
  286. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_548_gateway_remainder.py +0 -0
  287. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_552_codegraph_gateway.py +0 -0
  288. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_555_relay_row_shape.py +0 -0
  289. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_556_relay_freshness.py +0 -0
  290. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_559_edges_truncated.py +0 -0
  291. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_564_bootstrap_first_peer.py +0 -0
  292. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  293. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_579_register_bootstrap_message.py +0 -0
  294. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_591_cli_step_graph.py +0 -0
  295. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_644_monitor_supervision.py +0 -0
  296. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_648_install_unit.py +0 -0
  297. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_654_reexec.py +0 -0
  298. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_656_owned_slm.py +0 -0
  299. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_684_dreaming_verb.py +0 -0
  300. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_689_pkg_version_order.py +0 -0
  301. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_715_grok_wake.py +0 -0
  302. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_716_timeline_one_path.py +0 -0
  303. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_723_grok_0251.py +0 -0
  304. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_724_ps1_ascii_or_bom.py +0 -0
  305. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_725_stdio_reconfigure.py +0 -0
  306. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_726_grok_limit_screen.py +0 -0
  307. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_729_arm_check_delivery_gap.py +0 -0
  308. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_729_dm_once.py +0 -0
  309. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_734_dreaming_enrich_degrade.py +0 -0
  310. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_735_dm_mcp_tools.py +0 -0
  311. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_740_edit_project.py +0 -0
  312. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_762_cards_edit_priority.py +0 -0
  313. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_764_enrich_collapse.py +0 -0
  314. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_801_confirm_flow_cli.py +0 -0
  315. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_802_stage_history.py +0 -0
  316. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_825_codegraph_hook_noise.py +0 -0
  317. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_825_install_posttooluse_only.py +0 -0
  318. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_825_remaining_cap_shred_bind.py +0 -0
  319. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_829_counterfactual_column.py +0 -0
  320. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_830_hook_binding_version.py +0 -0
  321. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_84_cli_labels.py +0 -0
  322. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_866_doctrine_guide.py +0 -0
  323. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_872_identity_refuses_not_warns.py +0 -0
  324. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_874_source_text.py +0 -0
  325. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
  326. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_931_board_search.py +0 -0
  327. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_935_deadline_clock.py +0 -0
  328. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_937_dreaming_notify.py +0 -0
  329. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_938_organize_line_limit.py +0 -0
  330. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_941_bench_backends.py +0 -0
  331. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_941_harness_342.py +0 -0
  332. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_945_same_line_pairing.py +0 -0
  333. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_955_prompt_audit.py +0 -0
  334. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_957_auth_http.py +0 -0
  335. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_959_venv_interpreter.py +0 -0
  336. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
  337. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_961_cursor_grok_footer.py +0 -0
  338. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_961_loud_stop.py +0 -0
  339. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_963_plugin_manifest.py +0 -0
  340. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_964_channel_cell.py +0 -0
  341. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_965_mesh_wait.py +0 -0
  342. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_975_channel_hop.py +0 -0
  343. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_add_security_gate.py +0 -0
  344. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_artifact_add.py +0 -0
  345. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_artifact_hash.py +0 -0
  346. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_artifact_lib.py +0 -0
  347. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_artifact_mcp.py +0 -0
  348. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_artifact_skill.py +0 -0
  349. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_artifact_tool.py +0 -0
  350. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_artifact_uri.py +0 -0
  351. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_bench_backends.py +0 -0
  352. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_bench_claude_cli.py +0 -0
  353. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_bench_codex_cli.py +0 -0
  354. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_bench_pack.py +0 -0
  355. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_bench_quality.py +0 -0
  356. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_bench_runner.py +0 -0
  357. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_bench_validate.py +0 -0
  358. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_board_card_thread.py +0 -0
  359. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_board_command.py +0 -0
  360. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_board_merge_check.py +0 -0
  361. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_board_obligation_close.py +0 -0
  362. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_brain_ask_command.py +0 -0
  363. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_brain_ask_env_diagnosis.py +0 -0
  364. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_brain_ask_identity_explicitness.py +0 -0
  365. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_brain_command.py +0 -0
  366. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_caller_meta_guard.py +0 -0
  367. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_capture_lineage.py +0 -0
  368. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_capture_liveness.py +0 -0
  369. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_capture_manifest.py +0 -0
  370. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_capture_paths.py +0 -0
  371. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_capture_security.py +0 -0
  372. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_cell_command_dispatch.py +0 -0
  373. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_cell_harden.py +0 -0
  374. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_cell_loader.py +0 -0
  375. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_cell_selfcheck.py +0 -0
  376. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_cell_verify.py +0 -0
  377. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_chain_token.py +0 -0
  378. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_channel_command.py +0 -0
  379. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  380. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_channel_post.py +0 -0
  381. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_channel_wake_policy_filter.py +0 -0
  382. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_chat_command.py +0 -0
  383. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_claude_parser.py +0 -0
  384. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_claude_tmux_template.py +0 -0
  385. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_codegraph_caller_scope.py +0 -0
  386. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_codegraph_command.py +0 -0
  387. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_codegraph_hook.py +0 -0
  388. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_codegraph_mcp.py +0 -0
  389. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_codex_waker.py +0 -0
  390. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_compress_caller_convention.py +0 -0
  391. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_compress_command.py +0 -0
  392. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_compress_levers.py +0 -0
  393. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_compress_marker.py +0 -0
  394. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_compress_verify.py +0 -0
  395. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_console_encoding_e2e.py +0 -0
  396. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_content_composition.py +0 -0
  397. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_copilot_membrane.py +0 -0
  398. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_copilot_pane_reader.py +0 -0
  399. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_cursor_membrane.py +0 -0
  400. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_daemon_command.py +0 -0
  401. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_daemon_console_encoding.py +0 -0
  402. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_daemon_delivery.py +0 -0
  403. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_delivery_queue.py +0 -0
  404. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_display_sanitize.py +0 -0
  405. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  406. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_event_emit.py +0 -0
  407. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_feature_to_uri.py +0 -0
  408. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_gateway_brain.py +0 -0
  409. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_gateway_client.py +0 -0
  410. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_gateway_command.py +0 -0
  411. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_gateway_message_idempotency.py +0 -0
  412. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  413. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_group_command.py +0 -0
  414. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_guide_commands_parse.py +0 -0
  415. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_guide_selfcheck.py +0 -0
  416. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_heartbeat_check.py +0 -0
  417. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_highlight_command.py +0 -0
  418. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hook_output.py +0 -0
  419. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hooks_activity_marker.py +0 -0
  420. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hooks_add.py +0 -0
  421. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hooks_bundle.py +0 -0
  422. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hooks_init.py +0 -0
  423. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hooks_legacy_generation_removal.py +0 -0
  424. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hooks_lifecycle.py +0 -0
  425. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hooks_merge.py +0 -0
  426. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hooks_verify.py +0 -0
  427. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  428. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_hooks_win32_command_path.py +0 -0
  429. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_import_command.py +0 -0
  430. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_inbox_identity_provenance.py +0 -0
  431. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_init_command.py +0 -0
  432. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_init_provider_menu.py +0 -0
  433. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_install_codex_hooks.py +0 -0
  434. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_install_hook.py +0 -0
  435. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_install_multiplexer_command.py +0 -0
  436. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_install_postcompact_hook.py +0 -0
  437. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_install_wake_hook.py +0 -0
  438. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_lane_command.py +0 -0
  439. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_launchd_units.py +0 -0
  440. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_main.py +0 -0
  441. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_main_unknown_verb_guard.py +0 -0
  442. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mcp_missing_hint.py +0 -0
  443. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mcp_server.py +0 -0
  444. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_memory_command.py +0 -0
  445. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_memory_emit_snippet.py +0 -0
  446. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_memory_gateway.py +0 -0
  447. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_memory_sync.py +0 -0
  448. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_memory_sync_membrane.py +0 -0
  449. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mesh_command.py +0 -0
  450. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mesh_inbox_mark_read.py +0 -0
  451. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mesh_inbox_sanitize.py +0 -0
  452. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mesh_originate_thread_623.py +0 -0
  453. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mesh_send_unknown_peer.py +0 -0
  454. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mesh_sidecar.py +0 -0
  455. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  456. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mesh_sidecar_muse_sink.py +0 -0
  457. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  458. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_meta_edge_identity.py +0 -0
  459. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_monitor_channel_poll.py +0 -0
  460. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_monitor_cli.py +0 -0
  461. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_monitor_daemon_collision.py +0 -0
  462. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_monitor_self_name_verification.py +0 -0
  463. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_monitor_state_split.py +0 -0
  464. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_multiplexer.py +0 -0
  465. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_muse_membrane.py +0 -0
  466. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_muse_own_cli.py +0 -0
  467. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_obligation_close_is_surfaced.py +0 -0
  468. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_okf_links.py +0 -0
  469. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_onboard_command.py +0 -0
  470. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_opencode_membrane.py +0 -0
  471. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_opencode_plugin.py +0 -0
  472. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_operator_me.py +0 -0
  473. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_orphan_daemons.py +0 -0
  474. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_packaged_artifacts_exist.py +0 -0
  475. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_packaged_skills.py +0 -0
  476. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_peer_executor.py +0 -0
  477. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_peer_executor_windows.py +0 -0
  478. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_peer_reply_drain_command.py +0 -0
  479. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_peer_reply_drain_supervisor.py +0 -0
  480. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_peer_reply_outbox.py +0 -0
  481. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_peer_reply_transport.py +0 -0
  482. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_peer_service_e2e.py +0 -0
  483. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_peer_service_host.py +0 -0
  484. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_peer_service_payload.py +0 -0
  485. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_peer_service_reply.py +0 -0
  486. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_postcompact_recall.py +0 -0
  487. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_process_liveness.py +0 -0
  488. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_protocol_handler.py +0 -0
  489. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_providers_isolation.py +0 -0
  490. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_ratify_command.py +0 -0
  491. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_readme_claims_no_gateway_default.py +0 -0
  492. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_repl_caller_convention.py +0 -0
  493. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_schedule_command.py +0 -0
  494. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_schedule_create_contract.py +0 -0
  495. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_scrub.py +0 -0
  496. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_security.py +0 -0
  497. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_service_app.py +0 -0
  498. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_service_command.py +0 -0
  499. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_service_providers.py +0 -0
  500. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_session_bridge_inject.py +0 -0
  501. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_session_bridge_probe.py +0 -0
  502. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_session_bridge_resolve.py +0 -0
  503. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_session_path_role_gate.py +0 -0
  504. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_shipped_units_match_the_cli.py +0 -0
  505. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_smoke_chat.py +0 -0
  506. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_smoke_one_shot.py +0 -0
  507. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_smoke_phase_5_5.py +0 -0
  508. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_spawn_base_hoist.py +0 -0
  509. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_spawn_command.py +0 -0
  510. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_spawn_identity_stamp.py +0 -0
  511. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_spawn_live_pin.py +0 -0
  512. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_spawn_mitosis_lineage.py +0 -0
  513. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_spawn_tmux_session.py +0 -0
  514. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_spawn_windows_relaunch.py +0 -0
  515. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_stall_alert.py +0 -0
  516. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_subprocess_decode_encoding.py +0 -0
  517. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_timeline_command.py +0 -0
  518. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_tmux_wake_runstate_defer.py +0 -0
  519. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_tmux_wake_session_reanchor.py +0 -0
  520. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_tmux_wake_stale.py +0 -0
  521. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_tmux_wake_submit_verify.py +0 -0
  522. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_token_file_one_parser.py +0 -0
  523. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_token_precedence_explicit_first.py +0 -0
  524. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_unified_token_resolver.py +0 -0
  525. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_version_command.py +0 -0
  526. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_version_consistency.py +0 -0
  527. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_vibe_membrane.py +0 -0
  528. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_watchdog.py +0 -0
  529. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_watchdog_dm_wake.py +0 -0
  530. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  531. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  532. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_watchdog_emit_health.py +0 -0
  533. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_watchdog_install_flags.py +0 -0
  534. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_watchdog_model_rung.py +0 -0
  535. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_watchdog_stale_peers.py +0 -0
  536. {swarph_cli-0.72.29 → swarph_cli-0.72.30}/tests/test_windows_waker_installer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swarph-cli
3
- Version: 0.72.29
3
+ Version: 0.72.30
4
4
  Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
5
5
  Author: Pierre Samson, Claude Opus
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swarph-cli"
7
- version = "0.72.29"
7
+ version = "0.72.30"
8
8
  description = "The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -16,6 +16,6 @@ The architecture splits CLI from substrate so:
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
- __version__ = "0.72.29"
19
+ __version__ = "0.72.30"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -0,0 +1,284 @@
1
+ """The auto-refreshed LLM LIST-price table (spec §4) — LIFTED from the
2
+ reference lab's already-tested ``workers/llm_prices.py`` (adapted imports/
3
+ cache path only; lookup semantics, fallback table, and substring-order bug
4
+ guard are unchanged). Do NOT reinvent this — see
5
+ ``docs/2026-07-24-model-showdown-findings.md`` shipped-alongside note: it
6
+ already caught a real ~5x under-count on gemini-2.5-flash-lite.
7
+
8
+ The LIST-price BASE is auto-refreshed from the community-maintained LiteLLM
9
+ repo (:mod:`swarph_cli.bench.refresh_prices` -> a local JSON cache; TODO wire
10
+ a weekly cron the way the reference lab does), so new models are never
11
+ silently mis-priced by a stale hardcoded bucket.
12
+
13
+ Public API:
14
+ lookup(model) -> (input_$/Mtok, output_$/Mtok) # never raises
15
+ cost_usd(model, tokens_in, tokens_thought, tokens_out) -> $
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import datetime
20
+ import json
21
+ import logging
22
+ import os
23
+ import tempfile
24
+
25
+ log = logging.getLogger("swarph.bench.prices")
26
+
27
+ # card #1250. A cache older than this is refreshed on load(). Exactly this
28
+ # age is still fresh: "older than", not "at least".
29
+ PRICE_CACHE_TTL_S = 7 * 24 * 60 * 60
30
+ # Both load()-triggered fetches. refresh_prices.main() keeps its own 30s.
31
+ LOAD_FETCH_TIMEOUT_S = 5
32
+
33
+
34
+ def _default_cache_path() -> str:
35
+ """User cache, never the installed package.
36
+
37
+ card #1248: a table written next to this file lands in site-packages and
38
+ goes stale in the wheel. The cache lives under XDG_CACHE_HOME (or
39
+ ~/.cache). SWARPH_BENCH_PRICE_CACHE overrides it.
40
+ """
41
+ override = os.environ.get("SWARPH_BENCH_PRICE_CACHE")
42
+ if override:
43
+ return override
44
+ base = os.environ.get("XDG_CACHE_HOME") or os.path.join(
45
+ os.path.expanduser("~"), ".cache")
46
+ return os.path.join(base, "swarph", "llm_prices.json")
47
+
48
+
49
+ _CACHE_PATH = _default_cache_path()
50
+ _MAP: dict | None = None
51
+ # lookup() warns once per model per process when a loaded table has no row.
52
+ _FALLBACK_WARNED: set[str] = set()
53
+
54
+ # Reconciled fallbacks ($/Mtok input, output) — used ONLY when a model isn't in
55
+ # the refreshed cache. The cache is the real source; these are the safety net.
56
+ _FALLBACK = {
57
+ "pro": (1.25, 10.0),
58
+ "lite": (0.019, 0.075),
59
+ "flash": (0.30, 2.50),
60
+ }
61
+
62
+
63
+ def _now() -> datetime.datetime:
64
+ return datetime.datetime.now(datetime.timezone.utc)
65
+
66
+
67
+ def _read_payload() -> dict | None:
68
+ try:
69
+ with open(_CACHE_PATH) as f:
70
+ data = json.load(f) or {}
71
+ return data if isinstance(data, dict) else None
72
+ except Exception:
73
+ return None
74
+
75
+
76
+ def _prices_of(payload: dict | None) -> dict:
77
+ if not payload:
78
+ return {}
79
+ prices = payload.get("prices")
80
+ return prices if isinstance(prices, dict) else {}
81
+
82
+
83
+ def _generated_at(payload: dict | None) -> datetime.datetime | None:
84
+ """UTC timestamp, or None when the field is missing or unparseable."""
85
+ if not payload:
86
+ return None
87
+ raw = payload.get("generated_at")
88
+ if not isinstance(raw, str) or not raw.strip():
89
+ return None
90
+ try:
91
+ parsed = datetime.datetime.fromisoformat(raw.strip())
92
+ except ValueError:
93
+ return None
94
+ if parsed.tzinfo is None:
95
+ parsed = parsed.replace(tzinfo=datetime.timezone.utc)
96
+ return parsed
97
+
98
+
99
+ def _age_days_label(generated: datetime.datetime | None) -> str:
100
+ if generated is None:
101
+ return "unknown"
102
+ return str(max(0, int((_now() - generated).total_seconds() // 86400)))
103
+
104
+
105
+ def _read_cache() -> dict:
106
+ return _prices_of(_read_payload())
107
+
108
+
109
+ def _write_cache(prices: dict) -> None:
110
+ """Atomic write of the user cache. Never writes inside this package."""
111
+ dest = os.path.abspath(_CACHE_PATH)
112
+ pkg = os.path.dirname(os.path.abspath(__file__))
113
+ if dest == pkg or dest.startswith(pkg + os.sep):
114
+ log.warning(
115
+ "refusing to write the price table into the package tree (%s)", dest)
116
+ return
117
+ payload = {
118
+ "generated_at": _now().isoformat(),
119
+ "source": "BerriAI/litellm model_prices_and_context_window.json",
120
+ "count": len(prices),
121
+ "prices": prices,
122
+ }
123
+ try:
124
+ os.makedirs(os.path.dirname(dest), exist_ok=True)
125
+ fd, tmp = tempfile.mkstemp(dir=os.path.dirname(dest), suffix=".tmp")
126
+ with os.fdopen(fd, "w") as f:
127
+ json.dump(payload, f)
128
+ os.replace(tmp, dest)
129
+ except OSError as e:
130
+ log.warning("llm price cache not written (%s)", e)
131
+
132
+
133
+ def _fetch_into_cache() -> dict:
134
+ """Fill the user cache from the price source. Never writes inside
135
+ this package (that path is site-packages once the wheel is installed).
136
+
137
+ This is the empty-cache path. A stale cache goes through
138
+ ``refresh_prices.guard`` in ``load()`` before it is written.
139
+ """
140
+ try:
141
+ from .refresh_prices import fetch
142
+ fresh = fetch(timeout=LOAD_FETCH_TIMEOUT_S)
143
+ except Exception as e:
144
+ log.warning("llm price fetch failed (%s)", e)
145
+ return {}
146
+ if not fresh:
147
+ return {}
148
+ _write_cache(fresh)
149
+ return fresh
150
+
151
+
152
+ def _keep_stale(prior: dict, generated: datetime.datetime | None) -> dict:
153
+ log.warning(
154
+ "llm price refresh failed — keeping the stale table, %s days old",
155
+ _age_days_label(generated),
156
+ )
157
+ return prior
158
+
159
+
160
+ def load(force: bool = False) -> dict:
161
+ """The cached ``{normalized_model: {"in": $/Mtok, "out": $/Mtok}}`` map.
162
+ Cached in-process; ``force=True`` re-reads. Never raises.
163
+
164
+ A missing cache is fetched once into the user cache. If that also fails,
165
+ the empty table is a WARNING, not a DEBUG line: every later lookup is
166
+ then a built-in fallback (card #1248).
167
+
168
+ A cache older than ``PRICE_CACHE_TTL_S``, or one whose ``generated_at``
169
+ is missing or unparseable, is refreshed through ``refresh_prices.guard``.
170
+ A failed refresh keeps the stale table (card #1250).
171
+ """
172
+ global _MAP
173
+ if _MAP is not None and not force:
174
+ return _MAP
175
+ payload = _read_payload()
176
+ prior = _prices_of(payload)
177
+ generated = _generated_at(payload)
178
+ if prior and generated is not None:
179
+ age = (_now() - generated).total_seconds()
180
+ if age <= PRICE_CACHE_TTL_S:
181
+ _MAP = prior
182
+ return _MAP
183
+ if prior:
184
+ table = _refresh_stale(prior, generated)
185
+ else:
186
+ table = _fetch_into_cache()
187
+ if not table:
188
+ log.warning(
189
+ "llm price table unavailable — pricing from the built-in "
190
+ "fallbacks (pro/lite/flash). No cache at %s and the price "
191
+ "source could not be fetched.",
192
+ _CACHE_PATH,
193
+ )
194
+ _MAP = {}
195
+ return _MAP
196
+ _MAP = table
197
+ return _MAP
198
+
199
+
200
+ def _refresh_stale(prior: dict, generated: datetime.datetime | None) -> dict:
201
+ """Refetch a stale table. The guard runs only on this path, and the
202
+ guarded-count WARNING is logged only here — a first fill has no prior
203
+ to guard."""
204
+ try:
205
+ from .refresh_prices import fetch, guard
206
+ fresh = fetch(timeout=LOAD_FETCH_TIMEOUT_S)
207
+ except Exception as e:
208
+ log.warning("llm price fetch failed (%s)", e)
209
+ return _keep_stale(prior, generated)
210
+ if not fresh:
211
+ return _keep_stale(prior, generated)
212
+ merged, flagged = guard(fresh, prior)
213
+ log.warning(
214
+ "llm price refresh guarded %d change(s) against the stale table",
215
+ len(flagged),
216
+ )
217
+ _write_cache(merged)
218
+ return merged
219
+
220
+
221
+ def _norm(model: str) -> str:
222
+ """Strip provider prefix (gemini/, vertex_ai/, ...) + lowercase."""
223
+ return (model or "").split("/")[-1].strip().lower()
224
+
225
+
226
+ def lookup(model: str) -> tuple[float, float]:
227
+ """(input_$/Mtok, output_$/Mtok) for ``model``. Exact cache hit ->
228
+ substring fallback (lite before flash so 'flash-lite' resolves as lite —
229
+ order-sensitive, don't reorder). Never raises."""
230
+ m = _norm(model)
231
+ prices = load()
232
+ p = prices.get(m)
233
+ if p and "in" in p and "out" in p:
234
+ return (float(p["in"]), float(p["out"]))
235
+ # substring fallback — ORDER MATTERS: lite is a substring of flash-lite
236
+ # and must win over flash.
237
+ if "lite" in m:
238
+ chosen, label = _FALLBACK["lite"], "lite"
239
+ elif "pro" in m:
240
+ chosen, label = _FALLBACK["pro"], "pro"
241
+ else:
242
+ chosen, label = _FALLBACK["flash"], "flash"
243
+ # A loaded table that lacks this model is the #1248 defect class for a
244
+ # model upstream does not list yet. Once per model per process. An empty
245
+ # table already warned in load(); don't warn again on every lookup.
246
+ if prices and m not in _FALLBACK_WARNED:
247
+ _FALLBACK_WARNED.add(m)
248
+ log.warning(
249
+ "llm price for %s is not in the loaded table — using the %s "
250
+ "fallback %s",
251
+ m, label, chosen,
252
+ )
253
+ return chosen
254
+
255
+
256
+ def is_known(model_id: str) -> bool:
257
+ """True if ``model_id`` has an exact hit in the refreshed cache (as
258
+ opposed to resolving via the substring fallback)."""
259
+ p = load().get(_norm(model_id))
260
+ return bool(p and "in" in p and "out" in p)
261
+
262
+
263
+ def cost_usd(model_id: str, tokens_in: int, tokens_thought: int, tokens_out: int) -> float:
264
+ """Metered $ for one call: in-tokens at the input price, (thought + out)
265
+ tokens at the output price (mirrors the reference ``metered_usd()``)."""
266
+ price_in, price_out = lookup(model_id)
267
+ thought = tokens_thought or 0
268
+ return (tokens_in * price_in + (thought + tokens_out) * price_out) / 1_000_000
269
+
270
+
271
+ def all_cached(force: bool = False) -> dict[str, tuple[float, float]]:
272
+ """Every ``{model_id: (in, out)}`` currently in the refreshed cache — the
273
+ full LiteLLM-sourced price list, not just the models ``bench`` happens to
274
+ price. Exposed so the cache is a reusable mesh asset (e.g. a
275
+ cost-governor/ledger can read the same cache via ``swarph bench prices``)
276
+ rather than plumbing private to the runner."""
277
+ return {m: (float(v["in"]), float(v["out"])) for m, v in load(force=force).items()
278
+ if isinstance(v, dict) and "in" in v and "out" in v}
279
+
280
+
281
+ def fallback_buckets() -> dict[str, tuple[float, float]]:
282
+ """The 3 built-in substring-fallback buckets (pro/lite/flash), for
283
+ display when the cache is empty/stale."""
284
+ return dict(_FALLBACK)
@@ -19,6 +19,10 @@ not wired to any scheduler in this PR, just the ported fetch+guard logic.
19
19
 
20
20
  Network call — never exercised in the offline test suite (mocked or skipped).
21
21
  Read-only wrt the rest of swarph-cli: only ever writes the price cache.
22
+
23
+ ``SWARPH_BENCH_PRICE_URL`` overrides the source URL. Only the ``https``,
24
+ ``http`` and ``file`` schemes are accepted (card #1250). ``load()`` passes a
25
+ 5s timeout; this CLI keeps 30s.
22
26
  """
23
27
  from __future__ import annotations
24
28
 
@@ -26,22 +30,45 @@ import json
26
30
  import os
27
31
  import sys
28
32
  import tempfile
33
+ import urllib.parse
29
34
  import urllib.request
30
35
  from datetime import datetime, timezone
31
36
 
32
- from .prices import _CACHE_PATH as CACHE_PATH
37
+ def _cache_path() -> str:
38
+ """Read at call time so a monkeypatch of prices._CACHE_PATH is honored,
39
+ and so a refresh never keeps an import-time path inside the package."""
40
+ from .prices import _CACHE_PATH
41
+ return _CACHE_PATH
33
42
 
34
43
  LITELLM_URL = ("https://raw.githubusercontent.com/BerriAI/litellm/main/"
35
44
  "model_prices_and_context_window.json")
36
45
  GUARD_RATIO = 3.0 # reject a new price >3x or <1/3x the prior cached value
46
+ # The CLI's own fetch. load() passes prices.LOAD_FETCH_TIMEOUT_S instead.
47
+ CLI_FETCH_TIMEOUT_S = 30
48
+ _ALLOWED_SOURCE_SCHEMES = frozenset({"https", "http", "file"})
49
+
50
+
51
+ def price_source_url() -> str:
52
+ """The JSON URL ``fetch`` reads.
53
+
54
+ ``SWARPH_BENCH_PRICE_URL`` overrides ``LITELLM_URL``. Schemes other than
55
+ https, http and file are refused.
56
+ """
57
+ raw = (os.environ.get("SWARPH_BENCH_PRICE_URL") or LITELLM_URL).strip()
58
+ scheme = urllib.parse.urlparse(raw).scheme.lower()
59
+ if scheme not in _ALLOWED_SOURCE_SCHEMES:
60
+ raise ValueError(
61
+ f"SWARPH_BENCH_PRICE_URL scheme {scheme!r} is not allowed "
62
+ "(https, http, file)")
63
+ return raw
37
64
 
38
65
 
39
66
  def _norm(key: str) -> str:
40
67
  return key.split("/")[-1].strip().lower()
41
68
 
42
69
 
43
- def fetch() -> dict:
44
- raw = urllib.request.urlopen(LITELLM_URL, timeout=30).read()
70
+ def fetch(timeout: float = CLI_FETCH_TIMEOUT_S) -> dict:
71
+ raw = urllib.request.urlopen(price_source_url(), timeout=timeout).read()
45
72
  d = json.loads(raw)
46
73
  out: dict[str, dict] = {}
47
74
  for key, v in d.items():
@@ -59,7 +86,7 @@ def fetch() -> dict:
59
86
 
60
87
  def load_prior() -> dict:
61
88
  try:
62
- with open(CACHE_PATH) as f:
89
+ with open(_cache_path()) as f:
63
90
  return (json.load(f) or {}).get("prices", {}) or {}
64
91
  except Exception:
65
92
  return {}
@@ -98,11 +125,17 @@ def main() -> int:
98
125
  payload = {"generated_at": datetime.now(timezone.utc).isoformat(),
99
126
  "source": "BerriAI/litellm model_prices_and_context_window.json",
100
127
  "count": len(merged), "prices": merged}
101
- os.makedirs(os.path.dirname(CACHE_PATH), exist_ok=True)
102
- fd, tmp = tempfile.mkstemp(dir=os.path.dirname(CACHE_PATH), suffix=".tmp")
128
+ dest = _cache_path()
129
+ pkg = os.path.dirname(os.path.abspath(os.path.join(os.path.dirname(__file__), "prices.py")))
130
+ if os.path.abspath(dest).startswith(pkg + os.sep):
131
+ print(f"refresh_prices: refusing to write into the package tree ({dest})",
132
+ file=sys.stderr)
133
+ return 1
134
+ os.makedirs(os.path.dirname(dest), exist_ok=True)
135
+ fd, tmp = tempfile.mkstemp(dir=os.path.dirname(dest), suffix=".tmp")
103
136
  with os.fdopen(fd, "w") as f:
104
137
  json.dump(payload, f, indent=2, sort_keys=True)
105
- os.replace(tmp, CACHE_PATH)
138
+ os.replace(tmp, dest)
106
139
  print(f"refresh_prices: {len(merged)} models cached "
107
140
  f"({len(fresh)} fetched, {len(merged) - len(fresh)} prior-only kept). "
108
141
  f"{len(flagged)} guarded.")