swarph-cli 0.69.9__tar.gz → 0.71.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.69.9/src/swarph_cli.egg-info → swarph_cli-0.71.0}/PKG-INFO +1 -1
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/pyproject.toml +4 -1
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/backends.py +9 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/runner.py +23 -2
- swarph_cli-0.71.0/src/swarph_cli/bench/signal_score.py +110 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/validate.py +63 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/capture/paths.py +11 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/bench.py +30 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/board.py +68 -1
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/codegraph_hook.py +12 -1
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/hooks.py +50 -13
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/install_wake_hook.py +8 -7
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/mesh.py +310 -31
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/monitor.py +106 -9
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/wake_hook_output.py +64 -5
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/guide/GUIDE.md +3 -2
- swarph_cli-0.71.0/src/swarph_cli/operator/__init__.py +11 -0
- swarph_cli-0.71.0/src/swarph_cli/operator/__main__.py +4 -0
- swarph_cli-0.71.0/src/swarph_cli/operator/api.py +40 -0
- swarph_cli-0.71.0/src/swarph_cli/operator/cli.py +509 -0
- swarph_cli-0.71.0/src/swarph_cli/operator/config.py +90 -0
- swarph_cli-0.71.0/src/swarph_cli/operator/fmt.py +131 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli.egg-info/SOURCES.txt +13 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli.egg-info/entry_points.txt +1 -0
- swarph_cli-0.71.0/tests/test_1006_board_publisher.py +311 -0
- swarph_cli-0.71.0/tests/test_538_signal_bench.py +126 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_644_monitor_supervision.py +86 -11
- swarph_cli-0.71.0/tests/test_729_arm_check_delivery_gap.py +136 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_739_wake_writer.py +48 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_830_hook_binding_version.py +39 -1
- swarph_cli-0.71.0/tests/test_961_cursor_grok_footer.py +331 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_board_command.py +61 -1
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_content_composition.py +6 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_install_wake_hook.py +107 -53
- swarph_cli-0.71.0/tests/test_mesh_sidecar_muse_sink.py +193 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_opencode_plugin.py +1 -2
- swarph_cli-0.71.0/tests/test_operator_me.py +218 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/LICENSE +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/README.md +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/setup.cfg +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/providers.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_1006_session_board.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_735_dm_mcp_tools.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_group_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_import_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_init_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_main.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_security.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_service_app.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_service_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_version_command.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.0}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.69.9 → swarph_cli-0.71.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.71.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.71.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" }
|
|
@@ -130,6 +130,9 @@ service = [
|
|
|
130
130
|
|
|
131
131
|
[project.scripts]
|
|
132
132
|
swarph = "swarph_cli.main:main"
|
|
133
|
+
# #660: operator surface — separate entrypoint so identity cannot inherit
|
|
134
|
+
# $SWARPH_SELF from the cell CLI helpers (see swarph_cli.operator + its tests).
|
|
135
|
+
swarph-me = "swarph_cli.operator:main"
|
|
133
136
|
|
|
134
137
|
[tool.setuptools.packages.find]
|
|
135
138
|
where = ["src"]
|
|
@@ -475,6 +475,15 @@ class RuleBackend:
|
|
|
475
475
|
)
|
|
476
476
|
|
|
477
477
|
|
|
478
|
+
class SignalBackend(RuleBackend):
|
|
479
|
+
"""Deterministic signal arm (#213). ``model_id`` is ``module:callable``.
|
|
480
|
+
|
|
481
|
+
Same call as :class:`RuleBackend`: no credentials, no network, the
|
|
482
|
+
callable's return value is the categorical label. The runner scores a
|
|
483
|
+
``signal:`` arm with the robust date-grouped scorer, not mean distance.
|
|
484
|
+
"""
|
|
485
|
+
|
|
486
|
+
|
|
478
487
|
class TypedHttpBackend:
|
|
479
488
|
KIND = "typed"
|
|
480
489
|
"""POST a bench item to a Jev-compatible ``/v1/systemone`` server.
|
|
@@ -21,6 +21,7 @@ from .backends import Backend, BackendResult, _redact
|
|
|
21
21
|
from .prices import cost_usd, is_known, lookup
|
|
22
22
|
from .providers import egress_of_url
|
|
23
23
|
from .quality import score
|
|
24
|
+
from .signal_score import robust_report
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
@dataclass
|
|
@@ -55,7 +56,10 @@ def parse_models(arg: str) -> list[ModelSpec]:
|
|
|
55
56
|
id=name, backend="provider", provider=name,
|
|
56
57
|
label=label or f"provider:{name}"))
|
|
57
58
|
continue
|
|
58
|
-
|
|
59
|
+
# signal:<module:callable> is the deterministic signal-backtest arm
|
|
60
|
+
# (#213). It carries colons in the payload, same as rule:.
|
|
61
|
+
for prefix, backend in (
|
|
62
|
+
("typed-http:", "typed-http"), ("rule:", "rule"), ("signal:", "signal")):
|
|
59
63
|
if tok.startswith(prefix):
|
|
60
64
|
specs.append(ModelSpec(id=tok[len(prefix):], backend=backend, label=tok))
|
|
61
65
|
break
|
|
@@ -120,6 +124,7 @@ class ModelBoardRow:
|
|
|
120
124
|
base_url: str = ""
|
|
121
125
|
path: str = ""
|
|
122
126
|
kind: str = ""
|
|
127
|
+
robust: Optional[dict] = None
|
|
123
128
|
|
|
124
129
|
|
|
125
130
|
def _dispatch(backend: Backend, model_id: str, prompt: str, system: str) -> BackendResult:
|
|
@@ -319,6 +324,7 @@ def run_pack(
|
|
|
319
324
|
resumed[item["task_id"]] = _taskrow_from_ledger(item)
|
|
320
325
|
|
|
321
326
|
rows: list[TaskRow] = []
|
|
327
|
+
signal_obs: list[dict] = []
|
|
322
328
|
arm_spent = 0.0
|
|
323
329
|
arm_stopped = False
|
|
324
330
|
for task in tasks:
|
|
@@ -389,6 +395,17 @@ def run_pack(
|
|
|
389
395
|
estimated=result.estimated or unknown,
|
|
390
396
|
text=result.text,
|
|
391
397
|
))
|
|
398
|
+
if spec.backend == "signal":
|
|
399
|
+
meta = task.get("meta") or {}
|
|
400
|
+
fwd = meta.get("fwd")
|
|
401
|
+
predicted = sc.get("parsed")
|
|
402
|
+
signal_obs.append({
|
|
403
|
+
"cls": class_of(task),
|
|
404
|
+
"date": str(meta.get("date") or ""),
|
|
405
|
+
"fwd": float(fwd) if isinstance(fwd, (int, float)) and not isinstance(fwd, bool) else None,
|
|
406
|
+
"expected": str(task.get("expected") or ""),
|
|
407
|
+
"predicted": str(predicted).strip().upper() if predicted is not None else "",
|
|
408
|
+
})
|
|
392
409
|
detail[spec.label] = rows
|
|
393
410
|
|
|
394
411
|
done = [r for r in rows if r.error is None and not r.not_run]
|
|
@@ -429,6 +446,7 @@ def run_pack(
|
|
|
429
446
|
base_url=getattr(backend, "base_url", ""),
|
|
430
447
|
path=getattr(backend, "path", ""),
|
|
431
448
|
kind=getattr(backend, "KIND", ""),
|
|
449
|
+
robust=robust_report(signal_obs) if spec.backend == "signal" else None,
|
|
432
450
|
))
|
|
433
451
|
|
|
434
452
|
board.sort(key=lambda b: (b.mean_distance, b.cost_usd))
|
|
@@ -439,7 +457,10 @@ def run_pack(
|
|
|
439
457
|
"aborted": partial == "aborted",
|
|
440
458
|
"exit_code": 1 if partial else 0,
|
|
441
459
|
"egress_overrides": overrides,
|
|
442
|
-
"board": [
|
|
460
|
+
"board": [
|
|
461
|
+
{k: v for k, v in vars(b).items() if k != "robust" or v is not None}
|
|
462
|
+
for b in board
|
|
463
|
+
],
|
|
443
464
|
"detail": {label: [vars(r) for r in rows] for label, rows in detail.items()},
|
|
444
465
|
}
|
|
445
466
|
text = _redact(json.dumps(payload), secrets)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Robust scorer for a signal pack (#213).
|
|
2
|
+
|
|
3
|
+
Mean distance is the wrong lens for a categorical UP/FLAT/DOWN call: an arm
|
|
4
|
+
that always says FLAT can look precise while never separating the tails.
|
|
5
|
+
This scorer reports, per cell and only then pooled:
|
|
6
|
+
|
|
7
|
+
- n
|
|
8
|
+
- balanced accuracy (mean recall over the outcome labels present in the cell)
|
|
9
|
+
- the median forward return of the rows the arm called UP, and of the rows
|
|
10
|
+
it called DOWN (the separation)
|
|
11
|
+
- a bootstrap confidence interval of that separation, resampling whole
|
|
12
|
+
decision dates so rows that share a date stay together
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import random
|
|
17
|
+
|
|
18
|
+
LABELS = ("UP", "FLAT", "DOWN")
|
|
19
|
+
N_BOOT = 1000
|
|
20
|
+
SEED = 20260927
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _median(xs: list[float]) -> float | None:
|
|
24
|
+
if not xs:
|
|
25
|
+
return None
|
|
26
|
+
s = sorted(xs)
|
|
27
|
+
n = len(s)
|
|
28
|
+
mid = n // 2
|
|
29
|
+
if n % 2:
|
|
30
|
+
return s[mid]
|
|
31
|
+
return (s[mid - 1] + s[mid]) / 2.0
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def balanced_accuracy(expected: list[str], predicted: list[str]) -> float | None:
|
|
35
|
+
recalls = []
|
|
36
|
+
for lab in LABELS:
|
|
37
|
+
idx = [i for i, e in enumerate(expected) if e == lab]
|
|
38
|
+
if not idx:
|
|
39
|
+
continue
|
|
40
|
+
recalls.append(sum(1 for i in idx if predicted[i] == lab) / len(idx))
|
|
41
|
+
if not recalls:
|
|
42
|
+
return None
|
|
43
|
+
return round(sum(recalls) / len(recalls), 4)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def cell_block(rows: list[dict]) -> dict:
|
|
47
|
+
expected = [str(r.get("expected") or "") for r in rows]
|
|
48
|
+
predicted = [str(r.get("predicted") or "") for r in rows]
|
|
49
|
+
up = [float(r["fwd"]) for r in rows if r.get("predicted") == "UP" and isinstance(r.get("fwd"), (int, float))]
|
|
50
|
+
down = [float(r["fwd"]) for r in rows if r.get("predicted") == "DOWN" and isinstance(r.get("fwd"), (int, float))]
|
|
51
|
+
med_up = _median(up)
|
|
52
|
+
med_down = _median(down)
|
|
53
|
+
sep = None if med_up is None or med_down is None else round(med_up - med_down, 6)
|
|
54
|
+
return {
|
|
55
|
+
"n": len(rows),
|
|
56
|
+
"balanced_accuracy": balanced_accuracy(expected, predicted),
|
|
57
|
+
"n_called_up": len(up),
|
|
58
|
+
"n_called_down": len(down),
|
|
59
|
+
"median_fwd_called_up": None if med_up is None else round(med_up, 6),
|
|
60
|
+
"median_fwd_called_down": None if med_down is None else round(med_down, 6),
|
|
61
|
+
"separation": sep,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def bootstrap_ci(rows: list[dict], *, n_boot: int = N_BOOT, seed: int = SEED) -> dict:
|
|
66
|
+
"""95% interval of separation, resampling decision dates with replacement."""
|
|
67
|
+
by_date: dict[str, list[dict]] = {}
|
|
68
|
+
for row in rows:
|
|
69
|
+
by_date.setdefault(str(row.get("date") or ""), []).append(row)
|
|
70
|
+
dates = sorted(by_date)
|
|
71
|
+
out = {
|
|
72
|
+
"stat": "separation",
|
|
73
|
+
"n_dates": len(dates),
|
|
74
|
+
"n_boot": n_boot,
|
|
75
|
+
"seed": seed,
|
|
76
|
+
"lo": None,
|
|
77
|
+
"hi": None,
|
|
78
|
+
}
|
|
79
|
+
if len(dates) < 2:
|
|
80
|
+
return out
|
|
81
|
+
rng = random.Random(seed)
|
|
82
|
+
stats: list[float] = []
|
|
83
|
+
n_dates = len(dates)
|
|
84
|
+
for _ in range(n_boot):
|
|
85
|
+
drawn: list[dict] = []
|
|
86
|
+
for _i in range(n_dates):
|
|
87
|
+
drawn.extend(by_date[dates[rng.randrange(n_dates)]])
|
|
88
|
+
sep = cell_block(drawn)["separation"]
|
|
89
|
+
if sep is not None:
|
|
90
|
+
stats.append(sep)
|
|
91
|
+
if not stats:
|
|
92
|
+
return out
|
|
93
|
+
stats.sort()
|
|
94
|
+
last = len(stats) - 1
|
|
95
|
+
out["lo"] = round(stats[int(0.025 * last)], 6)
|
|
96
|
+
out["hi"] = round(stats[int(0.975 * last)], 6)
|
|
97
|
+
return out
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def robust_report(obs: list[dict]) -> dict:
|
|
101
|
+
"""Per-cell table first. Pooled is present only as a sibling of that table."""
|
|
102
|
+
per_cell: dict[str, dict] = {}
|
|
103
|
+
for cls in sorted({str(o.get("cls") or "") for o in obs}):
|
|
104
|
+
rows = [o for o in obs if str(o.get("cls") or "") == cls]
|
|
105
|
+
block = cell_block(rows)
|
|
106
|
+
block["bootstrap_ci"] = bootstrap_ci(rows)
|
|
107
|
+
per_cell[cls] = block
|
|
108
|
+
pooled = cell_block(obs)
|
|
109
|
+
pooled["bootstrap_ci"] = bootstrap_ci(obs)
|
|
110
|
+
return {"per_cell": per_cell, "pooled": pooled}
|
|
@@ -16,6 +16,9 @@ from __future__ import annotations
|
|
|
16
16
|
import re
|
|
17
17
|
from typing import Optional
|
|
18
18
|
|
|
19
|
+
import hashlib
|
|
20
|
+
import json
|
|
21
|
+
|
|
19
22
|
from .backends import Backend
|
|
20
23
|
from .pack import validate_schema
|
|
21
24
|
from .quality import d_text
|
|
@@ -280,4 +283,64 @@ def validate_pack(
|
|
|
280
283
|
report.warnings.extend(disc_warnings)
|
|
281
284
|
|
|
282
285
|
report.warnings.extend(gate_calibration(pack, backends))
|
|
286
|
+
report.errors.extend(gate_signal_pack(pack))
|
|
283
287
|
return report
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def tasks_sha256(tasks: list) -> str:
|
|
291
|
+
"""sha256 of the task list. Frozen canon: json.dumps with sort_keys and
|
|
292
|
+
compact separators, UTF-8. The pack builder must use this exact canon."""
|
|
293
|
+
blob = json.dumps(tasks, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
|
|
294
|
+
return hashlib.sha256(blob).hexdigest()
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def gate_signal_pack(pack: dict) -> list[str]:
|
|
298
|
+
"""A signal pack is valid only with a matching task-list sha256, a frozen
|
|
299
|
+
5-bar outcome rule, and cardinality > 1 on both conditioning axes
|
|
300
|
+
(regime and sector). A constant axis passes a schema check and still
|
|
301
|
+
measures nothing."""
|
|
302
|
+
header = pack.get("header")
|
|
303
|
+
if not isinstance(header, dict) or header.get("pack_kind") != "signal":
|
|
304
|
+
return []
|
|
305
|
+
errors: list[str] = []
|
|
306
|
+
tasks = pack.get("tasks") or []
|
|
307
|
+
digest = tasks_sha256(tasks)
|
|
308
|
+
if header.get("sha256_tasks") != digest:
|
|
309
|
+
errors.append(
|
|
310
|
+
f"header.sha256_tasks does not match the task list (computed {digest})"
|
|
311
|
+
)
|
|
312
|
+
if header.get("row_count") != len(tasks):
|
|
313
|
+
errors.append(
|
|
314
|
+
f"header.row_count={header.get('row_count')!r} does not match len(tasks)={len(tasks)}"
|
|
315
|
+
)
|
|
316
|
+
outcome = header.get("outcome") if isinstance(header.get("outcome"), dict) else {}
|
|
317
|
+
if outcome.get("horizon_bars") != 5 or outcome.get("up_gt") is None or outcome.get("down_lt") is None:
|
|
318
|
+
errors.append("header.outcome must freeze horizon_bars=5, up_gt, and down_lt")
|
|
319
|
+
for key in ("data_window", "universe_source_query", "price_history_snapshot_date"):
|
|
320
|
+
if not header.get(key):
|
|
321
|
+
errors.append(f"header.{key} is required on a signal pack")
|
|
322
|
+
regimes: set[str] = set()
|
|
323
|
+
sectors: set[str] = set()
|
|
324
|
+
for task in tasks:
|
|
325
|
+
if not isinstance(task, dict):
|
|
326
|
+
continue
|
|
327
|
+
cls = str((task.get("meta") or {}).get("class") or "")
|
|
328
|
+
if "|" not in cls:
|
|
329
|
+
errors.append(f"task {task.get('id')!r} meta.class must be '<regime>|<sector>'")
|
|
330
|
+
continue
|
|
331
|
+
regime, sector = cls.split("|", 1)
|
|
332
|
+
if regime:
|
|
333
|
+
regimes.add(regime)
|
|
334
|
+
if sector:
|
|
335
|
+
sectors.add(sector)
|
|
336
|
+
if len(regimes) < 2:
|
|
337
|
+
errors.append(
|
|
338
|
+
f"conditioning axis regime has cardinality {len(regimes)}; "
|
|
339
|
+
"a constant axis is not a valid pack"
|
|
340
|
+
)
|
|
341
|
+
if len(sectors) < 2:
|
|
342
|
+
errors.append(
|
|
343
|
+
f"conditioning axis sector has cardinality {len(sectors)}; "
|
|
344
|
+
"a constant axis is not a valid pack"
|
|
345
|
+
)
|
|
346
|
+
return errors
|
|
@@ -77,3 +77,14 @@ def manifest_path(role: str) -> Path:
|
|
|
77
77
|
validate_role(role)
|
|
78
78
|
base = captures_dir()
|
|
79
79
|
return _assert_contained(base / f"{role}.json", base)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def card_preimage_path() -> Path:
|
|
83
|
+
"""Append-only log of card text REPLACED by ``board cards edit`` on this box.
|
|
84
|
+
|
|
85
|
+
Not role-scoped (no ``validate_role``): the writer is the CLI itself, not a
|
|
86
|
+
capture role, and the file is one per machine on purpose — it answers "what
|
|
87
|
+
did an edit issued FROM HERE destroy", which is the only question a local
|
|
88
|
+
file can honestly answer. See ``_write_card_preimage`` in commands/board.py.
|
|
89
|
+
"""
|
|
90
|
+
return _swarph_state() / "board-card-preimages.jsonl"
|
|
@@ -28,6 +28,7 @@ from swarph_cli.bench.backends import (
|
|
|
28
28
|
MeteredGeminiBackend,
|
|
29
29
|
MeteredMistralBackend,
|
|
30
30
|
RuleBackend,
|
|
31
|
+
SignalBackend,
|
|
31
32
|
SubscriptionBackend,
|
|
32
33
|
TypedHttpBackend,
|
|
33
34
|
HttpBackend,
|
|
@@ -65,6 +66,7 @@ def _default_backends() -> dict[str, Backend]:
|
|
|
65
66
|
"mistral": MeteredMistralBackend(),
|
|
66
67
|
"subscription": subscription,
|
|
67
68
|
"rule": RuleBackend(),
|
|
69
|
+
"signal": SignalBackend(),
|
|
68
70
|
"typed-http": TypedHttpBackend(),
|
|
69
71
|
# Selectable class for the wiring lock. A real call is provider:<name>,
|
|
70
72
|
# which replaces this with the registry arm. An unresolved name is
|
|
@@ -108,6 +110,34 @@ def _format_run_table(result: dict) -> str:
|
|
|
108
110
|
f" {_s(cls):20} n={c['n']:<4} hits={c['hits']:<4} "
|
|
109
111
|
f"hit_rate={c['hit_rate']:<6} mean_distance={c['mean_distance']}"
|
|
110
112
|
)
|
|
113
|
+
robust = row.get("robust")
|
|
114
|
+
if robust:
|
|
115
|
+
lines.append(" per-cell (robust):")
|
|
116
|
+
per_cell = robust.get("per_cell") or {}
|
|
117
|
+
for cls, c in sorted(per_cell.items()):
|
|
118
|
+
ci = c.get("bootstrap_ci") or {}
|
|
119
|
+
lines.append(
|
|
120
|
+
f" {_s(cls):24} n={c['n']:<5} "
|
|
121
|
+
f"bal_acc={c['balanced_accuracy']} "
|
|
122
|
+
f"med_up={c['median_fwd_called_up']} "
|
|
123
|
+
f"med_down={c['median_fwd_called_down']} "
|
|
124
|
+
f"sep={c['separation']} "
|
|
125
|
+
f"ci=[{ci.get('lo')}, {ci.get('hi')}]"
|
|
126
|
+
)
|
|
127
|
+
# Pooled sits beside the per-cell table. It is not printed when
|
|
128
|
+
# the table is empty — a pooled-only line is the failure mode
|
|
129
|
+
# this scorer exists to prevent.
|
|
130
|
+
if per_cell and robust.get("pooled"):
|
|
131
|
+
p = robust["pooled"]
|
|
132
|
+
ci = p.get("bootstrap_ci") or {}
|
|
133
|
+
lines.append(
|
|
134
|
+
" pooled (beside the per-cell table): "
|
|
135
|
+
f"n={p['n']} bal_acc={p['balanced_accuracy']} "
|
|
136
|
+
f"med_up={p['median_fwd_called_up']} "
|
|
137
|
+
f"med_down={p['median_fwd_called_down']} "
|
|
138
|
+
f"sep={p['separation']} "
|
|
139
|
+
f"ci=[{ci.get('lo')}, {ci.get('hi')}]"
|
|
140
|
+
)
|
|
111
141
|
return "\n".join(lines)
|
|
112
142
|
|
|
113
143
|
|
|
@@ -12,11 +12,14 @@ from __future__ import annotations
|
|
|
12
12
|
|
|
13
13
|
import argparse
|
|
14
14
|
import json
|
|
15
|
+
import os
|
|
15
16
|
import re
|
|
16
17
|
import sys
|
|
17
18
|
import urllib.error
|
|
18
19
|
import urllib.parse
|
|
19
20
|
import urllib.request
|
|
21
|
+
from datetime import datetime, timezone
|
|
22
|
+
from pathlib import Path
|
|
20
23
|
from typing import Optional
|
|
21
24
|
|
|
22
25
|
# #532 — negative-branch marker detection. THREE COPIES exist and no single
|
|
@@ -30,6 +33,7 @@ from typing import Optional
|
|
|
30
33
|
# substring test can know a falsifier exists.
|
|
31
34
|
_FAIL_MARKER_RE = re.compile(r"(?<![\w-])fail(?:s|ed|ing|ures?)?(?![\w-])", re.IGNORECASE)
|
|
32
35
|
|
|
36
|
+
from swarph_cli.capture.paths import card_preimage_path
|
|
33
37
|
from swarph_cli.commands._content import ContentError, add_content_args, resolve_content
|
|
34
38
|
from swarph_cli.commands._display import sanitize_terminal as _s
|
|
35
39
|
from swarph_cli.commands.mesh import (
|
|
@@ -178,6 +182,49 @@ def _card_edit_payload(actor, title, body, *, due_at=_SENTINEL, project_id=None,
|
|
|
178
182
|
return patch
|
|
179
183
|
|
|
180
184
|
|
|
185
|
+
def _write_card_preimage(actor, gateway, card_id, card, patch) -> Path:
|
|
186
|
+
"""Append the card's CURRENT title and body to a local log BEFORE an edit
|
|
187
|
+
replaces them. Returns the path written.
|
|
188
|
+
|
|
189
|
+
>>> WHY THE CLIENT AND NOT THE SERVER. <<< #596 is fixed for TITLE only: the
|
|
190
|
+
gateway retains the replaced title in ``body_history`` (mesh-gateway 989c83d,
|
|
191
|
+
live since 2026-09-17 13:22Z) and for a BODY edit appends {by, at, chars} —
|
|
192
|
+
who, when, and the length of the NEW text. The replaced body is gone, and
|
|
193
|
+
#596's side table (the system-wide fix) is a gateway change behind a deploy
|
|
194
|
+
gate. This is the footprint the EDITING MACHINE can keep on its own.
|
|
195
|
+
|
|
196
|
+
ponytail: one file, one box. It covers edits issued FROM HERE and nothing
|
|
197
|
+
else — a body replaced from another cell is still unrecoverable, and
|
|
198
|
+
"a transcript is a copy of the board nobody indexes" (drop-on-meta-edge,
|
|
199
|
+
#596) applies to this file too. The side table remains the real fix; this
|
|
200
|
+
only makes the window survivable.
|
|
201
|
+
"""
|
|
202
|
+
rec = {
|
|
203
|
+
"at": datetime.now(timezone.utc).isoformat(timespec="seconds").replace("+00:00", "Z"),
|
|
204
|
+
"by": actor,
|
|
205
|
+
"gateway": gateway,
|
|
206
|
+
"card": card_id,
|
|
207
|
+
"body_version": card.get("body_version"),
|
|
208
|
+
"prev_title": card.get("title"),
|
|
209
|
+
"prev_body": card.get("body"),
|
|
210
|
+
"new_title": patch.get("title"),
|
|
211
|
+
"new_body": patch.get("body"),
|
|
212
|
+
}
|
|
213
|
+
path = card_preimage_path()
|
|
214
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
215
|
+
# A previous line with no trailing newline would MERGE with this one and
|
|
216
|
+
# destroy both records; the reader is json-per-line.
|
|
217
|
+
prefix = ""
|
|
218
|
+
if path.exists() and path.stat().st_size:
|
|
219
|
+
with path.open("rb") as fh:
|
|
220
|
+
fh.seek(-1, os.SEEK_END)
|
|
221
|
+
if fh.read(1) != b"\n":
|
|
222
|
+
prefix = "\n"
|
|
223
|
+
with path.open("a", encoding="utf-8") as fh:
|
|
224
|
+
fh.write(prefix + json.dumps(rec, ensure_ascii=False) + "\n")
|
|
225
|
+
return path
|
|
226
|
+
|
|
227
|
+
|
|
181
228
|
def _apply_label(current: list, action: str, label: str) -> list:
|
|
182
229
|
"""Compute the NEW label set. Pure, so the read-modify-write is testable
|
|
183
230
|
without a gateway.
|
|
@@ -1241,12 +1288,32 @@ def run_board(argv: list[str]) -> int:
|
|
|
1241
1288
|
except ValueError as exc:
|
|
1242
1289
|
print(f"swarph board cards edit: {exc}", file=sys.stderr)
|
|
1243
1290
|
return 2
|
|
1291
|
+
# READ BEFORE WRITE, and REFUSE if either the read or the capture
|
|
1292
|
+
# fails. This mirrors `label`'s read-modify-write guard for a
|
|
1293
|
+
# different reason: there the failed read would clobber the other
|
|
1294
|
+
# labels; here it would destroy text nothing can recover (#596).
|
|
1295
|
+
st_cur, cur = _http_get_json(f"{gw}/board/cards/{args.id}", token)
|
|
1296
|
+
if st_cur != 200 or not isinstance(cur, dict):
|
|
1297
|
+
print(f"swarph board cards edit: cannot read card #{args.id} "
|
|
1298
|
+
f"before editing (HTTP {st_cur}) — refusing to write. The "
|
|
1299
|
+
f"gateway keeps NO recoverable copy of a replaced body "
|
|
1300
|
+
f"(#596), so an edit whose pre-image was not captured is "
|
|
1301
|
+
f"an unrecoverable one", file=sys.stderr)
|
|
1302
|
+
return 1
|
|
1303
|
+
try:
|
|
1304
|
+
pre = _write_card_preimage(self_name, gw, args.id, cur, patch)
|
|
1305
|
+
except OSError as exc:
|
|
1306
|
+
print(f"swarph board cards edit: cannot write the pre-image log "
|
|
1307
|
+
f"({exc}) — refusing to write, for the same reason: the "
|
|
1308
|
+
f"replaced text would exist nowhere (#596)", file=sys.stderr)
|
|
1309
|
+
return 1
|
|
1244
1310
|
st, d = _patch_json(f"{gw}/board/cards/{args.id}", patch, token)
|
|
1245
1311
|
# Surface body_version: it is the latch every verdict stamp keys on
|
|
1246
1312
|
# (#199), so an edit that re-opens reviewed work is visible in the
|
|
1247
1313
|
# success line, not only in a later audit.
|
|
1248
1314
|
return _out(st, d, lambda x: f"card #{x.get('id')} edited "
|
|
1249
|
-
f"(body_version={x.get('body_version')}
|
|
1315
|
+
f"(body_version={x.get('body_version')}; "
|
|
1316
|
+
f"pre-image {pre})", aj)
|
|
1250
1317
|
if args.command == "thread":
|
|
1251
1318
|
st, d = _http_get_json(_thread_url(gw, args.id, limit=args.limit), token)
|
|
1252
1319
|
# NO special-casing of 403/409. `_out` already returns 1 and prints the
|
|
@@ -476,8 +476,19 @@ def supported_hook_events() -> frozenset:
|
|
|
476
476
|
|
|
477
477
|
|
|
478
478
|
def run_codegraph_hook(argv: Optional[list] = None) -> int:
|
|
479
|
-
"""ALWAYS exits 0 — must never fail a turn.
|
|
479
|
+
"""ALWAYS exits 0 on hook stdin — must never fail a turn.
|
|
480
|
+
|
|
481
|
+
``--supported-events`` is the out-of-process advertise path for
|
|
482
|
+
``swarph hooks add`` (#830): prints one event name per line and exits 0
|
|
483
|
+
without reading stdin. Installers MUST invoke this via PATH ``swarph``,
|
|
484
|
+
not an in-process import — same late binding as the generated hook script.
|
|
485
|
+
"""
|
|
480
486
|
argv = list(argv or [])
|
|
487
|
+
if "--supported-events" in argv:
|
|
488
|
+
for name in sorted(supported_hook_events()):
|
|
489
|
+
print(name)
|
|
490
|
+
return 0
|
|
491
|
+
|
|
481
492
|
self_name = identity.declared(env=identity.SELF_ONLY)[0] or ""
|
|
482
493
|
gateway = env_gateway()
|
|
483
494
|
for i, a in enumerate(argv):
|
|
@@ -42,6 +42,7 @@ import json
|
|
|
42
42
|
import os
|
|
43
43
|
import re
|
|
44
44
|
import shutil
|
|
45
|
+
import subprocess
|
|
45
46
|
import sys
|
|
46
47
|
import tempfile
|
|
47
48
|
from dataclasses import dataclass
|
|
@@ -618,16 +619,50 @@ def _read_script_bundle_version(script_path: Path) -> str | None:
|
|
|
618
619
|
return m.group(1) if m else None
|
|
619
620
|
|
|
620
621
|
|
|
621
|
-
def
|
|
622
|
-
"""
|
|
622
|
+
def _probe_path_handler_events() -> frozenset | None:
|
|
623
|
+
"""Ask PATH's ``swarph codegraph-hook --supported-events`` (#830).
|
|
624
|
+
|
|
625
|
+
Same late-bound name the generated script ``exec``s. An in-process import
|
|
626
|
+
cannot see install-vs-PATH skew — measured on lab-ovh after #408. Returns
|
|
627
|
+
``None`` when the probe cannot run; empty frozenset when the handler
|
|
628
|
+
answers with no lines (old binary that ignores the flag and prints nothing).
|
|
623
629
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
630
|
+
Empty is NOT "handler was asked and supports nothing" as distinct evidence:
|
|
631
|
+
an old handler silently ignores the unknown flag, reads stdin, finds no
|
|
632
|
+
tool_input, and exits 0 with blank stdout — #830's own silent-success defect
|
|
633
|
+
answering this probe. That empty, a genuine empty advertise, and a failed
|
|
634
|
+
probe (``None`` → treated as empty below) all fail the gate closed; the
|
|
635
|
+
operator message names the likely cause. Do not read empty as a successful
|
|
636
|
+
negotiation.
|
|
627
637
|
"""
|
|
628
|
-
|
|
638
|
+
try:
|
|
639
|
+
proc = subprocess.run(
|
|
640
|
+
["swarph", "codegraph-hook", "--supported-events"],
|
|
641
|
+
capture_output=True,
|
|
642
|
+
text=True,
|
|
643
|
+
encoding="utf-8",
|
|
644
|
+
errors="replace",
|
|
645
|
+
timeout=30,
|
|
646
|
+
stdin=subprocess.DEVNULL,
|
|
647
|
+
)
|
|
648
|
+
except (FileNotFoundError, OSError, subprocess.TimeoutExpired):
|
|
649
|
+
return None
|
|
650
|
+
if proc.returncode != 0:
|
|
651
|
+
return None
|
|
652
|
+
return frozenset(
|
|
653
|
+
ln.strip() for ln in (proc.stdout or "").splitlines() if ln.strip()
|
|
654
|
+
)
|
|
655
|
+
|
|
629
656
|
|
|
630
|
-
|
|
657
|
+
def _handler_missing_events(required: tuple) -> tuple[frozenset, frozenset]:
|
|
658
|
+
"""Return (advertised, missing) via PATH probe — not an in-process import.
|
|
659
|
+
|
|
660
|
+
Bundles with empty ``handler_events`` skip this gate. A failed probe is
|
|
661
|
+
treated as advertising nothing so install fails closed.
|
|
662
|
+
"""
|
|
663
|
+
advertised = _probe_path_handler_events()
|
|
664
|
+
if advertised is None:
|
|
665
|
+
return frozenset(), frozenset(required)
|
|
631
666
|
return advertised, frozenset(required) - advertised
|
|
632
667
|
|
|
633
668
|
|
|
@@ -685,16 +720,18 @@ def install_hook(
|
|
|
685
720
|
out(" Install Git for Windows, then re-run — nothing was written.")
|
|
686
721
|
return 1
|
|
687
722
|
|
|
688
|
-
# #830: refuse bindings
|
|
689
|
-
#
|
|
723
|
+
# #830: refuse bindings PATH's handler cannot advertise. Probe out of
|
|
724
|
+
# process (same ``swarph`` name the script will exec) — an in-process
|
|
725
|
+
# import is inert against install/PATH skew. Code must land before or
|
|
726
|
+
# with bindings, never after.
|
|
690
727
|
if bundle.handler_events:
|
|
691
728
|
advertised, missing = _handler_missing_events(bundle.handler_events)
|
|
692
729
|
if missing:
|
|
693
|
-
out(f"cannot install {bundle.name}:
|
|
694
|
-
f"advertise events {sorted(missing)}.")
|
|
730
|
+
out(f"cannot install {bundle.name}: PATH's swarph codegraph-hook "
|
|
731
|
+
f"does not advertise events {sorted(missing)}.")
|
|
695
732
|
out(f" handler advertises: {sorted(advertised) or '(none)'}")
|
|
696
|
-
out(" Upgrade swarph
|
|
697
|
-
"then re-run — nothing was written (#830).")
|
|
733
|
+
out(" Upgrade the swarph on PATH so the handler supports these "
|
|
734
|
+
"events, then re-run — nothing was written (#830).")
|
|
698
735
|
return 1
|
|
699
736
|
|
|
700
737
|
command = _hook_command_path(script_dst)
|
|
@@ -7,9 +7,9 @@ design), not by which harness happens to be detected:
|
|
|
7
7
|
* ``claude`` / ``codex`` → ARM-INSTRUCTION: the session-start hook emits
|
|
8
8
|
the watch pipeline (``tail -F inbox.log | dm_notify_filter``) as session
|
|
9
9
|
context so the agent arms it as a background watch.
|
|
10
|
-
* ``cursor`` →
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
* ``cursor`` → ARM-INSTRUCTION, same tail pipeline as claude/codex, written
|
|
11
|
+
to ``~/.cursor/hooks.json``. The wake is the session-armed tail. A
|
|
12
|
+
missing or stale sidecar inbox.log is said loudly in the session context.
|
|
13
13
|
* unknown / undetectable harness → LOUD REFUSAL: nonzero exit, nothing
|
|
14
14
|
written. A silent no-op here would manufacture exactly the
|
|
15
15
|
armed-looking-but-deaf cell this card exists to eliminate.
|
|
@@ -271,9 +271,10 @@ Usage:
|
|
|
271
271
|
|
|
272
272
|
|
|
273
273
|
Installs the silent-wake session-start hook (board card #482). The product
|
|
274
|
-
depends on where the wake lives: claude
|
|
275
|
-
tail -F inbox.log | dm_notify_filter watch)
|
|
276
|
-
|
|
274
|
+
depends on where the wake lives: claude, codex, and cursor get an
|
|
275
|
+
arm-instruction (the tail -F inbox.log | dm_notify_filter watch). Cursor
|
|
276
|
+
emits that pipeline as session context and says loudly when the sidecar
|
|
277
|
+
inbox.log is missing or stale. Unknown harnesses are refused loudly.
|
|
277
278
|
--cell is refused with --scope user (card #527): a baked cell name in a
|
|
278
279
|
box-global file arms one cell's wake for every session on the box and
|
|
279
280
|
silently evicts the last installed cell's. Omit --cell and the hook
|
|
@@ -444,7 +445,7 @@ def run_install_wake_hook(argv: Optional[list[str]] = None) -> int:
|
|
|
444
445
|
product = (
|
|
445
446
|
"arm-instruction (the session-start hook emits the "
|
|
446
447
|
"tail -F inbox.log | dm_notify_filter watch as session context)"
|
|
447
|
-
if harness in ("claude", "codex", "muse")
|
|
448
|
+
if harness in ("claude", "codex", "muse", "cursor")
|
|
448
449
|
else "verify-and-report (the session-start hook checks the "
|
|
449
450
|
"swarph monitor's push sink and says loudly if none exists)"
|
|
450
451
|
)
|