swarph-cli 0.45.2__tar.gz → 0.47.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.45.2/src/swarph_cli.egg-info → swarph_cli-0.47.0}/PKG-INFO +2 -1
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/README.md +1 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/pyproject.toml +3 -2
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/board.py +52 -3
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/brain_ask.py +7 -3
- swarph_cli-0.47.0/src/swarph_cli/commands/gateway.py +278 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/gh_route.py +2 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/init.py +7 -1
- swarph_cli-0.47.0/src/swarph_cli/commands/install_postcompact_hook.py +403 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/install_wake_hook.py +57 -6
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/memory_emit_hook.py +15 -5
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/mesh.py +246 -16
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/monitor.py +1 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/onboard.py +155 -6
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/spawn.py +113 -176
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/wake_hook_output.py +3 -1
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/gateway/schema.sql +3 -1
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/guide/GUIDE.md +3 -2
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/main.py +7 -1
- swarph_cli-0.47.0/src/swarph_cli/payloads/postcompact/_shim.cmd +4 -0
- swarph_cli-0.47.0/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +9 -0
- swarph_cli-0.47.0/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +19 -0
- swarph_cli-0.47.0/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +22 -0
- swarph_cli-0.47.0/src/swarph_cli/payloads/postcompact/precompact-flag.sh +10 -0
- swarph_cli-0.47.0/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +23 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/codex-waker.default +4 -1
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/peer-reply-drain.default +4 -1
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/tokens.py +22 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0/src/swarph_cli.egg-info}/PKG-INFO +2 -1
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli.egg-info/SOURCES.txt +13 -0
- swarph_cli-0.47.0/tests/test_124_register_merge.py +112 -0
- swarph_cli-0.47.0/tests/test_319_refusal_exit_codes.py +147 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_467b_onboard_operator_credential.py +42 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_532_accept_flag.py +6 -0
- swarph_cli-0.47.0/tests/test_535_version_capability.py +113 -0
- swarph_cli-0.47.0/tests/test_548_gateway_remainder.py +82 -0
- swarph_cli-0.47.0/tests/test_board_obligation_close.py +77 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_brain_ask_command.py +5 -2
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_cursor_membrane.py +43 -2
- swarph_cli-0.47.0/tests/test_gateway_command.py +226 -0
- swarph_cli-0.47.0/tests/test_install_postcompact_hook.py +341 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_install_wake_hook.py +56 -2
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_mesh_command.py +5 -1
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_monitor_state_split.py +57 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_onboard_command.py +192 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_postcompact_recall.py +66 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_spawn_base_hoist.py +39 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_spawn_command.py +3 -1
- swarph_cli-0.45.2/src/swarph_cli/commands/gateway.py +0 -116
- swarph_cli-0.45.2/tests/test_gateway_command.py +0 -92
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/LICENSE +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/setup.cfg +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_board_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_group_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_import_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_init_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_main.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_security.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_service_app.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_service_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.0}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.45.2 → swarph_cli-0.47.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.47.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
|
|
@@ -186,6 +186,7 @@ swarph board cards thread <id> [--limit N] # the card's conversation (a card
|
|
|
186
186
|
swarph board cards say <id> --content "…" [--to <peer>] [--kind fyi|question|answer|status|unblock]
|
|
187
187
|
swarph board cards ask <id> <holder> "<what>" [--timeout-hours N] # MINT an obligation:
|
|
188
188
|
# name who owes what as a ROW, not a sentence (#307)
|
|
189
|
+
swarph board obligations close <id> --outcome <pass|fail|cannot_evaluate> --evidence "what you observed"
|
|
189
190
|
```
|
|
190
191
|
|
|
191
192
|
`--project` accepts a numeric id **or** a slug (resolved via `projects list`). Note: card creation always starts at `proposed` (the gateway has no stage-on-create) — use `cards move` to advance.
|
|
@@ -138,6 +138,7 @@ swarph board cards thread <id> [--limit N] # the card's conversation (a card
|
|
|
138
138
|
swarph board cards say <id> --content "…" [--to <peer>] [--kind fyi|question|answer|status|unblock]
|
|
139
139
|
swarph board cards ask <id> <holder> "<what>" [--timeout-hours N] # MINT an obligation:
|
|
140
140
|
# name who owes what as a ROW, not a sentence (#307)
|
|
141
|
+
swarph board obligations close <id> --outcome <pass|fail|cannot_evaluate> --evidence "what you observed"
|
|
141
142
|
```
|
|
142
143
|
|
|
143
144
|
`--project` accepts a numeric id **or** a slug (resolved via `projects list`). Note: card creation always starts at `proposed` (the gateway has no stage-on-create) — use `cards move` to advance.
|
|
@@ -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.47.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"]
|
|
@@ -284,9 +284,10 @@ def _format_ask(d) -> str:
|
|
|
284
284
|
return (f"obligation #{d.get('id')} on card #{d.get('card_id')}: "
|
|
285
285
|
f"{d.get('holder')} owes it, status={d.get('status')}, {deadline}\n"
|
|
286
286
|
f" {falsifier}\n"
|
|
287
|
-
f" thread {d.get('thread_uuid')} —
|
|
288
|
-
f"
|
|
289
|
-
f"
|
|
287
|
+
f" thread {d.get('thread_uuid')} — work lands IN that thread; CLOSE "
|
|
288
|
+
f"it with `swarph board obligations close {d.get('id')}` plus an "
|
|
289
|
+
f"outcome and evidence; a plain `mesh send` cannot close it "
|
|
290
|
+
f"(#509/#562 — the VERB is the mechanism, the thread is where it lands)")
|
|
290
291
|
|
|
291
292
|
|
|
292
293
|
def _format_thread(data) -> str:
|
|
@@ -377,6 +378,25 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
377
378
|
cr = cards.add_parser("ready", help="flag a card ready-to-advance (move_ready) for the orchestrator")
|
|
378
379
|
cr.add_argument("id", type=int); cr.add_argument("--clear", action="store_true", help="unset move_ready")
|
|
379
380
|
cr.add_argument("--json", action="store_true"); _add_common(cr)
|
|
381
|
+
|
|
382
|
+
obl = top.add_parser(
|
|
383
|
+
"obligations",
|
|
384
|
+
help="card obligations — the close act (#562)").add_subparsers(
|
|
385
|
+
dest="command", required=True)
|
|
386
|
+
oc = obl.add_parser(
|
|
387
|
+
"close",
|
|
388
|
+
help="CLOSE an obligation: the DISTINCT ACT that records the check's "
|
|
389
|
+
"outcome plus the evidence observed. A thread reply does NOT "
|
|
390
|
+
"close an obligation (#562) — this does")
|
|
391
|
+
oc.add_argument("id", type=int, help="the obligation id")
|
|
392
|
+
oc.add_argument("--outcome", required=True,
|
|
393
|
+
choices=("pass", "fail", "cannot_evaluate"),
|
|
394
|
+
help="the accept check's OUTCOME")
|
|
395
|
+
oc.add_argument("--evidence", required=True,
|
|
396
|
+
help="what you OBSERVED running the check — whitespace is "
|
|
397
|
+
"refused: whitespace evidence is the vibe-close this "
|
|
398
|
+
"endpoint exists to kill")
|
|
399
|
+
oc.add_argument("--json", action="store_true"); _add_common(oc)
|
|
380
400
|
return p
|
|
381
401
|
|
|
382
402
|
|
|
@@ -425,6 +445,35 @@ def run_board(argv: list[str]) -> int:
|
|
|
425
445
|
st, d = _post_json(f"{gw}/board/projects", _project_add_payload(self_name, args.slug, args.title, goal=args.goal), token)
|
|
426
446
|
return _out(st, d, lambda x: f"created project #{x.get('id')} ({x.get('slug')})", aj)
|
|
427
447
|
|
|
448
|
+
if args.group == "obligations":
|
|
449
|
+
if args.command == "close":
|
|
450
|
+
# #562's CLI half: the explicit close act. The gateway guards the
|
|
451
|
+
# identity (holder, creator, or board orchestrator) and refuses a
|
|
452
|
+
# second close; the CLI's job is to refuse what it can see —
|
|
453
|
+
# whitespace evidence — and to propagate the gateway's refusals
|
|
454
|
+
# with their detail intact.
|
|
455
|
+
evidence = args.evidence
|
|
456
|
+
if not evidence.strip():
|
|
457
|
+
print("swarph board obligations close: --evidence is "
|
|
458
|
+
"whitespace-only — the close act records what you "
|
|
459
|
+
"OBSERVED, and nothing was observed", file=sys.stderr)
|
|
460
|
+
return 2
|
|
461
|
+
st, d = _post_json(
|
|
462
|
+
f"{gw}/board/obligations/{args.id}/close",
|
|
463
|
+
{"outcome": args.outcome, "evidence": evidence}, token)
|
|
464
|
+
if st < 200 or st >= 300:
|
|
465
|
+
detail = d.get("detail", d) if isinstance(d, dict) else d
|
|
466
|
+
print(f"swarph board obligations close: gateway {st}: {_s(detail)}",
|
|
467
|
+
file=sys.stderr)
|
|
468
|
+
return 1
|
|
469
|
+
if aj:
|
|
470
|
+
print(json.dumps(d, indent=2))
|
|
471
|
+
else:
|
|
472
|
+
print(f"obligation #{_s(d.get('id', args.id))} CLOSED by "
|
|
473
|
+
f"{_s(d.get('closed_by', self_name))} — outcome: "
|
|
474
|
+
f"{_s(d.get('close_outcome', args.outcome))}")
|
|
475
|
+
return 0
|
|
476
|
+
|
|
428
477
|
if args.group == "cards":
|
|
429
478
|
if args.command == "list":
|
|
430
479
|
pid, err = _resolve_project(gw, token, args.project)
|
|
@@ -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
|
|
@@ -51,6 +51,8 @@ def _allow_unchanged() -> int:
|
|
|
51
51
|
|
|
52
52
|
def run_hook(stdin_text: Optional[str] = None) -> int:
|
|
53
53
|
raw = stdin_text if stdin_text is not None else sys.stdin.read()
|
|
54
|
+
# PS 5.1 native pipes prefix a (double) UTF-8 BOM; strip before parse.
|
|
55
|
+
raw = (raw or "").lstrip("\ufeff")
|
|
54
56
|
try:
|
|
55
57
|
payload = json.loads(raw or "{}")
|
|
56
58
|
except Exception:
|
|
@@ -265,7 +265,13 @@ def run_init(argv: list[str]) -> int:
|
|
|
265
265
|
# its own context); an operator running `swarph onboard` first mints the
|
|
266
266
|
# token into a process that discards it, and the cell's later self-register
|
|
267
267
|
# returns token_status=existing with nothing.
|
|
268
|
-
|
|
268
|
+
# Scoped as CONDITIONAL (#319 d): a standalone outsider has no mesh and
|
|
269
|
+
# cannot ratify — the mesh path is named for the user who IS joining one,
|
|
270
|
+
# not presented as the next thing everyone must do. The outsider's next
|
|
271
|
+
# step is the `ready:` line above (swarph spawn), which works with zero
|
|
272
|
+
# mesh.
|
|
273
|
+
print(f"next: if you're joining a mesh — from the CELL'S OWN context: "
|
|
274
|
+
f"`swarph mesh register --as {name}` "
|
|
269
275
|
f"(mints + stores its once-only per-peer token, mode 600); then a witness "
|
|
270
276
|
f"runs `swarph ratify {name}`. Status at any point: "
|
|
271
277
|
f"`swarph onboard --check {name}`.")
|