swarph-cli 0.72.18__tar.gz → 0.72.20__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.72.18/src/swarph_cli.egg-info → swarph_cli-0.72.20}/PKG-INFO +1 -1
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/pyproject.toml +1 -1
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/providers.py +20 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/validate.py +57 -6
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/bench.py +3 -16
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/wake_watchdog.py +41 -2
- {swarph_cli-0.72.18 → swarph_cli-0.72.20/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_729_wake_watchdog.py +51 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_validate.py +141 -1
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/LICENSE +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/README.md +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/setup.cfg +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/codex_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/bench/signal_score.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/mesh.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/roster.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/rowclear_hook.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/sweep.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/triage.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/guide/GUIDE.md +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/__main__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/api.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/config.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/operator/fmt.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/quota_sync.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/rowclear.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/scrub.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-triage.service +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/__init__.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/backend.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/job.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/owners.json +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/router.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/rows.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/triage/sensor.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli.egg-info/SOURCES.txt +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1006_board_publisher.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1006_session_board.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1010_strand_only.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1013_spawn_channel.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1017_muse_tui.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1050_surrogate_wake.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1052_opencode_deaf.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1059_watchdog_unread_env.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1061_roster_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1064_stuck_sweep.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1065_release.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1066_quiet_wakes.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1068_structured_accept_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1071_quota_sync.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1073_triage.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1073_triage_board.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1073_wheel_install.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1075_task_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_1083_openai_decisions.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_432_rowclear.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_484_codex_queue_sink.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_538_signal_bench.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_729_arm_check_delivery_gap.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_735_dm_mcp_tools.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_739_wake_writer.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_961_cursor_grok_footer.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_961_loud_stop.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_codex_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_board_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_copilot_membrane.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_copilot_pane_reader.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_group_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_import_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_init_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_main.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_sidecar_muse_sink.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_operator_me.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_scrub.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_security.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_service_app.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_service_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_version_command.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.72.18 → swarph_cli-0.72.20}/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.
|
|
3
|
+
Version: 0.72.20
|
|
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.
|
|
7
|
+
version = "0.72.20"
|
|
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" }
|
|
@@ -99,3 +99,23 @@ def load_registry(path: str | Path | None) -> dict[str, dict]:
|
|
|
99
99
|
raw = Path(path).read_text(encoding="utf-8")
|
|
100
100
|
data = tomllib.loads(raw)
|
|
101
101
|
return {name: _check(name, entry) for name, entry in data.items()}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def provider_arm(name: str, entry: dict, noul_threshold):
|
|
105
|
+
"""The registry arm for ``provider:<name>``.
|
|
106
|
+
|
|
107
|
+
``kind = "decisions"`` is the OpenAI Decisions translator. ``typed`` and
|
|
108
|
+
``semantic`` stay on :class:`~swarph_cli.bench.backends.HttpBackend`,
|
|
109
|
+
which posts a typed pack body unchanged.
|
|
110
|
+
"""
|
|
111
|
+
from .backends import DecisionsBackend, HttpBackend
|
|
112
|
+
|
|
113
|
+
common = dict(
|
|
114
|
+
name=name, base_url=entry["base_url"], path=entry["path"],
|
|
115
|
+
auth=entry.get("auth"), usage=entry.get("usage"),
|
|
116
|
+
price=entry.get("price"), egress=entry["egress"],
|
|
117
|
+
noul_threshold=noul_threshold,
|
|
118
|
+
)
|
|
119
|
+
if entry["kind"] == "decisions":
|
|
120
|
+
return DecisionsBackend(**common)
|
|
121
|
+
return HttpBackend(kind=entry["kind"], **common)
|
|
@@ -22,7 +22,7 @@ import json
|
|
|
22
22
|
from .backends import Backend
|
|
23
23
|
from .pack import validate_schema
|
|
24
24
|
from .quality import d_text
|
|
25
|
-
from .runner import ModelSpec, preflight, run_pack
|
|
25
|
+
from .runner import ModelSpec, parse_models, preflight, run_pack
|
|
26
26
|
|
|
27
27
|
DISCRIMINATION_MIN_SPREAD = 0.05 # min stdev of mean_distance across reference models
|
|
28
28
|
# Conservative: text prompts and their expected answers naturally share topical
|
|
@@ -199,13 +199,48 @@ CALIBRATION_NOTICE = (
|
|
|
199
199
|
)
|
|
200
200
|
|
|
201
201
|
|
|
202
|
-
def
|
|
202
|
+
def _calibration_spec(model: str, pack: dict, registry: Optional[dict]):
|
|
203
|
+
"""One spec from the same grammar ``--models`` uses.
|
|
204
|
+
|
|
205
|
+
``provider:<name>`` is not runnable until its registry arm is attached.
|
|
206
|
+
A bare id stays on the metered default, which is what ``parse_models``
|
|
207
|
+
already does — this does not reimplement that split.
|
|
208
|
+
"""
|
|
209
|
+
from .providers import RegistryError, load_registry, provider_arm, registry_path
|
|
210
|
+
|
|
211
|
+
specs = parse_models(model)
|
|
212
|
+
if len(specs) != 1:
|
|
213
|
+
return None
|
|
214
|
+
spec = specs[0]
|
|
215
|
+
if spec.backend != "provider":
|
|
216
|
+
return spec
|
|
217
|
+
try:
|
|
218
|
+
if registry is None:
|
|
219
|
+
registry = load_registry(registry_path())
|
|
220
|
+
except (OSError, RegistryError) as exc:
|
|
221
|
+
raise RegistryError(str(exc)) from exc
|
|
222
|
+
entry = (registry or {}).get(spec.provider)
|
|
223
|
+
if entry is not None:
|
|
224
|
+
spec.arm = provider_arm(spec.provider, entry, pack.get("noul_threshold"))
|
|
225
|
+
return spec
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def gate_calibration(
|
|
229
|
+
pack: dict,
|
|
230
|
+
backends: Optional[dict[str, Backend]] = None,
|
|
231
|
+
*,
|
|
232
|
+
registry: Optional[dict] = None,
|
|
233
|
+
) -> list[str]:
|
|
203
234
|
"""ALWAYS emits the context-calibration requirement as a warning (§5d is
|
|
204
235
|
guidance, not automatable in full). If the pack declares
|
|
205
236
|
``meta.calibration`` ({model, task_ids, expected_mean_distance_max}),
|
|
206
237
|
additionally checks that the declared model+system reproduces it — full
|
|
207
238
|
standardization of this format is DEFERRED (decision #4); this is the
|
|
208
|
-
minimal v1 check.
|
|
239
|
+
minimal v1 check.
|
|
240
|
+
|
|
241
|
+
``meta.calibration.model`` is one ``parse_models`` token: ``id[:backend[:label]]``
|
|
242
|
+
or ``provider:<name>``. A bare id keeps the metered backend.
|
|
243
|
+
"""
|
|
209
244
|
warnings = [CALIBRATION_NOTICE]
|
|
210
245
|
calib = (pack.get("meta") or {}).get("calibration")
|
|
211
246
|
if not calib:
|
|
@@ -214,7 +249,7 @@ def gate_calibration(pack: dict, backends: Optional[dict[str, Backend]] = None)
|
|
|
214
249
|
model = calib.get("model")
|
|
215
250
|
task_ids = calib.get("task_ids")
|
|
216
251
|
expected_max = calib.get("expected_mean_distance_max")
|
|
217
|
-
if not (model and task_ids and expected_max is not None):
|
|
252
|
+
if not (isinstance(model, str) and model.strip() and task_ids and expected_max is not None):
|
|
218
253
|
warnings.append(
|
|
219
254
|
"meta.calibration is present but malformed (need model, task_ids, "
|
|
220
255
|
"expected_mean_distance_max) — skipping the reproduction check"
|
|
@@ -229,10 +264,26 @@ def gate_calibration(pack: dict, backends: Optional[dict[str, Backend]] = None)
|
|
|
229
264
|
)
|
|
230
265
|
return warnings
|
|
231
266
|
|
|
232
|
-
|
|
267
|
+
from .providers import RegistryError
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
spec = _calibration_spec(model, pack, registry)
|
|
271
|
+
except RegistryError as exc:
|
|
272
|
+
warnings.append(f"meta.calibration provider registry unreadable: {exc}")
|
|
273
|
+
return warnings
|
|
274
|
+
if spec is None:
|
|
275
|
+
warnings.append(
|
|
276
|
+
f"meta.calibration model={model!r} must be one model spec "
|
|
277
|
+
f"(id[:backend[:label]] or provider:<name>) — skipping the reproduction check"
|
|
278
|
+
)
|
|
279
|
+
return warnings
|
|
280
|
+
|
|
281
|
+
runnable, preflight_warnings = preflight([spec], backends, pack=pack)
|
|
233
282
|
warnings.extend(preflight_warnings)
|
|
234
283
|
if not runnable:
|
|
235
|
-
|
|
284
|
+
# The preflight warning already names the refusal (credentials, kind
|
|
285
|
+
# mismatch, on_box_only egress). A second "lacks credentials" line
|
|
286
|
+
# mislabels every other refusal as a missing key.
|
|
236
287
|
return warnings
|
|
237
288
|
|
|
238
289
|
result = run_pack(runnable, pack, backends, task_ids=task_ids)
|
|
@@ -32,7 +32,6 @@ from swarph_cli.bench.backends import (
|
|
|
32
32
|
SubscriptionBackend,
|
|
33
33
|
TypedHttpBackend,
|
|
34
34
|
HttpBackend,
|
|
35
|
-
DecisionsBackend,
|
|
36
35
|
)
|
|
37
36
|
from swarph_cli.bench.pack import PackError, load_pack, slugify_theme, validate_schema
|
|
38
37
|
from swarph_cli.bench.providers import RegistryError, load_registry, registry_path
|
|
@@ -223,21 +222,9 @@ def _default_packs_dir() -> Path:
|
|
|
223
222
|
|
|
224
223
|
|
|
225
224
|
def _provider_arm(name: str, entry: dict, noul_threshold):
|
|
226
|
-
"""The registry arm for ``provider:<name>``.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
``semantic`` stay on :class:`HttpBackend`, which posts a typed pack body
|
|
230
|
-
unchanged.
|
|
231
|
-
"""
|
|
232
|
-
common = dict(
|
|
233
|
-
name=name, base_url=entry["base_url"], path=entry["path"],
|
|
234
|
-
auth=entry.get("auth"), usage=entry.get("usage"),
|
|
235
|
-
price=entry.get("price"), egress=entry["egress"],
|
|
236
|
-
noul_threshold=noul_threshold,
|
|
237
|
-
)
|
|
238
|
-
if entry["kind"] == "decisions":
|
|
239
|
-
return DecisionsBackend(**common)
|
|
240
|
-
return HttpBackend(kind=entry["kind"], **common)
|
|
225
|
+
"""The registry arm for ``provider:<name>``. Same constructor validate uses."""
|
|
226
|
+
from swarph_cli.bench.providers import provider_arm
|
|
227
|
+
return provider_arm(name, entry, noul_threshold)
|
|
241
228
|
|
|
242
229
|
|
|
243
230
|
# ── dispatch ───────────────────────────────────────────────────────────────
|
|
@@ -14,6 +14,7 @@ from pathlib import Path
|
|
|
14
14
|
from typing import Iterable
|
|
15
15
|
|
|
16
16
|
GAP_SECONDS = 60
|
|
17
|
+
WAIT_REARM_GRACE = 600
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
def writer_verdict(*, reader_alive: bool, monitor_rc: int) -> str:
|
|
@@ -132,16 +133,33 @@ def _channel_alive(inbox: str, now: float | None = None) -> bool:
|
|
|
132
133
|
return (time.time() if now is None else now) - ts < 180
|
|
133
134
|
|
|
134
135
|
|
|
136
|
+
def _waiter_just_delivered(inbox: str, now: float | None = None) -> bool:
|
|
137
|
+
"""`swarph mesh wait --once` writes wait_cursor.json beside the inbox when it
|
|
138
|
+
delivers, then exits. The cell re-arms only after acting on the DM, which can
|
|
139
|
+
take minutes; inside that window no waiter is running but the wake is not dead.
|
|
140
|
+
"""
|
|
141
|
+
try:
|
|
142
|
+
mtime = (Path(inbox).parent / "wait_cursor.json").stat().st_mtime
|
|
143
|
+
except OSError:
|
|
144
|
+
return False
|
|
145
|
+
age = (time.time() if now is None else now) - mtime
|
|
146
|
+
return 0 <= age < WAIT_REARM_GRACE # a future mtime is not a delivery
|
|
147
|
+
|
|
148
|
+
|
|
135
149
|
def _watching(inbox: str, cmdlines: Iterable[str]) -> bool:
|
|
136
150
|
"""A reader is tail or dm_notify_filter with the inbox path as its own argument,
|
|
137
|
-
|
|
151
|
+
a channel server whose heartbeat is fresh, or a one-shot `swarph mesh wait`
|
|
152
|
+
for this cell (running, or delivered within WAIT_REARM_GRACE).
|
|
138
153
|
|
|
139
154
|
A process that merely mentions the path (a prompt, a log line) is not a reader.
|
|
140
155
|
"""
|
|
141
|
-
if _channel_alive(inbox):
|
|
156
|
+
if _channel_alive(inbox) or _waiter_just_delivered(inbox):
|
|
142
157
|
return True
|
|
158
|
+
cell = Path(inbox).parent.parent.name
|
|
143
159
|
for cmd in cmdlines:
|
|
144
160
|
parts = cmd.split()
|
|
161
|
+
if _waits_on(parts, cell):
|
|
162
|
+
return True
|
|
145
163
|
if inbox not in parts:
|
|
146
164
|
continue
|
|
147
165
|
if any(os.path.basename(p) == "tail" for p in parts):
|
|
@@ -151,6 +169,27 @@ def _watching(inbox: str, cmdlines: Iterable[str]) -> bool:
|
|
|
151
169
|
return False
|
|
152
170
|
|
|
153
171
|
|
|
172
|
+
def _waits_on(parts: list[str], cell: str) -> bool:
|
|
173
|
+
"""`swarph mesh wait --once --as <cell>` names the cell, not the inbox path.
|
|
174
|
+
|
|
175
|
+
copilot wakes on this waiter's exit (card #387). The process must BE swarph
|
|
176
|
+
(argv[0], or argv[1] after an interpreter), so a prompt that quotes the
|
|
177
|
+
command is not a reader.
|
|
178
|
+
"""
|
|
179
|
+
for i in (0, 1):
|
|
180
|
+
if len(parts) < i + 3 or os.path.basename(parts[i]) != "swarph":
|
|
181
|
+
continue
|
|
182
|
+
if i == 1 and not os.path.basename(parts[0]).startswith("python"):
|
|
183
|
+
continue
|
|
184
|
+
if parts[i + 1:i + 3] != ["mesh", "wait"]:
|
|
185
|
+
continue
|
|
186
|
+
rest = parts[i + 3:]
|
|
187
|
+
named = f"--as={cell}" in rest or any(
|
|
188
|
+
a == "--as" and b == cell for a, b in zip(rest, rest[1:]))
|
|
189
|
+
return "--once" in rest and named
|
|
190
|
+
return False
|
|
191
|
+
|
|
192
|
+
|
|
154
193
|
def _cron_watched(name: str, crontab: str) -> bool:
|
|
155
194
|
"""An active crontab line that runs dm_wake.py for this cell is its poller."""
|
|
156
195
|
for line in crontab.splitlines():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.20
|
|
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
|
|
@@ -240,3 +240,54 @@ def test_a_channel_cell_with_a_fresh_heartbeat_is_watched(tmp_path):
|
|
|
240
240
|
hb.write_text(json.dumps({"pid": 1, "ts": _t.time() - 600})) # server died 10 min ago
|
|
241
241
|
assert scan(cells, channel_ps, state, now=130) == []
|
|
242
242
|
assert scan(cells, channel_ps, state, now=200) == ["drop"]
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def test_a_one_shot_mesh_wait_for_the_cell_is_a_watcher(tmp_path):
|
|
246
|
+
"""Live 2026-10-12 23:34Z: copilot wakes on `swarph mesh wait --once` exiting (card #387,
|
|
247
|
+
probe 69717), and that command line names the cell, not the inbox path, so the watchdog
|
|
248
|
+
paged copilot 'DM wake is dead' (msgs 69720/69721). Fails on main.
|
|
249
|
+
tmp_path, not the live path: a live wait_cursor.json would count as watched."""
|
|
250
|
+
inbox = str(tmp_path / "copilot" / "mesh-sidecar" / "inbox.log")
|
|
251
|
+
cells = {"copilot": inbox}
|
|
252
|
+
waiter = ["/usr/bin/python3 /home/ubuntu/.local/bin/swarph mesh wait --once --as copilot --max-wait-s 1500"]
|
|
253
|
+
state = {}
|
|
254
|
+
assert scan(cells, waiter, state, now=0) == []
|
|
255
|
+
assert scan(cells, waiter, state, now=120) == []
|
|
256
|
+
assert scan(cells, ["swarph mesh wait --once --as=copilot"], {}, now=120) == []
|
|
257
|
+
other = ["/usr/bin/python3 /home/ubuntu/.local/bin/swarph mesh wait --once --as lab-ovh"]
|
|
258
|
+
quoted = ["claude -p run swarph mesh wait --once --as copilot then reply"]
|
|
259
|
+
no_once = ["/home/ubuntu/.local/bin/swarph mesh wait --as copilot"]
|
|
260
|
+
# drop-on-meta-edge #1682: argv[1] counted without checking argv[0] is an interpreter.
|
|
261
|
+
echo = ["echo swarph mesh wait --once --as copilot"]
|
|
262
|
+
grep = ["grep swarph mesh wait --once --as copilot notes.txt"]
|
|
263
|
+
claude = ["claude swarph mesh wait --once --as copilot and report"]
|
|
264
|
+
for listing in (other, quoted, no_once, echo, grep, claude):
|
|
265
|
+
st = {}
|
|
266
|
+
assert scan(cells, listing, st, now=0) == []
|
|
267
|
+
assert scan(cells, listing, st, now=120) == ["copilot"], listing
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def test_the_re_arm_gap_after_a_one_shot_delivery_is_not_an_outage(tmp_path):
|
|
271
|
+
"""The waiter exits on delivery and copilot re-arms only after acting on the DM;
|
|
272
|
+
a turn longer than GAP_SECONDS paged copilot under the waiter-only fix. A cursor
|
|
273
|
+
written 30 s ago covers the gap; one written 700 s ago does not."""
|
|
274
|
+
import os, time
|
|
275
|
+
inbox = tmp_path / "copilot" / "mesh-sidecar" / "inbox.log"
|
|
276
|
+
inbox.parent.mkdir(parents=True)
|
|
277
|
+
inbox.write_text("")
|
|
278
|
+
cursor = inbox.parent / "wait_cursor.json"
|
|
279
|
+
cursor.write_text('{"last_delivered_id": 69717}')
|
|
280
|
+
cells = {"copilot": str(inbox)}
|
|
281
|
+
t = time.time()
|
|
282
|
+
os.utime(cursor, (t - 30, t - 30))
|
|
283
|
+
st = {}
|
|
284
|
+
assert scan(cells, [], st, now=0) == []
|
|
285
|
+
assert scan(cells, [], st, now=120) == []
|
|
286
|
+
os.utime(cursor, (t - 700, t - 700))
|
|
287
|
+
st = {}
|
|
288
|
+
assert scan(cells, [], st, now=0) == []
|
|
289
|
+
assert scan(cells, [], st, now=120) == ["copilot"]
|
|
290
|
+
os.utime(cursor, (t + 3600, t + 3600)) # #1682: a future mtime hid the outage unboundedly
|
|
291
|
+
st = {}
|
|
292
|
+
assert scan(cells, [], st, now=0) == []
|
|
293
|
+
assert scan(cells, [], st, now=120) == ["copilot"]
|
|
@@ -294,7 +294,147 @@ def test_calibration_missing_creds_flagged_gracefully():
|
|
|
294
294
|
return ["SOME_KEY"]
|
|
295
295
|
|
|
296
296
|
warnings = gate_calibration(p, backends={"metered": NoCreds()})
|
|
297
|
-
assert any("
|
|
297
|
+
assert any("requires SOME_KEY" in w and "skipped" in w for w in warnings)
|
|
298
|
+
assert not any("lacks credentials" in w for w in warnings)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
class _Recording:
|
|
302
|
+
def __init__(self, inner):
|
|
303
|
+
self.inner = inner
|
|
304
|
+
self.calls = []
|
|
305
|
+
|
|
306
|
+
def generate(self, model_id, prompt, system=""):
|
|
307
|
+
self.calls.append(model_id)
|
|
308
|
+
return self.inner.generate(model_id, prompt, system)
|
|
309
|
+
|
|
310
|
+
def missing_creds(self):
|
|
311
|
+
return []
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def test_calibration_subscription_backend_is_called():
|
|
315
|
+
p = _pack(meta={"calibration": {
|
|
316
|
+
"model": "m:subscription",
|
|
317
|
+
"task_ids": ["arith_mult"],
|
|
318
|
+
"expected_mean_distance_max": 0.1,
|
|
319
|
+
}})
|
|
320
|
+
subscription = _Recording(ScriptedBackend(PERFECT_ANSWERS))
|
|
321
|
+
metered = _Recording(ScriptedBackend({}))
|
|
322
|
+
warnings = gate_calibration(p, backends={"subscription": subscription, "metered": metered})
|
|
323
|
+
assert subscription.calls == ["m"]
|
|
324
|
+
assert metered.calls == []
|
|
325
|
+
assert any("meta.calibration OK" in w or "MISMATCH" in w for w in warnings)
|
|
326
|
+
assert not any("could not run" in w for w in warnings)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def test_calibration_bare_id_binds_metered_backend():
|
|
330
|
+
p = _pack(meta={"calibration": {
|
|
331
|
+
"model": "bare-id",
|
|
332
|
+
"task_ids": ["arith_mult"],
|
|
333
|
+
"expected_mean_distance_max": 0.1,
|
|
334
|
+
}})
|
|
335
|
+
subscription = _Recording(ScriptedBackend(PERFECT_ANSWERS))
|
|
336
|
+
metered = _Recording(ScriptedBackend(PERFECT_ANSWERS))
|
|
337
|
+
warnings = gate_calibration(p, backends={"subscription": subscription, "metered": metered})
|
|
338
|
+
assert metered.calls == ["bare-id"]
|
|
339
|
+
assert subscription.calls == []
|
|
340
|
+
assert any("meta.calibration OK" in w for w in warnings)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def test_calibration_provider_resolves_registry_arm(monkeypatch):
|
|
344
|
+
from swarph_cli.bench import providers as providers_mod
|
|
345
|
+
from swarph_cli.bench.backends import HttpBackend
|
|
346
|
+
|
|
347
|
+
built = []
|
|
348
|
+
seen = []
|
|
349
|
+
real = providers_mod.provider_arm
|
|
350
|
+
|
|
351
|
+
def wrapped(name, entry, noul):
|
|
352
|
+
arm = real(name, entry, noul)
|
|
353
|
+
built.append((name, entry, arm))
|
|
354
|
+
inner = ScriptedBackend(PERFECT_ANSWERS)
|
|
355
|
+
|
|
356
|
+
def generate(model_id, prompt, system=""):
|
|
357
|
+
seen.append(model_id)
|
|
358
|
+
return inner.generate(model_id, prompt, system)
|
|
359
|
+
|
|
360
|
+
arm.generate = generate
|
|
361
|
+
return arm
|
|
362
|
+
|
|
363
|
+
monkeypatch.setattr(providers_mod, "provider_arm", wrapped)
|
|
364
|
+
entry = {
|
|
365
|
+
"kind": "typed",
|
|
366
|
+
"base_url": "http://127.0.0.1:9",
|
|
367
|
+
"path": "/v1/systemone",
|
|
368
|
+
"egress": "local",
|
|
369
|
+
}
|
|
370
|
+
p = _pack(meta={"calibration": {
|
|
371
|
+
"model": "provider:openai",
|
|
372
|
+
"task_ids": ["arith_mult"],
|
|
373
|
+
"expected_mean_distance_max": 0.1,
|
|
374
|
+
}})
|
|
375
|
+
metered = _Recording(ScriptedBackend(PERFECT_ANSWERS))
|
|
376
|
+
warnings = gate_calibration(
|
|
377
|
+
p, backends={"metered": metered}, registry={"openai": entry},
|
|
378
|
+
)
|
|
379
|
+
assert built and built[0][0] == "openai" and built[0][1] is entry
|
|
380
|
+
assert isinstance(built[0][2], HttpBackend)
|
|
381
|
+
assert seen == ["openai"]
|
|
382
|
+
assert metered.calls == []
|
|
383
|
+
assert any("meta.calibration OK" in w or "MISMATCH" in w for w in warnings)
|
|
384
|
+
assert not any("could not run" in w for w in warnings)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def test_calibration_on_box_only_refuses_external_provider(monkeypatch):
|
|
388
|
+
from swarph_cli.bench import providers as providers_mod
|
|
389
|
+
|
|
390
|
+
calls = []
|
|
391
|
+
real = providers_mod.provider_arm
|
|
392
|
+
|
|
393
|
+
def wrapped(name, entry, noul):
|
|
394
|
+
arm = real(name, entry, noul)
|
|
395
|
+
|
|
396
|
+
def generate(model_id, prompt, system=""):
|
|
397
|
+
calls.append(model_id)
|
|
398
|
+
raise AssertionError("external arm must not be dispatched")
|
|
399
|
+
|
|
400
|
+
arm.generate = generate
|
|
401
|
+
return arm
|
|
402
|
+
|
|
403
|
+
monkeypatch.setattr(providers_mod, "provider_arm", wrapped)
|
|
404
|
+
entry = {
|
|
405
|
+
"kind": "typed",
|
|
406
|
+
"base_url": "https://api.example.com",
|
|
407
|
+
"path": "/v1/systemone",
|
|
408
|
+
"egress": "external",
|
|
409
|
+
}
|
|
410
|
+
p = _pack(
|
|
411
|
+
egress="on_box_only",
|
|
412
|
+
meta={"calibration": {
|
|
413
|
+
"model": "provider:openai",
|
|
414
|
+
"task_ids": ["arith_mult"],
|
|
415
|
+
"expected_mean_distance_max": 0.1,
|
|
416
|
+
}},
|
|
417
|
+
)
|
|
418
|
+
warnings = gate_calibration(p, backends={}, registry={"openai": entry})
|
|
419
|
+
assert calls == []
|
|
420
|
+
assert any("on_box_only" in w and "external" in w for w in warnings)
|
|
421
|
+
assert not any("lacks credentials" in w for w in warnings)
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def test_calibration_kind_mismatch_refuses_the_arm():
|
|
425
|
+
p = _pack(
|
|
426
|
+
request_kind="typed",
|
|
427
|
+
meta={"calibration": {
|
|
428
|
+
"model": "m:subscription",
|
|
429
|
+
"task_ids": ["arith_mult"],
|
|
430
|
+
"expected_mean_distance_max": 0.1,
|
|
431
|
+
}},
|
|
432
|
+
)
|
|
433
|
+
subscription = _Recording(ScriptedBackend(PERFECT_ANSWERS))
|
|
434
|
+
warnings = gate_calibration(p, backends={"subscription": subscription})
|
|
435
|
+
assert subscription.calls == []
|
|
436
|
+
assert any("kind mismatch: pack=typed arm=semantic" in w for w in warnings)
|
|
437
|
+
assert not any("lacks credentials" in w for w in warnings)
|
|
298
438
|
|
|
299
439
|
|
|
300
440
|
# ── orchestration: validate_pack ───────────────────────────────────────────
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_opencode_plugin.py
RENAMED
|
File without changes
|
{swarph_cli-0.72.18 → swarph_cli-0.72.20}/src/swarph_cli/commands/install_postcompact_hook.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|