swarph-cli 0.72.8__tar.gz → 0.72.9__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.8/src/swarph_cli.egg-info → swarph_cli-0.72.9}/PKG-INFO +1 -1
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/pyproject.toml +1 -1
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/__init__.py +1 -1
- swarph_cli-0.72.9/src/swarph_cli/commands/roster.py +237 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/guide/GUIDE.md +1 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/main.py +1 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/rowclear.py +65 -4
- {swarph_cli-0.72.8 → swarph_cli-0.72.9/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli.egg-info/SOURCES.txt +2 -0
- swarph_cli-0.72.9/tests/test_1061_roster_cli.py +137 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_432_rowclear.py +165 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_sidecar.py +40 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/LICENSE +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/README.md +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/setup.cfg +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/codex_cli.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/providers.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/signal_score.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/mesh.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/rowclear_hook.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/__init__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/__main__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/api.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/cli.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/config.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/operator/fmt.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1006_board_publisher.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1006_session_board.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1010_strand_only.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1013_spawn_channel.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1017_muse_tui.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1050_surrogate_wake.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1052_opencode_deaf.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_1059_watchdog_unread_env.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_484_codex_queue_sink.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_538_signal_bench.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_729_arm_check_delivery_gap.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_735_dm_mcp_tools.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_739_wake_writer.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_961_cursor_grok_footer.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_961_loud_stop.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_codex_cli.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_board_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_group_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_import_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_init_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_main.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_sidecar_muse_sink.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_operator_me.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_security.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_service_app.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_service_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_version_command.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.72.8 → swarph_cli-0.72.9}/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.9
|
|
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.9"
|
|
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" }
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""``swarph roster`` — read/write the gateway's operator-maintained capacity table.
|
|
2
|
+
|
|
3
|
+
card #1061 (ROSTER AS DATA): the roster replaces tribal knowledge about who
|
|
4
|
+
builds, who reviews, on which model/effort, under which quota, and who is out
|
|
5
|
+
until when. Reads hit GET /roster (any authenticated caller); writes hit
|
|
6
|
+
PUT /roster/{peer} (operators only — the gateway 403s the rest).
|
|
7
|
+
|
|
8
|
+
swarph roster [--peer PEER] [--json] list the table (or one row)
|
|
9
|
+
swarph roster set PEER [--model M] [--effort E] [--roles r1,r2]
|
|
10
|
+
[--quota-pool P] [--quota-used PCT --quota-as-of TS] [--resets DATE]
|
|
11
|
+
[--until TS | --clear-until] [--note TEXT]
|
|
12
|
+
|
|
13
|
+
A quota VALUE without its as_of coordinate is a rumour: --quota-used /
|
|
14
|
+
--resets without --quota-as-of are refused client-side (exit 2) before the
|
|
15
|
+
gateway's own 400. The pool NAME needs no coordinate (identifier, not a
|
|
16
|
+
measurement). --clear-until is the grok-returns flow (explicit null clears).
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import json
|
|
22
|
+
import sys
|
|
23
|
+
import urllib.error
|
|
24
|
+
import urllib.request
|
|
25
|
+
|
|
26
|
+
# card #1061 role vocabulary — mirrors the gateway's _ROSTER_ROLES. A role
|
|
27
|
+
# the gateway does not know is refused here (exit 2) before its 400; when the
|
|
28
|
+
# vocabulary grows, BOTH pins change together (gateway tests + test_1061 below).
|
|
29
|
+
ROSTER_ROLES = ("build", "validate", "plan-review", "orchestrate")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _http_get_json(url, token, *, timeout=10.0):
|
|
33
|
+
from swarph_cli.commands.mesh import _http_get_json as _get
|
|
34
|
+
return _get(url, token, timeout=timeout)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _http_put_json(url, body, token, *, timeout=10.0):
|
|
38
|
+
from swarph_cli.commands.mesh import _require_absolute_gateway_url
|
|
39
|
+
_require_absolute_gateway_url(url)
|
|
40
|
+
data = json.dumps(body).encode("utf-8")
|
|
41
|
+
req = urllib.request.Request(
|
|
42
|
+
url, data=data, method="PUT",
|
|
43
|
+
headers={"Authorization": f"Bearer {token}",
|
|
44
|
+
"Content-Type": "application/json"})
|
|
45
|
+
try:
|
|
46
|
+
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
|
47
|
+
return resp.status, json.loads(resp.read().decode("utf-8") or "{}")
|
|
48
|
+
except urllib.error.HTTPError as exc:
|
|
49
|
+
try:
|
|
50
|
+
err_body = json.loads(exc.read().decode("utf-8") or "{}")
|
|
51
|
+
except Exception:
|
|
52
|
+
err_body = {"detail": str(exc)}
|
|
53
|
+
return exc.code, err_body
|
|
54
|
+
except urllib.error.URLError as exc:
|
|
55
|
+
return 0, {"detail": str(exc)}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _resolve(args):
|
|
59
|
+
from swarph_cli.tokens import resolve_token
|
|
60
|
+
resolution = resolve_token(args.self_name, args.token_file,
|
|
61
|
+
identity_is_explicit=bool(args.self_name))
|
|
62
|
+
if resolution is None:
|
|
63
|
+
print("swarph roster: no token (set MESH_GATEWAY_TOKEN, pass "
|
|
64
|
+
"--token-file, or --as a peer with a stored token)",
|
|
65
|
+
file=sys.stderr)
|
|
66
|
+
return None
|
|
67
|
+
return resolution.token
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _quota_compact(r):
|
|
71
|
+
if r.get("quota_used_pct") is None and not r.get("quota_pool"):
|
|
72
|
+
return "-"
|
|
73
|
+
parts = []
|
|
74
|
+
if r.get("quota_pool"):
|
|
75
|
+
parts.append(str(r["quota_pool"]))
|
|
76
|
+
if r.get("quota_used_pct") is not None:
|
|
77
|
+
parts.append(f"{r['quota_used_pct']}%")
|
|
78
|
+
if r.get("quota_as_of"):
|
|
79
|
+
parts.append(f"@{r['quota_as_of']}")
|
|
80
|
+
if r.get("quota_resets_at"):
|
|
81
|
+
parts.append(f"(resets {r['quota_resets_at']})")
|
|
82
|
+
return " ".join(parts)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _line(r):
|
|
86
|
+
roles = ",".join(r["roles"]) if r.get("roles") else "-"
|
|
87
|
+
bits = [r["peer"],
|
|
88
|
+
f"model={r.get('model') or '-'}",
|
|
89
|
+
f"effort={r.get('effort') or '-'}",
|
|
90
|
+
f"roles={roles}",
|
|
91
|
+
f"quota={_quota_compact(r)}"]
|
|
92
|
+
if r.get("unavailable_until"):
|
|
93
|
+
bits.append(f"out-until={r['unavailable_until']}")
|
|
94
|
+
bits.append(f"updated_by={r.get('updated_by') or '?'}")
|
|
95
|
+
return " ".join(bits)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _run_list(args):
|
|
99
|
+
token = _resolve(args)
|
|
100
|
+
if token is None:
|
|
101
|
+
return 2
|
|
102
|
+
gateway = args.gateway.rstrip("/")
|
|
103
|
+
status, payload = _http_get_json(f"{gateway}/roster", token)
|
|
104
|
+
if status < 200 or status >= 300:
|
|
105
|
+
detail = payload.get("detail", "<gateway error>") if isinstance(payload, dict) else "<gateway error>"
|
|
106
|
+
print(f"swarph roster: gateway {status}: {detail}", file=sys.stderr)
|
|
107
|
+
return 1
|
|
108
|
+
rows = payload.get("roster") if isinstance(payload, dict) else None
|
|
109
|
+
if not isinstance(rows, list):
|
|
110
|
+
print("swarph roster: unexpected /roster shape (no roster list)",
|
|
111
|
+
file=sys.stderr)
|
|
112
|
+
return 1
|
|
113
|
+
if args.peer:
|
|
114
|
+
rows = [r for r in rows if isinstance(r, dict) and r.get("peer") == args.peer]
|
|
115
|
+
if not rows:
|
|
116
|
+
print(f"swarph roster: no row for {args.peer!r}", file=sys.stderr)
|
|
117
|
+
return 1
|
|
118
|
+
if args.json:
|
|
119
|
+
print(json.dumps(rows, indent=2))
|
|
120
|
+
else:
|
|
121
|
+
for r in rows:
|
|
122
|
+
print(_line(r) if isinstance(r, dict) else r)
|
|
123
|
+
return 0
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _run_set(args):
|
|
127
|
+
token = _resolve(args)
|
|
128
|
+
if token is None:
|
|
129
|
+
return 2
|
|
130
|
+
if ((args.quota_used is not None or args.resets is not None)
|
|
131
|
+
and args.quota_as_of is None):
|
|
132
|
+
print("swarph roster set: --quota-used / --resets need --quota-as-of "
|
|
133
|
+
"(a quota value without its coordinate is a rumour)",
|
|
134
|
+
file=sys.stderr)
|
|
135
|
+
return 2
|
|
136
|
+
body = {}
|
|
137
|
+
if args.model is not None:
|
|
138
|
+
body["model"] = args.model
|
|
139
|
+
if args.effort is not None:
|
|
140
|
+
body["effort"] = args.effort
|
|
141
|
+
if args.roles is not None:
|
|
142
|
+
roles = [x.strip() for x in args.roles.split(",") if x.strip()]
|
|
143
|
+
bad = [x for x in roles if x not in ROSTER_ROLES]
|
|
144
|
+
if bad:
|
|
145
|
+
print(f"swarph roster set: unknown role(s) {bad} "
|
|
146
|
+
f"(vocabulary: {', '.join(ROSTER_ROLES)})", file=sys.stderr)
|
|
147
|
+
return 2
|
|
148
|
+
body["roles"] = roles
|
|
149
|
+
if args.quota_pool is not None:
|
|
150
|
+
body["quota_pool"] = args.quota_pool
|
|
151
|
+
if args.quota_used is not None:
|
|
152
|
+
body["quota_used_pct"] = args.quota_used
|
|
153
|
+
if args.resets is not None:
|
|
154
|
+
body["quota_resets_at"] = args.resets
|
|
155
|
+
if args.quota_as_of is not None:
|
|
156
|
+
body["quota_as_of"] = args.quota_as_of
|
|
157
|
+
if args.until is not None:
|
|
158
|
+
body["unavailable_until"] = args.until
|
|
159
|
+
if args.clear_until:
|
|
160
|
+
body["unavailable_until"] = None
|
|
161
|
+
if args.note is not None:
|
|
162
|
+
body["note"] = args.note
|
|
163
|
+
if not body:
|
|
164
|
+
print("swarph roster set: nothing to set (pass a field flag)",
|
|
165
|
+
file=sys.stderr)
|
|
166
|
+
return 2
|
|
167
|
+
gateway = args.gateway.rstrip("/")
|
|
168
|
+
status, payload = _http_put_json(
|
|
169
|
+
f"{gateway}/roster/{args.peer}", body, token)
|
|
170
|
+
if status < 200 or status >= 300:
|
|
171
|
+
detail = payload.get("detail", "<gateway error>") if isinstance(payload, dict) else "<gateway error>"
|
|
172
|
+
print(f"swarph roster set: gateway {status}: {detail}", file=sys.stderr)
|
|
173
|
+
return 1
|
|
174
|
+
if args.json:
|
|
175
|
+
print(json.dumps(payload, indent=2))
|
|
176
|
+
else:
|
|
177
|
+
print(f"updated {args.peer} (updated_by={payload.get('updated_by', '?')})")
|
|
178
|
+
return 0
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _add_global(p):
|
|
182
|
+
p.add_argument("--as", dest="self_name", default=None,
|
|
183
|
+
help="peer identity for token resolution")
|
|
184
|
+
from swarph_cli.gateway_default import env_gateway
|
|
185
|
+
p.add_argument("--gateway", default=env_gateway(),
|
|
186
|
+
help="mesh-gateway base URL")
|
|
187
|
+
p.add_argument("--token-file", default=None,
|
|
188
|
+
help="explicit Bearer [REDACTED] file")
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _build_parser():
|
|
192
|
+
p = argparse.ArgumentParser(
|
|
193
|
+
prog="swarph roster",
|
|
194
|
+
description="Read/write the gateway capacity roster (card #1061).")
|
|
195
|
+
_add_global(p)
|
|
196
|
+
p.add_argument("--peer", default=None,
|
|
197
|
+
help="show only this peer (list mode)")
|
|
198
|
+
p.add_argument("--json", action="store_true",
|
|
199
|
+
help="print the raw gateway payload")
|
|
200
|
+
sub = p.add_subparsers(dest="command")
|
|
201
|
+
s = sub.add_parser("set", help="upsert one roster row (operators only)")
|
|
202
|
+
_add_global(s)
|
|
203
|
+
s.add_argument("peer", help="peer the row belongs to")
|
|
204
|
+
s.add_argument("--json", action="store_true",
|
|
205
|
+
help="print the raw gateway payload")
|
|
206
|
+
s.add_argument("--model", default=None)
|
|
207
|
+
s.add_argument("--effort", default=None)
|
|
208
|
+
s.add_argument("--roles", default=None,
|
|
209
|
+
help="comma-separated subset of " + ",".join(ROSTER_ROLES))
|
|
210
|
+
s.add_argument("--quota-pool", default=None)
|
|
211
|
+
s.add_argument("--quota-used", type=float, default=None,
|
|
212
|
+
help="quota_used_pct (needs --quota-as-of)")
|
|
213
|
+
s.add_argument("--quota-as-of", default=None)
|
|
214
|
+
s.add_argument("--resets", default=None,
|
|
215
|
+
help="quota_resets_at date (needs --quota-as-of)")
|
|
216
|
+
group = s.add_mutually_exclusive_group()
|
|
217
|
+
group.add_argument("--until", default=None,
|
|
218
|
+
help="unavailable_until timestamp")
|
|
219
|
+
group.add_argument("--clear-until", action="store_true",
|
|
220
|
+
help="clear unavailable_until (peer is back)")
|
|
221
|
+
s.add_argument("--note", default=None)
|
|
222
|
+
return p
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def run_roster(argv):
|
|
226
|
+
parser = _build_parser()
|
|
227
|
+
args = parser.parse_args(argv)
|
|
228
|
+
try:
|
|
229
|
+
if args.command == "set":
|
|
230
|
+
return _run_set(args)
|
|
231
|
+
if args.command is None:
|
|
232
|
+
return _run_list(args)
|
|
233
|
+
parser.error(f"unknown command: {args.command}")
|
|
234
|
+
except RuntimeError as exc:
|
|
235
|
+
print(f"swarph roster: {exc}", file=sys.stderr)
|
|
236
|
+
return 2
|
|
237
|
+
return 2
|
|
@@ -543,6 +543,7 @@ answers `--help`; hook-plumbing verbs are the callbacks hooks invoke, not comman
|
|
|
543
543
|
- `swarph protocol-handler` -- register `swarph://` as an OS URL-scheme handler.
|
|
544
544
|
- `swarph ratify` -- witness flip that admits an onboarded peer; takes the peer name and `--reason`.
|
|
545
545
|
- `swarph rights` -- RBAC rights over the gateway (companion of `swarph group`).
|
|
546
|
+
- `swarph roster` -- the gateway capacity table (card #1061): who builds, who reviews, quota, who is out until when. `swarph roster --peer <peer>`, `swarph roster set <peer> --roles build` (operators only).
|
|
546
547
|
- `swarph rowclear-hook` -- SessionStart hook (card #432): when `source` is `clear`, write the new session id into the role's `<role>.session-id` pin so the next spawn resumes the cleared session.
|
|
547
548
|
- `swarph scan` -- statically scan an artifact for dangerous patterns before publish.
|
|
548
549
|
- `swarph schedule` -- the gateway's scheduled events: create, list, get, enable, disable, delete, fire-now.
|
|
@@ -110,6 +110,7 @@ _VERB_HANDLERS: dict[str, str] = {
|
|
|
110
110
|
"board": "swarph_cli.commands.board.run_board",
|
|
111
111
|
"group": "swarph_cli.commands.group.run_group",
|
|
112
112
|
"rights": "swarph_cli.commands.group.run_rights",
|
|
113
|
+
"roster": "swarph_cli.commands.roster.run_roster",
|
|
113
114
|
"mcp-server": "swarph_cli.commands.mcp_server.run_mcp_server",
|
|
114
115
|
"compress": "swarph_cli.commands.compress.run_compress",
|
|
115
116
|
"cell": "swarph_cli.commands.cell.run_cell",
|
|
@@ -6,6 +6,10 @@ when the cell holds no live row, the pane reads idle, and no DM is owed.
|
|
|
6
6
|
type nothing), or ``live``. v1 opt-in is drop-on-meta-edge only: a cell
|
|
7
7
|
that owns a project keeps its context (design_1007 / optin_owners).
|
|
8
8
|
|
|
9
|
+
v1.1 (#1362): a taken row whose step needs are UNMET is waiting, not
|
|
10
|
+
working — it does not count as live. Needs state comes from the card's
|
|
11
|
+
step graph; anything unreadable about it fails closed (no clear).
|
|
12
|
+
|
|
9
13
|
A ``/clear`` mints a new Claude session id. The SessionStart hook with
|
|
10
14
|
``source=clear`` writes that id into the role's ``<role>.session-id``
|
|
11
15
|
pin, so the next spawn resumes the cleared session instead of the long
|
|
@@ -95,11 +99,62 @@ def _dm_owed(state) -> bool:
|
|
|
95
99
|
return False
|
|
96
100
|
|
|
97
101
|
|
|
102
|
+
def _step_needs_met(state, row: dict, http_get: Callable,
|
|
103
|
+
graphs: dict) -> Optional[bool]:
|
|
104
|
+
"""Is this open row's work actionable (True), waiting (False), or
|
|
105
|
+
unevaluable (None)?
|
|
106
|
+
|
|
107
|
+
A row with no step has no needs to unmeet (ruling_1236: still live).
|
|
108
|
+
Otherwise the card's step graph (GET /board/cards/{id}/graph) names the
|
|
109
|
+
step's needs with a satisfied flag — every need satisfied means the
|
|
110
|
+
holder can act; one unsatisfied need means the cell is between rows.
|
|
111
|
+
Anything unreadable — no card id, a failed graph fetch, a missing step
|
|
112
|
+
entry, a needs entry without a boolean satisfied flag — is None: an
|
|
113
|
+
unevaluable row must not look like an empty cell (fail closed, #1362).
|
|
114
|
+
One graph fetch per card per poll; the same http_get the board read uses.
|
|
115
|
+
"""
|
|
116
|
+
step = row.get("step")
|
|
117
|
+
if not step:
|
|
118
|
+
return True
|
|
119
|
+
card_id = row.get("card_id")
|
|
120
|
+
if not isinstance(card_id, int) or isinstance(card_id, bool):
|
|
121
|
+
return None
|
|
122
|
+
if card_id not in graphs:
|
|
123
|
+
url = f"{state.gateway}/board/cards/{card_id}/graph"
|
|
124
|
+
try:
|
|
125
|
+
status, body = http_get(url, state.token)
|
|
126
|
+
except Exception:
|
|
127
|
+
return None
|
|
128
|
+
if status != 200 or not isinstance(body, dict):
|
|
129
|
+
return None
|
|
130
|
+
steps = body.get("steps")
|
|
131
|
+
if not isinstance(steps, list):
|
|
132
|
+
return None
|
|
133
|
+
graphs[card_id] = steps
|
|
134
|
+
for entry in graphs[card_id]:
|
|
135
|
+
if isinstance(entry, dict) and entry.get("step") == step:
|
|
136
|
+
needs = entry.get("needs")
|
|
137
|
+
if not isinstance(needs, list):
|
|
138
|
+
return None
|
|
139
|
+
for need in needs:
|
|
140
|
+
if not isinstance(need, dict) or not isinstance(
|
|
141
|
+
need.get("satisfied"), bool):
|
|
142
|
+
return None
|
|
143
|
+
if not need["satisfied"]:
|
|
144
|
+
return False
|
|
145
|
+
return True
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
|
|
98
149
|
def _live_row_count(state, http_get: Callable) -> Optional[int]:
|
|
99
|
-
"""How many
|
|
150
|
+
"""How many ACTIONABLE rows this cell holds, or None if unread.
|
|
100
151
|
|
|
101
152
|
None fails closed: an unreadable board must not look like an empty
|
|
102
153
|
one, or a live row we failed to see gets a ``/clear``.
|
|
154
|
+
|
|
155
|
+
v1.1 (#1362): an open row whose step needs are unmet is waiting, not
|
|
156
|
+
working — it does not count. An open row with no step, or whose step
|
|
157
|
+
needs nothing, is still live (ruling_1236 unchanged).
|
|
103
158
|
"""
|
|
104
159
|
url = f"{state.gateway}/board/obligations?holder={state.self_name}"
|
|
105
160
|
try:
|
|
@@ -111,15 +166,21 @@ def _live_row_count(state, http_get: Callable) -> Optional[int]:
|
|
|
111
166
|
rows = body.get("obligations")
|
|
112
167
|
if not isinstance(rows, list):
|
|
113
168
|
return None
|
|
169
|
+
graphs: dict = {}
|
|
114
170
|
live = 0
|
|
115
171
|
for row in rows:
|
|
116
172
|
if not isinstance(row, dict):
|
|
117
173
|
return None
|
|
118
174
|
status = str(row.get("status") or "")
|
|
119
|
-
if status
|
|
120
|
-
|
|
121
|
-
|
|
175
|
+
if status in _FINISHED:
|
|
176
|
+
continue
|
|
177
|
+
if status != _LIVE:
|
|
122
178
|
return None
|
|
179
|
+
met = _step_needs_met(state, row, http_get, graphs)
|
|
180
|
+
if met is None:
|
|
181
|
+
return None
|
|
182
|
+
if met:
|
|
183
|
+
live += 1
|
|
123
184
|
return live
|
|
124
185
|
|
|
125
186
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.9
|
|
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
|
|
@@ -110,6 +110,7 @@ src/swarph_cli/commands/peer_reply_drain.py
|
|
|
110
110
|
src/swarph_cli/commands/postcompact_hook_output.py
|
|
111
111
|
src/swarph_cli/commands/protocol_handler.py
|
|
112
112
|
src/swarph_cli/commands/ratify.py
|
|
113
|
+
src/swarph_cli/commands/roster.py
|
|
113
114
|
src/swarph_cli/commands/rowclear_hook.py
|
|
114
115
|
src/swarph_cli/commands/schedule.py
|
|
115
116
|
src/swarph_cli/commands/security.py
|
|
@@ -196,6 +197,7 @@ tests/test_1017_muse_tui.py
|
|
|
196
197
|
tests/test_1050_surrogate_wake.py
|
|
197
198
|
tests/test_1052_opencode_deaf.py
|
|
198
199
|
tests/test_1059_watchdog_unread_env.py
|
|
200
|
+
tests/test_1061_roster_cli.py
|
|
199
201
|
tests/test_124_register_merge.py
|
|
200
202
|
tests/test_126_pending_from_complete.py
|
|
201
203
|
tests/test_132_ensure_monitor_state_dir.py
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""card #1061 — ``swarph roster`` list + set against a faked gateway transport."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from swarph_cli.commands import roster
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _env(monkeypatch):
|
|
8
|
+
monkeypatch.setenv("MESH_GATEWAY_URL", "http://gw.test:8788")
|
|
9
|
+
monkeypatch.setenv("MESH_GATEWAY_TOKEN", "tok")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _fake_get(monkeypatch, payload, status=200):
|
|
13
|
+
calls = []
|
|
14
|
+
|
|
15
|
+
def _fake(url, token, **kw):
|
|
16
|
+
calls.append((url, token))
|
|
17
|
+
return status, payload
|
|
18
|
+
|
|
19
|
+
monkeypatch.setattr(roster, "_http_get_json", _fake)
|
|
20
|
+
return calls
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _fake_put(monkeypatch, payload=None, status=200):
|
|
24
|
+
calls = []
|
|
25
|
+
|
|
26
|
+
def _fake(url, body, token, **kw):
|
|
27
|
+
calls.append((url, body, token))
|
|
28
|
+
return status, ({"peer": "p", "updated_by": "shared-token",
|
|
29
|
+
**body} if payload is None else payload)
|
|
30
|
+
|
|
31
|
+
monkeypatch.setattr(roster, "_http_put_json", _fake)
|
|
32
|
+
return calls
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
ROWS = {"roster": [
|
|
36
|
+
{"peer": "meta-muse", "model": None, "effort": "MAX", "roles": ["build"],
|
|
37
|
+
"quota_pool": None, "quota_used_pct": 4.0,
|
|
38
|
+
"quota_resets_at": None, "quota_as_of": "2026-10-07T17:00:00Z",
|
|
39
|
+
"unavailable_until": None, "note": None,
|
|
40
|
+
"updated_by": "seed #1061", "updated_at": "t"},
|
|
41
|
+
{"peer": "grok-researcher", "model": None, "effort": None, "roles": None,
|
|
42
|
+
"quota_pool": None, "quota_used_pct": None,
|
|
43
|
+
"quota_resets_at": None, "quota_as_of": None,
|
|
44
|
+
"unavailable_until": "2026-10-09T22:37:00Z", "note": None,
|
|
45
|
+
"updated_by": "seed #1061", "updated_at": "t"},
|
|
46
|
+
]}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_list_prints_one_line_per_peer(monkeypatch, capsys):
|
|
50
|
+
_env(monkeypatch)
|
|
51
|
+
_fake_get(monkeypatch, ROWS)
|
|
52
|
+
assert roster.run_roster([]) == 0
|
|
53
|
+
out = capsys.readouterr().out.splitlines()
|
|
54
|
+
assert len(out) == 2
|
|
55
|
+
assert out[0].startswith("meta-muse") and "roles=build" in out[0]
|
|
56
|
+
assert "out-until=2026-10-09T22:37:00Z" in out[1]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_list_peer_filter_and_missing(monkeypatch, capsys):
|
|
60
|
+
_env(monkeypatch)
|
|
61
|
+
_fake_get(monkeypatch, ROWS)
|
|
62
|
+
assert roster.run_roster(["--peer", "grok-researcher"]) == 0
|
|
63
|
+
assert capsys.readouterr().out.startswith("grok-researcher")
|
|
64
|
+
assert roster.run_roster(["--peer", "nobody"]) == 1
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_list_gateway_error_is_exit_1(monkeypatch, capsys):
|
|
68
|
+
_env(monkeypatch)
|
|
69
|
+
_fake_get(monkeypatch, {"detail": "nope"}, status=403)
|
|
70
|
+
assert roster.run_roster([]) == 1
|
|
71
|
+
assert "403" in capsys.readouterr().err
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_set_sends_partial_body(monkeypatch, capsys):
|
|
75
|
+
_env(monkeypatch)
|
|
76
|
+
calls = _fake_put(monkeypatch)
|
|
77
|
+
rc = roster.run_roster(["set", "grok-researcher",
|
|
78
|
+
"--until", "2026-10-09T22:37Z",
|
|
79
|
+
"--note", "quota out"])
|
|
80
|
+
assert rc == 0
|
|
81
|
+
url, body, token = calls[0]
|
|
82
|
+
assert url == "http://gw.test:8788/roster/grok-researcher"
|
|
83
|
+
assert body == {"unavailable_until": "2026-10-09T22:37Z",
|
|
84
|
+
"note": "quota out"}
|
|
85
|
+
assert token == "tok"
|
|
86
|
+
assert "shared-token" in capsys.readouterr().out
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_set_clear_until_sends_null(monkeypatch):
|
|
90
|
+
_env(monkeypatch)
|
|
91
|
+
calls = _fake_put(monkeypatch)
|
|
92
|
+
assert roster.run_roster(["set", "grok-researcher", "--clear-until"]) == 0
|
|
93
|
+
assert calls[0][1] == {"unavailable_until": None}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_set_quota_without_as_of_refused_client_side(monkeypatch, capsys):
|
|
97
|
+
_env(monkeypatch)
|
|
98
|
+
calls = _fake_put(monkeypatch)
|
|
99
|
+
assert roster.run_roster(["set", "p", "--quota-used", "70"]) == 2
|
|
100
|
+
assert roster.run_roster(["set", "p", "--resets", "2026-10-13"]) == 2
|
|
101
|
+
assert calls == [] # refused before any transport
|
|
102
|
+
assert "as-of" in capsys.readouterr().err
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_set_quota_with_as_of_sends_all_three(monkeypatch):
|
|
106
|
+
_env(monkeypatch)
|
|
107
|
+
calls = _fake_put(monkeypatch)
|
|
108
|
+
assert roster.run_roster(["set", "cursor-lin", "--quota-pool", "Cursor",
|
|
109
|
+
"--quota-used", "70",
|
|
110
|
+
"--quota-as-of", "2026-10-07T17:00:00Z",
|
|
111
|
+
"--resets", "2026-10-13"]) == 0
|
|
112
|
+
assert calls[0][1] == {"quota_pool": "Cursor", "quota_used_pct": 70.0,
|
|
113
|
+
"quota_as_of": "2026-10-07T17:00:00Z",
|
|
114
|
+
"quota_resets_at": "2026-10-13"}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_set_unknown_role_refused_client_side(monkeypatch, capsys):
|
|
118
|
+
_env(monkeypatch)
|
|
119
|
+
calls = _fake_put(monkeypatch)
|
|
120
|
+
assert roster.run_roster(["set", "p", "--roles", "build,pilot"]) == 2
|
|
121
|
+
assert calls == []
|
|
122
|
+
assert "pilot" in capsys.readouterr().err
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_set_gateway_403_names_the_gate(monkeypatch, capsys):
|
|
126
|
+
_env(monkeypatch)
|
|
127
|
+
_fake_put(monkeypatch, {"detail": "roster PUT requires an operator"},
|
|
128
|
+
status=403)
|
|
129
|
+
assert roster.run_roster(["set", "p", "--model", "M"]) == 1
|
|
130
|
+
assert "403" in capsys.readouterr().err
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def test_set_with_no_fields_is_usage_error(monkeypatch, capsys):
|
|
134
|
+
_env(monkeypatch)
|
|
135
|
+
calls = _fake_put(monkeypatch)
|
|
136
|
+
assert roster.run_roster(["set", "p"]) == 2
|
|
137
|
+
assert calls == []
|