swarph-cli 0.46.0__tar.gz → 0.48.0__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.46.0/src/swarph_cli.egg-info → swarph_cli-0.48.0}/PKG-INFO +1 -1
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/pyproject.toml +3 -2
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/brain_ask.py +7 -3
- swarph_cli-0.48.0/src/swarph_cli/commands/gateway.py +278 -0
- swarph_cli-0.48.0/src/swarph_cli/commands/install_postcompact_hook.py +528 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/install_wake_hook.py +57 -6
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/mesh.py +218 -25
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/onboard.py +154 -5
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/spawn.py +50 -4
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/watchdog.py +8 -1
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/gateway/schema.sql +3 -1
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/main.py +1 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/_shim.cmd +7 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +12 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +5 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +19 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +9 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +19 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +19 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +22 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/precompact-flag.sh +10 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +20 -0
- swarph_cli-0.48.0/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +23 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/codex-waker.default +4 -1
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/peer-reply-drain.default +4 -1
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/tokens.py +22 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli.egg-info/SOURCES.txt +15 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_467b_onboard_operator_credential.py +42 -0
- swarph_cli-0.48.0/tests/test_548_gateway_remainder.py +82 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_brain_ask_command.py +5 -2
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_cursor_membrane.py +43 -2
- swarph_cli-0.48.0/tests/test_gateway_command.py +226 -0
- swarph_cli-0.48.0/tests/test_install_postcompact_hook.py +532 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_install_wake_hook.py +56 -2
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_mesh_sidecar.py +9 -2
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_monitor_state_split.py +57 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_onboard_command.py +192 -0
- swarph_cli-0.48.0/tests/test_tmux_wake_submit_verify.py +272 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_watchdog_model_rung.py +22 -0
- swarph_cli-0.46.0/src/swarph_cli/commands/gateway.py +0 -116
- swarph_cli-0.46.0/tests/test_gateway_command.py +0 -92
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/LICENSE +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/README.md +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/setup.cfg +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/guide/GUIDE.md +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_board_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_group_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_import_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_init_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_main.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_security.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_service_app.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_service_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.46.0 → swarph_cli-0.48.0}/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.
|
|
3
|
+
Version: 0.48.0
|
|
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.
|
|
7
|
+
version = "0.48.0"
|
|
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" }
|
|
@@ -120,7 +120,8 @@ where = ["src"]
|
|
|
120
120
|
# importlib.resources, so an undeclared GUIDE.md passes every test in the
|
|
121
121
|
# tree and fails on every installed wheel -- the 0.39.3 bug above, again.
|
|
122
122
|
swarph_cli = ["systemd/*.service", "systemd/*.timer", "systemd/*.default",
|
|
123
|
-
"scripts/*.sh", "scripts/*.ps1", "guide/*.md"
|
|
123
|
+
"scripts/*.sh", "scripts/*.ps1", "guide/*.md",
|
|
124
|
+
"payloads/postcompact/*.sh", "payloads/postcompact/*.cmd"]
|
|
124
125
|
# v0.15: ship the bundled mesh-gateway schema so `swarph gateway serve`
|
|
125
126
|
# can apply it at startup via MESH_SCHEMA_PATH (defaults next to server.py).
|
|
126
127
|
"swarph_cli.gateway" = ["*.sql"]
|
|
@@ -10,7 +10,8 @@ verb so any cell can search the swarm's shared memory the same way. Two modes:
|
|
|
10
10
|
Stdlib-only. Config from the environment, mirroring ``swarph mesh``'s token model:
|
|
11
11
|
|
|
12
12
|
GBRAIN_MCP_URL gbrain MCP endpoint; falls back to SWARPH_BRAIN_MCP, else
|
|
13
|
-
/ SWARPH_BRAIN_MCP http://
|
|
13
|
+
/ SWARPH_BRAIN_MCP http://100.107.222.72:8792/mcp (tailnet IP — gbrain
|
|
14
|
+
binds no loopback; measured 2026-08-23, card #548)
|
|
14
15
|
GBRAIN_TOKEN read token; falls back to SWARPH_BRAIN_TOKEN, then to the
|
|
15
16
|
/ SWARPH_BRAIN_TOKEN mesh per-peer token (~/.config/swarph/<self>.peer_token).
|
|
16
17
|
/ peer-token file Once gbrain accepts mesh peer tokens, the peer token IS
|
|
@@ -34,12 +35,15 @@ from swarph_cli import tokens
|
|
|
34
35
|
from pathlib import Path
|
|
35
36
|
from typing import Optional
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
# TAILNET IP, NOT loopback (card #548): measured 2026-08-23, gbrain binds
|
|
39
|
+
# 100.107.222.72:8792 ONLY — 127.0.0.1:8792 refuses on the gateway box itself.
|
|
40
|
+
# A loopback default is deaf everywhere, including on the box running gbrain.
|
|
41
|
+
_DEFAULT_GBRAIN = "http://100.107.222.72:8792/mcp"
|
|
38
42
|
_DEFAULT_TOPK = 6
|
|
39
43
|
|
|
40
44
|
|
|
41
45
|
def _resolve_endpoint() -> str:
|
|
42
|
-
"""Endpoint precedence: GBRAIN_MCP_URL > SWARPH_BRAIN_MCP >
|
|
46
|
+
"""Endpoint precedence: GBRAIN_MCP_URL > SWARPH_BRAIN_MCP > tailnet default.
|
|
43
47
|
|
|
44
48
|
The SWARPH_BRAIN_MCP fallback keeps the verb config-compatible with the
|
|
45
49
|
standalone ``swarph-brain-ask`` script (which reads SWARPH_BRAIN_*), so one
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"""``swarph gateway`` — run the bundled mesh-gateway server.
|
|
2
|
+
|
|
3
|
+
The mesh-gateway is the coordination/DM server behind the swarph mesh:
|
|
4
|
+
peer registry, DM inbox/outbox, feature aggregation + allowlist/caps,
|
|
5
|
+
and lane/service control. It used to live as a standalone deployment;
|
|
6
|
+
``swarph gateway serve`` bundles it as a first-class verb so any host
|
|
7
|
+
can stand up a gateway the same way it runs the client verbs.
|
|
8
|
+
|
|
9
|
+
The FastAPI/uvicorn server stack is an OPTIONAL extra so the core
|
|
10
|
+
client paths (one-shot / chat / mesh / brain-ask) stay dependency-light::
|
|
11
|
+
|
|
12
|
+
pip install "swarph-cli[gateway]"
|
|
13
|
+
|
|
14
|
+
Token model (mirrors ``swarph mesh``'s ``MESH_GATEWAY_TOKEN`` bearer):
|
|
15
|
+
|
|
16
|
+
* ``--token`` sets ``MESH_GATEWAY_TOKEN`` for the served process.
|
|
17
|
+
* Otherwise an existing ``MESH_GATEWAY_TOKEN`` in the environment is used.
|
|
18
|
+
* If neither is present a fresh token is minted (``secrets.token_urlsafe``)
|
|
19
|
+
and printed once so the operator can hand it to the mesh cells.
|
|
20
|
+
|
|
21
|
+
``bootstrap-ratify`` (#565-B) is the ratify ladder's first rung: on a fresh
|
|
22
|
+
gateway zero peers are ratified, so no witness exists and ``swarph ratify``
|
|
23
|
+
can never complete. This verb flips ONE peer ratified via a local DB write —
|
|
24
|
+
an explicit, audited act by the human commander on the gateway box, not a
|
|
25
|
+
migration accident. It self-destroys: it refuses when any ratified peer
|
|
26
|
+
already exists.
|
|
27
|
+
|
|
28
|
+
Bare ``swarph gateway`` prints help.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import argparse
|
|
34
|
+
import getpass
|
|
35
|
+
import os
|
|
36
|
+
import secrets
|
|
37
|
+
import socket
|
|
38
|
+
import sqlite3
|
|
39
|
+
import sys
|
|
40
|
+
from datetime import datetime, timezone
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
44
|
+
p = argparse.ArgumentParser(
|
|
45
|
+
prog="swarph gateway",
|
|
46
|
+
description=(
|
|
47
|
+
"Run the bundled mesh-gateway server (peer registry + DM "
|
|
48
|
+
"inbox/outbox + feature aggregation + lane/service control)."
|
|
49
|
+
),
|
|
50
|
+
)
|
|
51
|
+
sub = p.add_subparsers(dest="command")
|
|
52
|
+
|
|
53
|
+
serve = sub.add_parser("serve", help="run the mesh-gateway HTTP server")
|
|
54
|
+
serve.add_argument(
|
|
55
|
+
"--host",
|
|
56
|
+
default="127.0.0.1",
|
|
57
|
+
help="bind address (default 127.0.0.1; use a tailnet IP to expose to peers)",
|
|
58
|
+
)
|
|
59
|
+
serve.add_argument(
|
|
60
|
+
"--port",
|
|
61
|
+
type=int,
|
|
62
|
+
default=8788,
|
|
63
|
+
help="bind port (default 8788)",
|
|
64
|
+
)
|
|
65
|
+
serve.add_argument(
|
|
66
|
+
"--token",
|
|
67
|
+
default=None,
|
|
68
|
+
help="bearer token for the gateway (sets MESH_GATEWAY_TOKEN); "
|
|
69
|
+
"minted + printed once if omitted and not already in the env",
|
|
70
|
+
)
|
|
71
|
+
serve.add_argument(
|
|
72
|
+
"--db",
|
|
73
|
+
default=None,
|
|
74
|
+
help="path to the gateway SQLite DB (sets MESH_DB_PATH)",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
boot = sub.add_parser(
|
|
78
|
+
"bootstrap-ratify",
|
|
79
|
+
help="ratify the FIRST peer on a fresh gateway (human commander, "
|
|
80
|
+
"local DB write, audited)",
|
|
81
|
+
)
|
|
82
|
+
boot.add_argument("peer", help="peer name to bootstrap-ratify")
|
|
83
|
+
boot.add_argument(
|
|
84
|
+
"--db",
|
|
85
|
+
default=None,
|
|
86
|
+
help="path to the gateway SQLite DB (default: $MESH_DB_PATH or "
|
|
87
|
+
"~/.swarph/mesh.db)",
|
|
88
|
+
)
|
|
89
|
+
boot.add_argument(
|
|
90
|
+
"--reason",
|
|
91
|
+
default=None,
|
|
92
|
+
help="extra audit text appended to the bootstrap reason",
|
|
93
|
+
)
|
|
94
|
+
return p
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _serve(args: argparse.Namespace) -> int:
|
|
98
|
+
# Dependency gate — the server stack is an optional extra. Probe the
|
|
99
|
+
# imports before touching uvicorn so a missing extra prints a clean
|
|
100
|
+
# install hint instead of a traceback.
|
|
101
|
+
try:
|
|
102
|
+
import fastapi # noqa: F401
|
|
103
|
+
import uvicorn # noqa: F401
|
|
104
|
+
except ImportError:
|
|
105
|
+
sys.stderr.write(
|
|
106
|
+
'swarph gateway needs the optional server deps: '
|
|
107
|
+
'pip install "swarph-cli[gateway]"\n'
|
|
108
|
+
)
|
|
109
|
+
return 2
|
|
110
|
+
|
|
111
|
+
if args.db:
|
|
112
|
+
os.environ["MESH_DB_PATH"] = args.db
|
|
113
|
+
|
|
114
|
+
token = args.token or os.environ.get("MESH_GATEWAY_TOKEN")
|
|
115
|
+
if not token:
|
|
116
|
+
token = secrets.token_urlsafe(48)
|
|
117
|
+
print(
|
|
118
|
+
"swarph gateway: minted a new MESH_GATEWAY_TOKEN "
|
|
119
|
+
"(give this to your mesh cells):\n"
|
|
120
|
+
f" {token}",
|
|
121
|
+
file=sys.stderr,
|
|
122
|
+
)
|
|
123
|
+
os.environ["MESH_GATEWAY_TOKEN"] = token
|
|
124
|
+
|
|
125
|
+
uvicorn.run(
|
|
126
|
+
"swarph_cli.gateway.server:app",
|
|
127
|
+
host=args.host,
|
|
128
|
+
port=args.port,
|
|
129
|
+
log_level="info",
|
|
130
|
+
)
|
|
131
|
+
return 0
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _bootstrap_ratify(args: argparse.Namespace) -> int:
|
|
135
|
+
"""#565-B: the ratify ladder's first rung, as an audited local write.
|
|
136
|
+
|
|
137
|
+
On a fresh gateway, `swarph ratify` can never complete — the witness must
|
|
138
|
+
itself be ratified, and zero peers are. The live mesh only works because
|
|
139
|
+
a one-time Phase 5.5 migration grandfathered its cohort; every deployment
|
|
140
|
+
since hangs off that accident. This verb makes the bootstrap explicit:
|
|
141
|
+
|
|
142
|
+
* LOCAL DB write — operator-with-filesystem-access is already god; this
|
|
143
|
+
makes the act explicit and audited instead of a SQL escape hatch.
|
|
144
|
+
* HUMAN-only — an interactive tty and a typed 'yes'. One prompt, no
|
|
145
|
+
ceremony: the gate must not cut into the onboarding flow it serves.
|
|
146
|
+
* SELF-DESTROYING — refuses when ANY ratified peer exists, so it can
|
|
147
|
+
never become a second ratification path. Recovery stays possible:
|
|
148
|
+
whenever zero ratified peers exist, the gate passes again.
|
|
149
|
+
* HAND-IN-HAND with onboarding — the target must already be registered
|
|
150
|
+
(onboard first), and the output names the next step.
|
|
151
|
+
"""
|
|
152
|
+
db_path = (
|
|
153
|
+
args.db
|
|
154
|
+
or os.environ.get("MESH_DB_PATH")
|
|
155
|
+
or os.path.expanduser("~/.swarph/mesh.db")
|
|
156
|
+
)
|
|
157
|
+
if not os.path.exists(db_path):
|
|
158
|
+
sys.stderr.write(
|
|
159
|
+
f"swarph gateway bootstrap-ratify: no gateway DB at {db_path}\n"
|
|
160
|
+
" Run this on the gateway box, or pass --db / set MESH_DB_PATH.\n"
|
|
161
|
+
)
|
|
162
|
+
return 2
|
|
163
|
+
|
|
164
|
+
# Match server.py _conn(): autocommit with explicit transaction control
|
|
165
|
+
# (we BEGIN IMMEDIATE ourselves) and FK enforcement ON — the audit insert
|
|
166
|
+
# into peer_ratifications references claude_peers, and without the pragma
|
|
167
|
+
# a dangling reference would write silently.
|
|
168
|
+
conn = sqlite3.connect(db_path, isolation_level=None)
|
|
169
|
+
conn.execute("PRAGMA foreign_keys = ON")
|
|
170
|
+
conn.row_factory = sqlite3.Row
|
|
171
|
+
try:
|
|
172
|
+
row = conn.execute(
|
|
173
|
+
"SELECT ratified FROM claude_peers WHERE name = ?", (args.peer,)
|
|
174
|
+
).fetchone()
|
|
175
|
+
if row is None:
|
|
176
|
+
sys.stderr.write(
|
|
177
|
+
f"swarph gateway bootstrap-ratify: {args.peer!r} is not "
|
|
178
|
+
"registered —\n onboard it first:\n"
|
|
179
|
+
f" swarph onboard {args.peer}\n"
|
|
180
|
+
)
|
|
181
|
+
return 2
|
|
182
|
+
if row["ratified"]:
|
|
183
|
+
print(f"{args.peer!r} is already ratified — nothing to do.")
|
|
184
|
+
return 0
|
|
185
|
+
existing = conn.execute(
|
|
186
|
+
"SELECT name FROM claude_peers WHERE ratified = 1 LIMIT 1"
|
|
187
|
+
).fetchone()
|
|
188
|
+
if existing:
|
|
189
|
+
sys.stderr.write(
|
|
190
|
+
f"swarph gateway bootstrap-ratify: refusing — "
|
|
191
|
+
f"{existing['name']!r} is already ratified.\n"
|
|
192
|
+
" The ladder has its first rung; bootstrap exists ONLY for a "
|
|
193
|
+
"fresh gateway.\n"
|
|
194
|
+
f" Ratify {args.peer!r} through the normal witness path "
|
|
195
|
+
f"(a ratified witness runs:\n"
|
|
196
|
+
f" swarph ratify {args.peer} --reason \"<short text>\")\n"
|
|
197
|
+
)
|
|
198
|
+
return 2
|
|
199
|
+
|
|
200
|
+
if not sys.stdin.isatty():
|
|
201
|
+
sys.stderr.write(
|
|
202
|
+
"swarph gateway bootstrap-ratify: refusing — this is the "
|
|
203
|
+
"human commander's act.\n"
|
|
204
|
+
" Run it interactively on the gateway box (no pipes, no "
|
|
205
|
+
"scripts, no cells).\n"
|
|
206
|
+
)
|
|
207
|
+
return 2
|
|
208
|
+
|
|
209
|
+
operator = f"{getpass.getuser()}@{socket.gethostname()}"
|
|
210
|
+
print(f"Bootstrap-ratify {args.peer!r} on {db_path}:")
|
|
211
|
+
print(" - zero ratified peers exist (fresh gateway)")
|
|
212
|
+
print(" - flips ratified=1 and writes an audited peer_ratifications "
|
|
213
|
+
"row (binding_regime='bootstrap')")
|
|
214
|
+
print(f" - performed by {operator}")
|
|
215
|
+
if input("Type 'yes' to confirm: ").strip().lower() != "yes":
|
|
216
|
+
print("aborted — nothing written.")
|
|
217
|
+
return 1
|
|
218
|
+
|
|
219
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
220
|
+
reason = f"bootstrap by {operator} (#565)"
|
|
221
|
+
if args.reason:
|
|
222
|
+
reason += f": {args.reason}"
|
|
223
|
+
conn.execute("BEGIN IMMEDIATE")
|
|
224
|
+
try:
|
|
225
|
+
row = conn.execute(
|
|
226
|
+
"SELECT ratified FROM claude_peers WHERE name = ?", (args.peer,)
|
|
227
|
+
).fetchone()
|
|
228
|
+
existing = conn.execute(
|
|
229
|
+
"SELECT name FROM claude_peers WHERE ratified = 1 LIMIT 1"
|
|
230
|
+
).fetchone()
|
|
231
|
+
if row is None or row["ratified"] or existing:
|
|
232
|
+
conn.execute("ROLLBACK")
|
|
233
|
+
sys.stderr.write(
|
|
234
|
+
"swarph gateway bootstrap-ratify: gateway state changed while "
|
|
235
|
+
"you confirmed; refusing to create a second first rung.\n"
|
|
236
|
+
)
|
|
237
|
+
return 2
|
|
238
|
+
conn.execute(
|
|
239
|
+
"UPDATE claude_peers SET ratified=1, ratified_at=?, "
|
|
240
|
+
"ratified_by=?, ratification_reason=? WHERE name=?",
|
|
241
|
+
(now, "bootstrap", reason, args.peer),
|
|
242
|
+
)
|
|
243
|
+
conn.execute(
|
|
244
|
+
"INSERT INTO peer_ratifications "
|
|
245
|
+
"(peer, ratified_by, ratified_at, reason, witness_dm_id, "
|
|
246
|
+
"binding_regime) VALUES (?, ?, ?, ?, NULL, 'bootstrap')",
|
|
247
|
+
(args.peer, "bootstrap", now, reason),
|
|
248
|
+
)
|
|
249
|
+
conn.execute("COMMIT")
|
|
250
|
+
except Exception:
|
|
251
|
+
conn.execute("ROLLBACK")
|
|
252
|
+
raise
|
|
253
|
+
finally:
|
|
254
|
+
conn.close()
|
|
255
|
+
|
|
256
|
+
print(f"{args.peer!r} ratified (bootstrap). The ladder has its first "
|
|
257
|
+
"rung — hand in hand with onboarding:")
|
|
258
|
+
print(f" - {args.peer} can now WITNESS ratifications for the cells "
|
|
259
|
+
"that follow")
|
|
260
|
+
print(f" - next cell: `swarph onboard <cell>` on its box, complete the "
|
|
261
|
+
f"handshake, then a witness runs:")
|
|
262
|
+
print(f" swarph ratify <cell> --reason \"<short text>\"")
|
|
263
|
+
return 0
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def run_gateway(argv: list) -> int:
|
|
267
|
+
"""Entry point invoked by ``swarph_cli.main`` verb dispatch."""
|
|
268
|
+
parser = _build_parser()
|
|
269
|
+
args = parser.parse_args(argv)
|
|
270
|
+
|
|
271
|
+
if args.command == "serve":
|
|
272
|
+
return _serve(args)
|
|
273
|
+
if args.command == "bootstrap-ratify":
|
|
274
|
+
return _bootstrap_ratify(args)
|
|
275
|
+
|
|
276
|
+
# bare `swarph gateway` (no subcommand) — print help.
|
|
277
|
+
parser.print_help()
|
|
278
|
+
return 0
|