swarph-cli 0.69.3__tar.gz → 0.69.5__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.
- {swarph_cli-0.69.3/src/swarph_cli.egg-info → swarph_cli-0.69.5}/PKG-INFO +3 -1
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/README.md +2 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/pyproject.toml +1 -1
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/bench/backends.py +33 -9
- swarph_cli-0.69.5/src/swarph_cli/bench/claude_cli.py +68 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/bench/runner.py +84 -1
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/bench.py +13 -2
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/daemon.py +4 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/mcp_server.py +4 -3
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/mesh.py +40 -15
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/guide/GUIDE.md +1 -1
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/scripts/ensure_monitor.sh +61 -2
- swarph_cli-0.69.5/src/swarph_cli/stall_alert.py +144 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5/src/swarph_cli.egg-info}/PKG-INFO +3 -1
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli.egg-info/SOURCES.txt +3 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_735_dm_mcp_tools.py +2 -2
- swarph_cli-0.69.5/tests/test_960_ensure_monitor_heartbeat.py +166 -0
- swarph_cli-0.69.5/tests/test_bench_claude_cli.py +67 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_bench_runner.py +72 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_mesh_inbox_mark_read.py +60 -7
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_monitor_state_split.py +5 -0
- swarph_cli-0.69.5/tests/test_stall_alert.py +140 -0
- swarph_cli-0.69.3/src/swarph_cli/stall_alert.py +0 -52
- swarph_cli-0.69.3/tests/test_stall_alert.py +0 -52
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/LICENSE +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/setup.cfg +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/bench/providers.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_board_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_group_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_import_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_init_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_main.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_security.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_service_app.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_service_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_version_command.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.69.3 → swarph_cli-0.69.5}/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.69.
|
|
3
|
+
Version: 0.69.5
|
|
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
|
|
@@ -246,6 +246,8 @@ Task types: `numeric` (rel-err), `categorical` (exact), `ranking` (Kendall-tau),
|
|
|
246
246
|
|
|
247
247
|
`provider:<name>` reads a TOML registry (`--providers`, else `$SWARPH_BENCH_PROVIDERS`, else `~/.config/swarph/bench_providers.toml`). The file names an env var; it does not hold the key. A worked example is `docs/examples/bench_providers.toml` (Jev, `env = "JEV_API_KEY"`, 0.42 USD per 1M input tokens, output free). `--max-usd` stops the run at the cap. A pack with `egress = "on_box_only"` refuses an external arm unless `--allow-egress <provider>` names it.
|
|
248
248
|
|
|
249
|
+
`claude-sonnet-5-5:subscription` runs `claude -p` on the Claude subscription when `claude` is on PATH. The argv is fixed: `--max-turns 1`, `--output-format stream-json`, `--strict-mcp-config`, an empty MCP config, `--tools ""`, `--setting-sources ""`. The prompt goes on stdin. The child environment drops `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, and every `SWARPH_CHANNEL*` name. A result whose `apiKeySource` is not `none` is `billing:<source>`, is not scored, and aborts the rest of the run on every arm. A usage limit is retried after 60s and then 300s; the arm then stops with `--ledger`, and the next run skips tasks that already completed. It is not scored as an answer.
|
|
250
|
+
|
|
249
251
|
### `swarph brain-ask` (v0.14.0)
|
|
250
252
|
|
|
251
253
|
Search the **swarph-brain** (gbrain) — the swarm's sovereign $0 semantic-retrieval memory — over MCP. The "does the swarm already know X?" reflex, as a one-shot.
|
|
@@ -197,6 +197,8 @@ Task types: `numeric` (rel-err), `categorical` (exact), `ranking` (Kendall-tau),
|
|
|
197
197
|
|
|
198
198
|
`provider:<name>` reads a TOML registry (`--providers`, else `$SWARPH_BENCH_PROVIDERS`, else `~/.config/swarph/bench_providers.toml`). The file names an env var; it does not hold the key. A worked example is `docs/examples/bench_providers.toml` (Jev, `env = "JEV_API_KEY"`, 0.42 USD per 1M input tokens, output free). `--max-usd` stops the run at the cap. A pack with `egress = "on_box_only"` refuses an external arm unless `--allow-egress <provider>` names it.
|
|
199
199
|
|
|
200
|
+
`claude-sonnet-5-5:subscription` runs `claude -p` on the Claude subscription when `claude` is on PATH. The argv is fixed: `--max-turns 1`, `--output-format stream-json`, `--strict-mcp-config`, an empty MCP config, `--tools ""`, `--setting-sources ""`. The prompt goes on stdin. The child environment drops `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, and every `SWARPH_CHANNEL*` name. A result whose `apiKeySource` is not `none` is `billing:<source>`, is not scored, and aborts the rest of the run on every arm. A usage limit is retried after 60s and then 300s; the arm then stops with `--ledger`, and the next run skips tasks that already completed. It is not scored as an answer.
|
|
201
|
+
|
|
200
202
|
### `swarph brain-ask` (v0.14.0)
|
|
201
203
|
|
|
202
204
|
Search the **swarph-brain** (gbrain) — the swarm's sovereign $0 semantic-retrieval memory — over MCP. The "does the swarm already know X?" reflex, as a one-shot.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "swarph-cli"
|
|
7
|
-
version = "0.69.
|
|
7
|
+
version = "0.69.5"
|
|
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" }
|
|
@@ -14,11 +14,11 @@ Ships these backends:
|
|
|
14
14
|
passes ``vertexai=False`` EXPLICITLY — a ``GOOGLE_GENAI_USE_VERTEXAI=true``
|
|
15
15
|
env 401s API-key auth (this exact bug bit the reference lab; see
|
|
16
16
|
``model_showdown.py::run_metered``).
|
|
17
|
-
- :class:`SubscriptionBackend` — a
|
|
18
|
-
ESTIMATED (``~len(text)/4
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
- :class:`SubscriptionBackend` — a stub until a ``call_fn`` is wired. A
|
|
18
|
+
string return is still ESTIMATED (``~len(text)/4``). A
|
|
19
|
+
:class:`~swarph_cli.bench.claude_cli.CliResult` uses the CLI's reported
|
|
20
|
+
usage (``estimated=False``). ``swarph bench`` wires ``claude -p`` when
|
|
21
|
+
the ``claude`` binary is on PATH.
|
|
22
22
|
- :class:`RuleBackend` — in-process ``rule:<module:callable>``. No credentials.
|
|
23
23
|
- :class:`TypedHttpBackend` — POST to a Jev-compatible ``/v1/systemone``
|
|
24
24
|
(laya-serve). No credentials; per-item latency is the HTTP round trip.
|
|
@@ -229,6 +229,15 @@ class MeteredMistralBackend:
|
|
|
229
229
|
)
|
|
230
230
|
|
|
231
231
|
|
|
232
|
+
def normalize_judge_action(text: str) -> str:
|
|
233
|
+
"""BUY or SKIP, after trimming and uppercasing. Anything else is ABSTAIN."""
|
|
234
|
+
try:
|
|
235
|
+
action = str(json.loads(text).get("action", "")).strip().upper()
|
|
236
|
+
except Exception:
|
|
237
|
+
return "ABSTAIN"
|
|
238
|
+
return action if action in ("BUY", "SKIP") else "ABSTAIN"
|
|
239
|
+
|
|
240
|
+
|
|
232
241
|
class SubscriptionBackend:
|
|
233
242
|
KIND = "semantic"
|
|
234
243
|
"""STUB/interface-only backend for a $0 subscription path (e.g. a node's
|
|
@@ -271,20 +280,35 @@ class SubscriptionBackend:
|
|
|
271
280
|
)
|
|
272
281
|
t0 = time.time()
|
|
273
282
|
try:
|
|
274
|
-
|
|
283
|
+
raw = self._call_fn(model_id, prompt, system)
|
|
275
284
|
except Exception as exc:
|
|
276
285
|
return BackendResult(
|
|
277
286
|
text="", tokens_in=0, tokens_thought=0, tokens_out=0,
|
|
278
287
|
latency_s=round(time.time() - t0, 2), estimated=True, error=str(exc),
|
|
279
288
|
)
|
|
280
289
|
latency_s = round(time.time() - t0, 2)
|
|
290
|
+
if raw is None or isinstance(raw, str):
|
|
291
|
+
text = raw or ""
|
|
292
|
+
return BackendResult(
|
|
293
|
+
text=text,
|
|
294
|
+
tokens_in=estimate_tokens(prompt),
|
|
295
|
+
tokens_thought=0,
|
|
296
|
+
tokens_out=estimate_tokens(text),
|
|
297
|
+
latency_s=latency_s,
|
|
298
|
+
estimated=True,
|
|
299
|
+
)
|
|
300
|
+
# CliResult from claude_cli: real usage, and the billing/rate-limit error
|
|
301
|
+
# is the result, not an exception. An error discards the answer text.
|
|
302
|
+
err = getattr(raw, "error", None)
|
|
303
|
+
text = "" if err else (getattr(raw, "text", "") or "")
|
|
281
304
|
return BackendResult(
|
|
282
305
|
text=text,
|
|
283
|
-
tokens_in=
|
|
306
|
+
tokens_in=int(getattr(raw, "tokens_in", 0) or 0),
|
|
284
307
|
tokens_thought=0,
|
|
285
|
-
tokens_out=
|
|
308
|
+
tokens_out=int(getattr(raw, "tokens_out", 0) or 0),
|
|
286
309
|
latency_s=latency_s,
|
|
287
|
-
estimated=
|
|
310
|
+
estimated=False,
|
|
311
|
+
error=err,
|
|
288
312
|
)
|
|
289
313
|
|
|
290
314
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""claude -p transport for the bench `subscription` backend (#999). Subscription-only,
|
|
2
|
+
isolated, billing-guarded. Measured 2026-09-29: without the isolation flags one call loaded
|
|
3
|
+
286 tools and 213k cache-write tokens; with them, 0 tools and ~421 input tokens."""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import subprocess
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
_STRIP_EXACT = ("ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN")
|
|
12
|
+
_RATE = ("usage limit", "rate limit", "429", "overloaded")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class CliResult:
|
|
17
|
+
text: str
|
|
18
|
+
tokens_in: int
|
|
19
|
+
tokens_out: int
|
|
20
|
+
api_key_source: Optional[str]
|
|
21
|
+
cost_equiv: Optional[float]
|
|
22
|
+
error: Optional[str] = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def build_argv(model_id: str, system: str) -> list:
|
|
26
|
+
return ["claude", "-p", "--model", model_id, "--system-prompt", system, "--max-turns", "1",
|
|
27
|
+
"--output-format", "stream-json", "--verbose", "--strict-mcp-config",
|
|
28
|
+
"--mcp-config", '{"mcpServers":{}}', "--tools", "", "--setting-sources", ""]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def clean_env(env: dict) -> dict:
|
|
32
|
+
"""Drop billing keys and every SWARPH_CHANNEL* name, including ones not listed yet."""
|
|
33
|
+
return {
|
|
34
|
+
k: v for k, v in env.items()
|
|
35
|
+
if k not in _STRIP_EXACT and not k.startswith("SWARPH_CHANNEL")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def parse_stream(lines) -> CliResult:
|
|
40
|
+
key, res = None, None
|
|
41
|
+
for ln in lines:
|
|
42
|
+
try:
|
|
43
|
+
e = json.loads(ln)
|
|
44
|
+
except Exception:
|
|
45
|
+
continue
|
|
46
|
+
if e.get("type") == "system" and e.get("subtype") == "init":
|
|
47
|
+
key = e.get("apiKeySource")
|
|
48
|
+
elif e.get("type") == "result":
|
|
49
|
+
res = e
|
|
50
|
+
if res is None:
|
|
51
|
+
return CliResult("", 0, 0, key, None, error="no_result")
|
|
52
|
+
u = res.get("usage") or {}
|
|
53
|
+
tin = sum(int(u.get(k) or 0) for k in ("input_tokens", "cache_creation_input_tokens", "cache_read_input_tokens"))
|
|
54
|
+
out = CliResult(res.get("result") or "", tin, int(u.get("output_tokens") or 0), key, res.get("total_cost_usd"))
|
|
55
|
+
if key != "none":
|
|
56
|
+
return CliResult("", tin, out.tokens_out, key, out.cost_equiv, error=f"billing:{key}")
|
|
57
|
+
if res.get("is_error"):
|
|
58
|
+
msg = (res.get("result") or "").lower()
|
|
59
|
+
out.text = ""
|
|
60
|
+
out.error = "rate_limit" if any(t in msg for t in _RATE) else f"cli_error:{res.get('subtype')}"
|
|
61
|
+
return out
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def call(model_id: str, prompt: str, system: str, *, runner=subprocess.run, timeout: int = 300) -> CliResult:
|
|
65
|
+
import os
|
|
66
|
+
p = runner(build_argv(model_id, system), input=prompt, capture_output=True, text=True,
|
|
67
|
+
env=clean_env(dict(os.environ)), timeout=timeout)
|
|
68
|
+
return parse_stream((p.stdout or "").splitlines())
|
|
@@ -12,6 +12,7 @@ alongside the aggregate, and the CLI always PRINTS it.
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
14
|
import json
|
|
15
|
+
import time
|
|
15
16
|
from dataclasses import dataclass, field
|
|
16
17
|
from datetime import datetime, timezone
|
|
17
18
|
from typing import Optional
|
|
@@ -95,6 +96,7 @@ class TaskRow:
|
|
|
95
96
|
estimated: bool
|
|
96
97
|
error: Optional[str] = None
|
|
97
98
|
not_run: Optional[str] = None
|
|
99
|
+
text: str = ""
|
|
98
100
|
|
|
99
101
|
|
|
100
102
|
@dataclass
|
|
@@ -225,6 +227,33 @@ def _secrets_of(specs, backends) -> list:
|
|
|
225
227
|
return found
|
|
226
228
|
|
|
227
229
|
|
|
230
|
+
def _taskrow_from_ledger(item: dict) -> TaskRow:
|
|
231
|
+
return TaskRow(
|
|
232
|
+
task_id=item["task_id"],
|
|
233
|
+
cls=item.get("cls") or "",
|
|
234
|
+
distance=float(item.get("distance") or 0.0),
|
|
235
|
+
parse_ok=bool(item.get("parse_ok")),
|
|
236
|
+
tokens_in=int(item.get("tokens_in") or 0),
|
|
237
|
+
tokens_thought=int(item.get("tokens_thought") or 0),
|
|
238
|
+
tokens_out=int(item.get("tokens_out") or 0),
|
|
239
|
+
latency_s=float(item.get("latency_s") or 0.0),
|
|
240
|
+
cost_usd=float(item.get("cost_usd") or 0.0),
|
|
241
|
+
estimated=bool(item.get("estimated")),
|
|
242
|
+
error=item.get("error"),
|
|
243
|
+
not_run=item.get("not_run"),
|
|
244
|
+
text=item.get("text") or "",
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _skipped(task: dict, reason: str) -> TaskRow:
|
|
249
|
+
"""A task that was not scored. rate_limit is retryable, never an ABSTAIN."""
|
|
250
|
+
return TaskRow(
|
|
251
|
+
task_id=task["id"], cls=class_of(task), distance=0.0, parse_ok=False,
|
|
252
|
+
tokens_in=0, tokens_thought=0, tokens_out=0, latency_s=0.0,
|
|
253
|
+
cost_usd=0.0, estimated=False, error=reason, not_run=reason, text="",
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
228
257
|
def run_pack(
|
|
229
258
|
specs: list[ModelSpec],
|
|
230
259
|
pack: dict,
|
|
@@ -235,6 +264,7 @@ def run_pack(
|
|
|
235
264
|
max_usd_per_arm: Optional[float] = None,
|
|
236
265
|
allow_egress: Optional[set[str]] = None,
|
|
237
266
|
ledger_path: Optional[str] = None,
|
|
267
|
+
sleeper=None,
|
|
238
268
|
) -> dict:
|
|
239
269
|
"""Run every spec against every task in ``pack`` (or a ``task_ids``
|
|
240
270
|
subset). ``backends`` maps backend-name ("metered"/"subscription"/...) ->
|
|
@@ -260,6 +290,17 @@ def run_pack(
|
|
|
260
290
|
secrets = _secrets_of(specs, backends)
|
|
261
291
|
allow_egress = allow_egress or set()
|
|
262
292
|
overrides = []
|
|
293
|
+
sleep = sleeper or time.sleep
|
|
294
|
+
run_aborted = False
|
|
295
|
+
prior_detail: dict = {}
|
|
296
|
+
if ledger_path:
|
|
297
|
+
from pathlib import Path
|
|
298
|
+
ledger = Path(ledger_path)
|
|
299
|
+
if ledger.is_file():
|
|
300
|
+
try:
|
|
301
|
+
prior_detail = json.loads(ledger.read_text(encoding="utf-8")).get("detail") or {}
|
|
302
|
+
except (OSError, json.JSONDecodeError):
|
|
303
|
+
prior_detail = {}
|
|
263
304
|
|
|
264
305
|
for spec in specs:
|
|
265
306
|
backend = _bound(spec, backends)
|
|
@@ -272,9 +313,24 @@ def run_pack(
|
|
|
272
313
|
"at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
273
314
|
})
|
|
274
315
|
|
|
316
|
+
resumed = {}
|
|
317
|
+
for item in prior_detail.get(spec.label) or []:
|
|
318
|
+
if isinstance(item, dict) and item.get("task_id") and item.get("error") is None and not item.get("not_run"):
|
|
319
|
+
resumed[item["task_id"]] = _taskrow_from_ledger(item)
|
|
320
|
+
|
|
275
321
|
rows: list[TaskRow] = []
|
|
276
322
|
arm_spent = 0.0
|
|
323
|
+
arm_stopped = False
|
|
277
324
|
for task in tasks:
|
|
325
|
+
if task["id"] in resumed:
|
|
326
|
+
rows.append(resumed[task["id"]])
|
|
327
|
+
continue
|
|
328
|
+
if run_aborted:
|
|
329
|
+
rows.append(_skipped(task, "aborted"))
|
|
330
|
+
continue
|
|
331
|
+
if arm_stopped:
|
|
332
|
+
rows.append(_skipped(task, "rate_limit"))
|
|
333
|
+
continue
|
|
278
334
|
if (max_usd is not None and spent >= max_usd) or (
|
|
279
335
|
max_usd_per_arm is not None and arm_spent >= max_usd_per_arm):
|
|
280
336
|
partial = "spend_cap"
|
|
@@ -286,8 +342,31 @@ def run_pack(
|
|
|
286
342
|
))
|
|
287
343
|
continue
|
|
288
344
|
result = _dispatch(backend, spec.id, task["prompt"], system)
|
|
345
|
+
rate_hits = 0
|
|
346
|
+
while result.error == "rate_limit" and rate_hits < 2:
|
|
347
|
+
sleep(60 if rate_hits == 0 else 300)
|
|
348
|
+
rate_hits += 1
|
|
349
|
+
result = _dispatch(backend, spec.id, task["prompt"], system)
|
|
289
350
|
if result.error:
|
|
290
351
|
result.error = _redact(result.error, secrets)
|
|
352
|
+
if result.error and str(result.error).startswith("billing:"):
|
|
353
|
+
# A billing leak aborts every remaining task on every arm.
|
|
354
|
+
# The answer is already empty. One such call stops the run.
|
|
355
|
+
partial = "aborted"
|
|
356
|
+
run_aborted = True
|
|
357
|
+
rows.append(TaskRow(
|
|
358
|
+
task_id=task["id"], cls=class_of(task), distance=0.0, parse_ok=False,
|
|
359
|
+
tokens_in=result.tokens_in, tokens_thought=result.tokens_thought,
|
|
360
|
+
tokens_out=result.tokens_out, latency_s=result.latency_s,
|
|
361
|
+
cost_usd=0.0, estimated=result.estimated, error=result.error,
|
|
362
|
+
not_run="aborted", text="",
|
|
363
|
+
))
|
|
364
|
+
continue
|
|
365
|
+
if result.error == "rate_limit":
|
|
366
|
+
partial = "rate_limit"
|
|
367
|
+
arm_stopped = True
|
|
368
|
+
rows.append(_skipped(task, "rate_limit"))
|
|
369
|
+
continue
|
|
291
370
|
if result.error:
|
|
292
371
|
rows.append(TaskRow(
|
|
293
372
|
task_id=task["id"], cls=class_of(task), distance=1.0, parse_ok=False,
|
|
@@ -308,6 +387,7 @@ def run_pack(
|
|
|
308
387
|
latency_s=result.latency_s,
|
|
309
388
|
cost_usd=usd,
|
|
310
389
|
estimated=result.estimated or unknown,
|
|
390
|
+
text=result.text,
|
|
311
391
|
))
|
|
312
392
|
detail[spec.label] = rows
|
|
313
393
|
|
|
@@ -340,7 +420,9 @@ def run_pack(
|
|
|
340
420
|
estimated=any(r.estimated for r in done),
|
|
341
421
|
per_class=per_class,
|
|
342
422
|
errors=sum(1 for r in rows if r.error and not r.not_run),
|
|
343
|
-
partial="
|
|
423
|
+
partial=("aborted" if any(r.not_run == "aborted" for r in rows)
|
|
424
|
+
else "rate_limit" if any(r.not_run == "rate_limit" for r in rows)
|
|
425
|
+
else "spend_cap" if any(r.not_run for r in rows) else None),
|
|
344
426
|
price_source=(getattr(backend, "price", None) or {}).get("source", "")
|
|
345
427
|
if isinstance(getattr(backend, "price", None), dict) else "",
|
|
346
428
|
egress=_arm_egress(spec, backend),
|
|
@@ -354,6 +436,7 @@ def run_pack(
|
|
|
354
436
|
"theme": pack.get("theme"),
|
|
355
437
|
"tasks_total": len(tasks),
|
|
356
438
|
"partial": partial,
|
|
439
|
+
"aborted": partial == "aborted",
|
|
357
440
|
"exit_code": 1 if partial else 0,
|
|
358
441
|
"egress_overrides": overrides,
|
|
359
442
|
"board": [vars(b) for b in board],
|
|
@@ -17,6 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
|
|
18
18
|
import argparse
|
|
19
19
|
import json
|
|
20
|
+
import shutil
|
|
20
21
|
import sys
|
|
21
22
|
from pathlib import Path
|
|
22
23
|
from typing import Optional
|
|
@@ -53,10 +54,16 @@ def _default_backends() -> dict[str, Backend]:
|
|
|
53
54
|
`metered` stays bound to Gemini so existing `id:metered` specs keep their
|
|
54
55
|
meaning; mistral is its own key rather than a redefinition.
|
|
55
56
|
"""
|
|
57
|
+
# claude on PATH wires the subscription lane to an isolated `claude -p`
|
|
58
|
+
# (card #999). Without the binary the stub stays, and preflight skips it.
|
|
59
|
+
subscription = SubscriptionBackend()
|
|
60
|
+
if shutil.which("claude"):
|
|
61
|
+
from swarph_cli.bench.claude_cli import call as claude_call
|
|
62
|
+
subscription = SubscriptionBackend(call_fn=claude_call)
|
|
56
63
|
return {
|
|
57
64
|
"metered": MeteredGeminiBackend(),
|
|
58
65
|
"mistral": MeteredMistralBackend(),
|
|
59
|
-
"subscription":
|
|
66
|
+
"subscription": subscription,
|
|
60
67
|
"rule": RuleBackend(),
|
|
61
68
|
"typed-http": TypedHttpBackend(),
|
|
62
69
|
# Selectable class for the wiring lock. A real call is provider:<name>,
|
|
@@ -138,6 +145,9 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
138
145
|
r.add_argument("--max-usd-per-arm", type=float, default=None)
|
|
139
146
|
r.add_argument("--allow-egress", action="append", default=[], help="provider allowed off-box")
|
|
140
147
|
r.add_argument("--allow-unpriced", action="append", default=[], help="provider allowed with no price under a cap")
|
|
148
|
+
r.add_argument("--ledger", default=None,
|
|
149
|
+
help="JSON path. A re-run skips tasks that already completed; "
|
|
150
|
+
"a usage limit stops the arm here and the next run resumes")
|
|
141
151
|
r.add_argument("--strict", action="store_true",
|
|
142
152
|
help="abort (no dispatch) if ANY requested model lacks credentials, "
|
|
143
153
|
"instead of skipping it and running the rest")
|
|
@@ -223,7 +233,8 @@ def _cmd_run(args) -> int:
|
|
|
223
233
|
|
|
224
234
|
result = run_pack(
|
|
225
235
|
runnable, pack, backends, max_usd=args.max_usd,
|
|
226
|
-
max_usd_per_arm=args.max_usd_per_arm, allow_egress=allow_egress
|
|
236
|
+
max_usd_per_arm=args.max_usd_per_arm, allow_egress=allow_egress,
|
|
237
|
+
ledger_path=args.ledger)
|
|
227
238
|
if args.report == "json":
|
|
228
239
|
print(json.dumps(result, indent=2))
|
|
229
240
|
else:
|
|
@@ -381,8 +381,12 @@ def _legacy_attempt_delivery_removed(state: DaemonState) -> None:
|
|
|
381
381
|
entries = state.queue.pending()
|
|
382
382
|
block = _render_delivery_block(entries)
|
|
383
383
|
if session_bridge.inject(pane, block):
|
|
384
|
+
stalled = state.queue.deferred_ticks
|
|
384
385
|
state.queue.remove({e["id"] for e in entries})
|
|
385
386
|
state.queue.reset_deferred()
|
|
387
|
+
if stalled:
|
|
388
|
+
stall_alert.clear_stall_alert(
|
|
389
|
+
state.gateway, state.token, state.self_name)
|
|
386
390
|
# inject failure → leave queued, retry next tick (no counter bump —
|
|
387
391
|
# the cell was idle; a send failure is transient, not a stall).
|
|
388
392
|
except Exception as exc: # noqa: BLE001 — bridge must never crash the loop
|
|
@@ -344,14 +344,15 @@ def _dm_reply(message_id: int, text: str, kind: str = "answer",
|
|
|
344
344
|
st, d = _mesh._post_json(f"{gw}/messages", body, tok)
|
|
345
345
|
if not (200 <= st < 300):
|
|
346
346
|
return {"error": f"gateway {st}: {d.get('detail', d) if isinstance(d, dict) else d}"}
|
|
347
|
-
|
|
347
|
+
failed = _mesh._mark_read(gw, tok, [{"id": int(message_id)}])
|
|
348
|
+
acked = int(message_id) not in failed
|
|
348
349
|
return {
|
|
349
350
|
"id": d.get("id"),
|
|
350
351
|
"to_node": to,
|
|
351
352
|
"kind": kind,
|
|
352
353
|
"thread_id": d.get("thread_id"),
|
|
353
|
-
"acked": int(message_id) if
|
|
354
|
-
"ack_status":
|
|
354
|
+
"acked": int(message_id) if acked else None,
|
|
355
|
+
"ack_status": 200 if acked else 0,
|
|
355
356
|
"closed_obligations": d.get("closed_obligations") or [],
|
|
356
357
|
}
|
|
357
358
|
except Exception as exc:
|
|
@@ -944,38 +944,58 @@ def _run_reply(args: argparse.Namespace) -> int:
|
|
|
944
944
|
return 0
|
|
945
945
|
|
|
946
946
|
|
|
947
|
-
|
|
947
|
+
_BULK_READ_MAX = 500
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
def _mark_read(gateway: str, token: str, messages: list) -> list:
|
|
948
951
|
"""Mark every unread DM we just surfaced as read. Best-effort.
|
|
949
952
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
because the CLI never called the gateway's POST /messages/{id}/read.
|
|
953
|
+
One POST /messages/read per 500 ids. The gateway's single worker spends a
|
|
954
|
+
synchronous sqlite write on every request, so a per-id loop is how a drain
|
|
955
|
+
turns into HTTP 503. A 404 means that route is not on this gateway yet, and
|
|
956
|
+
only then does this fall back to one POST per id.
|
|
955
957
|
|
|
956
958
|
A mark-read failure must NEVER fail the listing — the caller has already seen
|
|
957
959
|
the messages, and losing the read receipt is strictly less bad than losing them.
|
|
958
960
|
"""
|
|
959
961
|
base = gateway.rstrip("/")
|
|
960
|
-
|
|
962
|
+
ids = []
|
|
961
963
|
for dm in messages:
|
|
962
|
-
if dm
|
|
963
|
-
|
|
964
|
-
|
|
964
|
+
if isinstance(dm, dict):
|
|
965
|
+
if dm.get("read_at"):
|
|
966
|
+
continue
|
|
967
|
+
msg_id = dm.get("id")
|
|
968
|
+
else:
|
|
969
|
+
msg_id = dm
|
|
965
970
|
if msg_id is None:
|
|
966
971
|
continue
|
|
972
|
+
ids.append(msg_id)
|
|
973
|
+
failed = []
|
|
974
|
+
for start in range(0, len(ids), _BULK_READ_MAX):
|
|
975
|
+
chunk = ids[start:start + _BULK_READ_MAX]
|
|
967
976
|
try:
|
|
968
|
-
status, _ = _post_json(f"{base}/messages/
|
|
969
|
-
if status < 200 or status >= 300:
|
|
970
|
-
failed.append(msg_id)
|
|
977
|
+
status, _ = _post_json(f"{base}/messages/read", {"ids": chunk}, token)
|
|
971
978
|
except Exception: # network, DNS, timeout — never break the listing
|
|
972
|
-
failed.
|
|
979
|
+
failed.extend(chunk)
|
|
980
|
+
continue
|
|
981
|
+
if status == 404:
|
|
982
|
+
for msg_id in chunk:
|
|
983
|
+
try:
|
|
984
|
+
one, _ = _post_json(f"{base}/messages/{msg_id}/read", {}, token)
|
|
985
|
+
if one < 200 or one >= 300:
|
|
986
|
+
failed.append(msg_id)
|
|
987
|
+
except Exception:
|
|
988
|
+
failed.append(msg_id)
|
|
989
|
+
continue
|
|
990
|
+
if status < 200 or status >= 300:
|
|
991
|
+
failed.extend(chunk)
|
|
973
992
|
if failed:
|
|
974
993
|
print(
|
|
975
994
|
f"swarph mesh inbox: mark-read failed for id(s) {failed} "
|
|
976
995
|
"(messages shown above; they will be re-listed as unread)",
|
|
977
996
|
file=sys.stderr,
|
|
978
997
|
)
|
|
998
|
+
return failed
|
|
979
999
|
|
|
980
1000
|
|
|
981
1001
|
def _run_inbox(args: argparse.Namespace) -> int:
|
|
@@ -2673,7 +2693,8 @@ def _monitor_deliver(state: MonitorState) -> None:
|
|
|
2673
2693
|
f"no failure counted",
|
|
2674
2694
|
flush=True)
|
|
2675
2695
|
continue
|
|
2676
|
-
|
|
2696
|
+
was_stalled = bool(led.get("deferred_ticks"))
|
|
2697
|
+
if was_stalled:
|
|
2677
2698
|
led["deferred_ticks"] = 0
|
|
2678
2699
|
if outcome:
|
|
2679
2700
|
led["last_delivered_id"] = observed
|
|
@@ -2682,6 +2703,10 @@ def _monitor_deliver(state: MonitorState) -> None:
|
|
|
2682
2703
|
state.deliveries[sink.name] = state.deliveries.get(sink.name, 0) + 1
|
|
2683
2704
|
print(f"{state.log_prefix} delivered to {sink.name} up to id {observed}",
|
|
2684
2705
|
flush=True)
|
|
2706
|
+
if was_stalled:
|
|
2707
|
+
from swarph_cli import stall_alert
|
|
2708
|
+
stall_alert.clear_stall_alert(
|
|
2709
|
+
state.gateway, state.token, state.self_name)
|
|
2685
2710
|
else:
|
|
2686
2711
|
# A dead sink is VISIBLE instead of silently freezing anything.
|
|
2687
2712
|
led["consecutive_failures"] = int(led["consecutive_failures"]) + 1
|
|
@@ -488,7 +488,7 @@ registry name the SAME set, so a verb shipped without a line here is a red test.
|
|
|
488
488
|
answers `--help`; hook-plumbing verbs are the callbacks hooks invoke, not commands you type.
|
|
489
489
|
|
|
490
490
|
- `swarph add` -- install a swarph artifact by `swarph://` URI (magnet-link style).
|
|
491
|
-
- `swarph bench` -- deterministic LLM benchmark-pack runner (card #101). `provider:<name>` uses a TOML registry of env-var names (example `docs/examples/bench_providers.toml`, Jev at 0.42 USD per 1M input tokens, output free). `--max-usd` is a hard cap. `egress = "on_box_only"` refuses an external arm unless `--allow-egress` names that provider.
|
|
491
|
+
- `swarph bench` -- deterministic LLM benchmark-pack runner (card #101). `provider:<name>` uses a TOML registry of env-var names (example `docs/examples/bench_providers.toml`, Jev at 0.42 USD per 1M input tokens, output free). `--max-usd` is a hard cap. `egress = "on_box_only"` refuses an external arm unless `--allow-egress` names that provider. `claude-sonnet-5-5:subscription` is `claude -p` on the Claude subscription (isolation flags, billing guard requires `apiKeySource=none` and aborts every arm, prompt on stdin, every `SWARPH_CHANNEL*` name stripped). A usage limit retries 60s then 300s and resumes from `--ledger`; it is not scored.
|
|
492
492
|
- `swarph board` -- the mesh board: projects, cards, obligations (see [The board](#the-board)).
|
|
493
493
|
- `swarph brain` -- run the gbrain HTTP brain server, the $0 semantic memory.
|
|
494
494
|
- `swarph brain-ask` -- search the swarph-brain memory with a question; optional $0 synthesis.
|
|
@@ -64,12 +64,71 @@ STATE_DIR="${1:-${SWARPH_STATE_DIR:-}}"
|
|
|
64
64
|
SD=()
|
|
65
65
|
[ -n "$STATE_DIR" ] && SD=(--state-dir "$STATE_DIR")
|
|
66
66
|
|
|
67
|
+
# >>> #960: a fresh channel heartbeat is already a reader. <<<
|
|
68
|
+
# swarph channel-serve writes channel_heartbeat.json beside the inbox every
|
|
69
|
+
# 60s and names no path on its command line, so `monitor status` cannot see
|
|
70
|
+
# it. Starting a pull monitor beside a heartbeat younger than 180s is the
|
|
71
|
+
# duplicate this script exists to prevent. Absent or older: start, as before.
|
|
72
|
+
# A missing python3 is treated as absent (start), never as a failed caller.
|
|
73
|
+
_heartbeat_fresh() {
|
|
74
|
+
local f="$1"
|
|
75
|
+
[ -n "$f" ] && [ -f "$f" ] || return 1
|
|
76
|
+
command -v python3 >/dev/null 2>&1 || return 1
|
|
77
|
+
python3 -c 'import json,os,sys,time
|
|
78
|
+
try:
|
|
79
|
+
data=json.load(open(sys.argv[1],encoding="utf-8"))
|
|
80
|
+
ts=float(data.get("ts") or 0)
|
|
81
|
+
except Exception:
|
|
82
|
+
raise SystemExit(1)
|
|
83
|
+
age=time.time()-ts
|
|
84
|
+
# A clock a few seconds ahead is still a live writer. An hour ahead is not.
|
|
85
|
+
if age < -30 or age >= 180:
|
|
86
|
+
raise SystemExit(1)
|
|
87
|
+
pid=data.get("pid")
|
|
88
|
+
if pid is None:
|
|
89
|
+
raise SystemExit(0)
|
|
90
|
+
try:
|
|
91
|
+
pid=int(pid)
|
|
92
|
+
except (TypeError, ValueError):
|
|
93
|
+
raise SystemExit(1)
|
|
94
|
+
# pid 0 is this process group and pid -1 is every process we can signal.
|
|
95
|
+
# Neither is the channel server. os.kill would report both as alive.
|
|
96
|
+
if pid <= 0:
|
|
97
|
+
raise SystemExit(1)
|
|
98
|
+
try:
|
|
99
|
+
os.kill(pid, 0)
|
|
100
|
+
except PermissionError:
|
|
101
|
+
pass
|
|
102
|
+
except OSError:
|
|
103
|
+
raise SystemExit(1)
|
|
104
|
+
try:
|
|
105
|
+
raw=open("/proc/%s/cmdline" % pid, "rb").read()
|
|
106
|
+
except OSError:
|
|
107
|
+
# No command line to read (macOS, or a pid we may not inspect).
|
|
108
|
+
# A live pid still counts, which is the check this host can make.
|
|
109
|
+
raise SystemExit(0)
|
|
110
|
+
text=raw.replace(b"\x00", b" ").decode("utf-8", "replace")
|
|
111
|
+
if "channel-serve" in text or "swarph_cli.channel" in text:
|
|
112
|
+
raise SystemExit(0)
|
|
113
|
+
raise SystemExit(1)' "$f"
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
HB_ROOT="${STATE_DIR:-$HOME/swarph_state/$SELF}"
|
|
117
|
+
HB_FILE=""
|
|
118
|
+
if [ -f "$HB_ROOT/channel_heartbeat.json" ]; then
|
|
119
|
+
HB_FILE="$HB_ROOT/channel_heartbeat.json"
|
|
120
|
+
elif [ -f "$HB_ROOT/mesh-sidecar/channel_heartbeat.json" ]; then
|
|
121
|
+
HB_FILE="$HB_ROOT/mesh-sidecar/channel_heartbeat.json"
|
|
122
|
+
fi
|
|
123
|
+
|
|
67
124
|
"$SW" monitor status --as "$SELF" ${SD[@]+"${SD[@]}"} >/dev/null 2>&1
|
|
68
125
|
case $? in
|
|
69
126
|
0) ;; # running, nothing pending
|
|
70
127
|
1) ;; # running, DMs pending — reported below
|
|
71
|
-
*) # not running (2) or unknown
|
|
72
|
-
if
|
|
128
|
+
*) # not running (2) or unknown.
|
|
129
|
+
if _heartbeat_fresh "$HB_FILE"; then
|
|
130
|
+
echo "[monitor] channel heartbeat is under 180s old — not starting a monitor"
|
|
131
|
+
elif "$SW" monitor start --as "$SELF" --deliver pull ${SD[@]+"${SD[@]}"} >/tmp/.swarph-monitor-start.$$ 2>&1; then
|
|
73
132
|
echo "[monitor] started (--deliver pull)"
|
|
74
133
|
else
|
|
75
134
|
# LOUD, not silent: an auto-start that fails quietly rebuilds the exact
|