swarph-cli 0.72.0__tar.gz → 0.72.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {swarph_cli-0.72.0/src/swarph_cli.egg-info → swarph_cli-0.72.2}/PKG-INFO +3 -1
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/README.md +2 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/pyproject.toml +1 -1
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/__init__.py +1 -1
- swarph_cli-0.72.2/src/swarph_cli/bench/codex_cli.py +127 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/bench.py +7 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/mesh.py +13 -3
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/spawn.py +57 -23
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/wake_hook_output.py +39 -5
- {swarph_cli-0.72.0 → swarph_cli-0.72.2/src/swarph_cli.egg-info}/PKG-INFO +3 -1
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli.egg-info/SOURCES.txt +3 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_1006_board_publisher.py +37 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_1013_spawn_channel.py +72 -3
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_1017_muse_tui.py +17 -1
- swarph_cli-0.72.2/tests/test_961_loud_stop.py +106 -0
- swarph_cli-0.72.2/tests/test_bench_codex_cli.py +138 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/LICENSE +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/setup.cfg +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/providers.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/signal_score.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/guide/GUIDE.md +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/__init__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/__main__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/api.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/cli.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/config.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/operator/fmt.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_1006_session_board.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_484_codex_queue_sink.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_538_signal_bench.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_729_arm_check_delivery_gap.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_735_dm_mcp_tools.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_739_wake_writer.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_961_cursor_grok_footer.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_board_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_group_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_import_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_init_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_main.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_sidecar_muse_sink.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_operator_me.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_security.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_service_app.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_service_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_version_command.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.72.0 → swarph_cli-0.72.2}/tests/test_windows_waker_installer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.2
|
|
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
|
|
@@ -248,6 +248,8 @@ Task types: `numeric` (rel-err), `categorical` (exact), `ranking` (Kendall-tau),
|
|
|
248
248
|
|
|
249
249
|
`claude-sonnet-5-5:subscription` runs `claude -p` on the Claude subscription when `claude` is on PATH. The argv is fixed: `--max-turns 1`, `--output-format stream-json`, `--strict-mcp-config`, an empty MCP config, `--tools ""`, `--setting-sources ""`. The prompt goes on stdin. The child environment drops `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, and every `SWARPH_CHANNEL*` name. A result whose `apiKeySource` is not `none` is `billing:<source>`, is not scored, and aborts the rest of the run on every arm. A usage limit is retried after 60s and then 300s; the arm then stops with `--ledger`, and the next run skips tasks that already completed. It is not scored as an answer.
|
|
250
250
|
|
|
251
|
+
`gpt-5.6-sol:codex` runs `codex exec` on the ChatGPT subscription when `codex` is on PATH. The argv is fixed: `--json`, `--ephemeral`, `--skip-git-repo-check`, `--ignore-user-config`, `--ignore-rules`, `--sandbox read-only`, in an empty temporary directory. `codex exec` has no system-prompt flag, so the pack's `system` goes on stdin ahead of the prompt. The child environment drops `OPENAI_API_KEY`, `CODEX_API_KEY`, and every `SWARPH_CHANNEL*` name. The billing guard runs **before** the call: the codex stream reports no key source, so the arm reads `auth_mode` from `$CODEX_HOME/auth.json` and refuses with `billing:<mode>` unless it is `chatgpt` (`billing:unknown` when the file cannot be read). Usage limits follow the claude arm: retried, then resumable with `--ledger`, never scored. The isolation flags drop the operator's MCP servers and plugins only. Measured on codex-cli 0.157.0 with a one-line prompt: 15,472 input tokens by default, 14,410 with the flags. The rest is the CLI's own agent instructions, so this arm's input tokens are not comparable with the claude arm's.
|
|
252
|
+
|
|
251
253
|
### `swarph brain-ask` (v0.14.0)
|
|
252
254
|
|
|
253
255
|
Search the **swarph-brain** (gbrain) — the swarm's sovereign $0 semantic-retrieval memory — over MCP. The "does the swarm already know X?" reflex, as a one-shot.
|
|
@@ -199,6 +199,8 @@ Task types: `numeric` (rel-err), `categorical` (exact), `ranking` (Kendall-tau),
|
|
|
199
199
|
|
|
200
200
|
`claude-sonnet-5-5:subscription` runs `claude -p` on the Claude subscription when `claude` is on PATH. The argv is fixed: `--max-turns 1`, `--output-format stream-json`, `--strict-mcp-config`, an empty MCP config, `--tools ""`, `--setting-sources ""`. The prompt goes on stdin. The child environment drops `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, and every `SWARPH_CHANNEL*` name. A result whose `apiKeySource` is not `none` is `billing:<source>`, is not scored, and aborts the rest of the run on every arm. A usage limit is retried after 60s and then 300s; the arm then stops with `--ledger`, and the next run skips tasks that already completed. It is not scored as an answer.
|
|
201
201
|
|
|
202
|
+
`gpt-5.6-sol:codex` runs `codex exec` on the ChatGPT subscription when `codex` is on PATH. The argv is fixed: `--json`, `--ephemeral`, `--skip-git-repo-check`, `--ignore-user-config`, `--ignore-rules`, `--sandbox read-only`, in an empty temporary directory. `codex exec` has no system-prompt flag, so the pack's `system` goes on stdin ahead of the prompt. The child environment drops `OPENAI_API_KEY`, `CODEX_API_KEY`, and every `SWARPH_CHANNEL*` name. The billing guard runs **before** the call: the codex stream reports no key source, so the arm reads `auth_mode` from `$CODEX_HOME/auth.json` and refuses with `billing:<mode>` unless it is `chatgpt` (`billing:unknown` when the file cannot be read). Usage limits follow the claude arm: retried, then resumable with `--ledger`, never scored. The isolation flags drop the operator's MCP servers and plugins only. Measured on codex-cli 0.157.0 with a one-line prompt: 15,472 input tokens by default, 14,410 with the flags. The rest is the CLI's own agent instructions, so this arm's input tokens are not comparable with the claude arm's.
|
|
203
|
+
|
|
202
204
|
### `swarph brain-ask` (v0.14.0)
|
|
203
205
|
|
|
204
206
|
Search the **swarph-brain** (gbrain) — the swarm's sovereign $0 semantic-retrieval memory — over MCP. The "does the swarm already know X?" reflex, as a one-shot.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "swarph-cli"
|
|
7
|
-
version = "0.72.
|
|
7
|
+
version = "0.72.2"
|
|
8
8
|
description = "The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""codex exec transport for the bench `codex` backend. Subscription-only, isolated,
|
|
2
|
+
billing-guarded. Sibling of :mod:`swarph_cli.bench.claude_cli`, and it differs from it
|
|
3
|
+
in three places that matter.
|
|
4
|
+
|
|
5
|
+
Measured 2026-10-02, codex-cli 0.157.0, macOS arm64, a one-line prompt:
|
|
6
|
+
default config 15,472 input tokens
|
|
7
|
+
--ignore-user-config --ignore-rules 14,410 input tokens
|
|
8
|
+
The isolation flags remove the operator's MCP servers and plugins, and that is all
|
|
9
|
+
they remove. The floor is the CLI's own agent instructions: there is no flag here that
|
|
10
|
+
turns `codex exec` into a bare completion, so this arm does not reach the ~421 tokens
|
|
11
|
+
`claude -p --tools ""` does. Compare arms on quality and on OUTPUT tokens; the input
|
|
12
|
+
count carries this fixed load.
|
|
13
|
+
|
|
14
|
+
THE BILLING GUARD IS CHECKED BEFORE THE CALL, NOT READ FROM THE RESULT. The claude
|
|
15
|
+
stream names its key source (`apiKeySource`). The codex stream names nothing about
|
|
16
|
+
billing, so the guard reads `auth_mode` from `$CODEX_HOME/auth.json` and refuses to
|
|
17
|
+
call unless it is `chatgpt`. A file that cannot be read is `billing:unknown`: not
|
|
18
|
+
knowing is a refusal, never a pass.
|
|
19
|
+
|
|
20
|
+
NO SYSTEM-PROMPT FLAG. `codex exec` has none, so the pack's `system` is sent on stdin
|
|
21
|
+
ahead of the prompt, separated by a blank line.
|
|
22
|
+
|
|
23
|
+
The child runs in an empty temporary directory under a read-only sandbox, so there is
|
|
24
|
+
no repository for the agent to read and nothing it can write.
|
|
25
|
+
"""
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import json
|
|
29
|
+
import os
|
|
30
|
+
import subprocess
|
|
31
|
+
import tempfile
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
from typing import Optional
|
|
34
|
+
|
|
35
|
+
from swarph_cli.bench.claude_cli import CliResult
|
|
36
|
+
|
|
37
|
+
_STRIP_EXACT = ("OPENAI_API_KEY", "CODEX_API_KEY")
|
|
38
|
+
_RATE = ("usage limit", "rate limit", "429", "too many requests")
|
|
39
|
+
_SUBSCRIPTION_MODE = "chatgpt"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def build_argv(model_id: str) -> list:
|
|
43
|
+
"""Fixed argv. The trailing `-` reads the prompt from stdin, never from argv."""
|
|
44
|
+
return ["codex", "exec", "--model", model_id, "--json", "--ephemeral",
|
|
45
|
+
"--skip-git-repo-check", "--ignore-user-config", "--ignore-rules",
|
|
46
|
+
"--sandbox", "read-only", "-"]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def clean_env(env: dict) -> dict:
|
|
50
|
+
"""Drop billing keys and every SWARPH_CHANNEL* name, including ones not listed yet."""
|
|
51
|
+
return {
|
|
52
|
+
k: v for k, v in env.items()
|
|
53
|
+
if k not in _STRIP_EXACT and not k.startswith("SWARPH_CHANNEL")
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def codex_home(env: dict) -> Path:
|
|
58
|
+
return Path(env.get("CODEX_HOME") or (Path.home() / ".codex"))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def auth_mode(home: Path) -> Optional[str]:
|
|
62
|
+
"""`auth_mode` from auth.json, or None when it cannot be read. None is not a pass."""
|
|
63
|
+
try:
|
|
64
|
+
data = json.loads((home / "auth.json").read_text(encoding="utf-8"))
|
|
65
|
+
except (OSError, ValueError):
|
|
66
|
+
return None
|
|
67
|
+
mode = data.get("auth_mode") if isinstance(data, dict) else None
|
|
68
|
+
return mode if isinstance(mode, str) and mode else None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def stdin_text(prompt: str, system: str) -> str:
|
|
72
|
+
return f"{system}\n\n{prompt}" if system else prompt
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _is_rate(text: str) -> bool:
|
|
76
|
+
low = (text or "").lower()
|
|
77
|
+
return any(t in low for t in _RATE)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def parse_stream(lines, stderr: str = "", key: Optional[str] = _SUBSCRIPTION_MODE) -> CliResult:
|
|
81
|
+
"""JSONL from `codex exec --json` -> CliResult.
|
|
82
|
+
|
|
83
|
+
The answer is the LAST agent_message. Usage is the LAST turn.completed: that event
|
|
84
|
+
carries the thread's running total, so adding two of them would double-count.
|
|
85
|
+
A usage limit is `rate_limit` whether it arrives as an event or on stderr — the
|
|
86
|
+
runner retries that string and never scores it as an answer.
|
|
87
|
+
"""
|
|
88
|
+
text, usage, failure = None, None, None
|
|
89
|
+
for ln in lines:
|
|
90
|
+
try:
|
|
91
|
+
e = json.loads(ln)
|
|
92
|
+
except Exception:
|
|
93
|
+
continue
|
|
94
|
+
if not isinstance(e, dict):
|
|
95
|
+
continue
|
|
96
|
+
kind = e.get("type")
|
|
97
|
+
if kind == "item.completed":
|
|
98
|
+
item = e.get("item") or {}
|
|
99
|
+
if item.get("type") == "agent_message" and isinstance(item.get("text"), str):
|
|
100
|
+
text = item["text"]
|
|
101
|
+
elif kind == "turn.completed":
|
|
102
|
+
usage = e.get("usage") or {}
|
|
103
|
+
elif kind in ("error", "turn.failed"):
|
|
104
|
+
detail = e.get("message") or e.get("error") or ""
|
|
105
|
+
failure = (kind, detail if isinstance(detail, str) else json.dumps(detail))
|
|
106
|
+
u = usage or {}
|
|
107
|
+
tin, tout = int(u.get("input_tokens") or 0), int(u.get("output_tokens") or 0)
|
|
108
|
+
if failure is not None:
|
|
109
|
+
err = "rate_limit" if _is_rate(failure[1]) or _is_rate(stderr) else f"cli_error:{failure[0]}"
|
|
110
|
+
return CliResult("", tin, tout, key, None, error=err)
|
|
111
|
+
if text is None or usage is None:
|
|
112
|
+
err = "rate_limit" if _is_rate(stderr) else "no_result"
|
|
113
|
+
return CliResult("", tin, tout, key, None, error=err)
|
|
114
|
+
return CliResult(text, tin, tout, key, None)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def call(model_id: str, prompt: str, system: str, *, runner=subprocess.run,
|
|
118
|
+
timeout: int = 300, env: Optional[dict] = None) -> CliResult:
|
|
119
|
+
source = dict(os.environ) if env is None else dict(env)
|
|
120
|
+
mode = auth_mode(codex_home(source))
|
|
121
|
+
if mode != _SUBSCRIPTION_MODE:
|
|
122
|
+
# Refused before any call: nothing was spent, and nothing is scored.
|
|
123
|
+
return CliResult("", 0, 0, mode, None, error=f"billing:{mode or 'unknown'}")
|
|
124
|
+
with tempfile.TemporaryDirectory(prefix="swarph-bench-codex-") as cwd:
|
|
125
|
+
p = runner(build_argv(model_id), input=stdin_text(prompt, system), capture_output=True,
|
|
126
|
+
text=True, env=clean_env(source), timeout=timeout, cwd=cwd)
|
|
127
|
+
return parse_stream((p.stdout or "").splitlines(), p.stderr or "", key=mode)
|
|
@@ -61,10 +61,17 @@ def _default_backends() -> dict[str, Backend]:
|
|
|
61
61
|
if shutil.which("claude"):
|
|
62
62
|
from swarph_cli.bench.claude_cli import call as claude_call
|
|
63
63
|
subscription = SubscriptionBackend(call_fn=claude_call)
|
|
64
|
+
# codex on PATH wires its own lane to an isolated `codex exec`. Its own key,
|
|
65
|
+
# like mistral: `id:subscription` keeps meaning claude.
|
|
66
|
+
codex = SubscriptionBackend()
|
|
67
|
+
if shutil.which("codex"):
|
|
68
|
+
from swarph_cli.bench.codex_cli import call as codex_call
|
|
69
|
+
codex = SubscriptionBackend(call_fn=codex_call)
|
|
64
70
|
return {
|
|
65
71
|
"metered": MeteredGeminiBackend(),
|
|
66
72
|
"mistral": MeteredMistralBackend(),
|
|
67
73
|
"subscription": subscription,
|
|
74
|
+
"codex": codex,
|
|
68
75
|
"rule": RuleBackend(),
|
|
69
76
|
"signal": SignalBackend(),
|
|
70
77
|
"typed-http": TypedHttpBackend(),
|
|
@@ -2302,6 +2302,9 @@ _OPENCODE_WAKE_PROMPT = "check mesh: swarph_dm_unread"
|
|
|
2302
2302
|
# Grok's TUI has the same shape (#715, grok 1.0.41): no push channel, so
|
|
2303
2303
|
# the wake is one line naming the pull tool and no DM body.
|
|
2304
2304
|
_GROK_WAKE_PROMPT = "check mesh: swarph_dm_unread"
|
|
2305
|
+
# Muse 1.4.1 has no push channel either. The wake names the pull tool,
|
|
2306
|
+
# same text the grok and opencode sinks inject.
|
|
2307
|
+
_MUSE_WAKE_PROMPT = "check mesh: swarph_dm_unread"
|
|
2305
2308
|
# A finished turn keeps its ▣ header and adds a duration.
|
|
2306
2309
|
# Short turns read `· 3.3s` (drop-on-meta-edge, 1.18.33, card #961 post
|
|
2307
2310
|
# 54557). A longer idle turn reads `· 3m 4s` (opencode pane, 2026-09-29
|
|
@@ -2439,7 +2442,7 @@ def _only_wake_text(content: str) -> bool:
|
|
|
2439
2442
|
human's line.
|
|
2440
2443
|
"""
|
|
2441
2444
|
rest = content
|
|
2442
|
-
for prompt in (_GROK_WAKE_PROMPT, _OPENCODE_WAKE_PROMPT, _WAKE_PROMPT):
|
|
2445
|
+
for prompt in (_MUSE_WAKE_PROMPT, _GROK_WAKE_PROMPT, _OPENCODE_WAKE_PROMPT, _WAKE_PROMPT):
|
|
2443
2446
|
rest = rest.replace(prompt, "")
|
|
2444
2447
|
return rest.strip() == ""
|
|
2445
2448
|
|
|
@@ -2611,8 +2614,13 @@ def _is_muse_rule(line: str) -> bool:
|
|
|
2611
2614
|
|
|
2612
2615
|
|
|
2613
2616
|
def _is_muse_status(line: str) -> bool:
|
|
2614
|
-
"""
|
|
2615
|
-
|
|
2617
|
+
"""A status row under the lower rule.
|
|
2618
|
+
|
|
2619
|
+
Measured muse-spark is ``model · effort · path · YOLO``. An echo
|
|
2620
|
+
provider is ``echo · ~/x · YOLO``. The anchor is two or more `` · ``
|
|
2621
|
+
separators, not the model name. A model switch must not blind the sink.
|
|
2622
|
+
"""
|
|
2623
|
+
return line.count(" · ") >= 2
|
|
2616
2624
|
|
|
2617
2625
|
|
|
2618
2626
|
def _is_muse_composer_row(lines: list[str], index: int) -> bool:
|
|
@@ -2853,6 +2861,8 @@ def _wake_prompt_for(lines: Optional[list[str]]) -> str:
|
|
|
2853
2861
|
return _GROK_WAKE_PROMPT
|
|
2854
2862
|
if lines and _is_opencode_pane(lines):
|
|
2855
2863
|
return _OPENCODE_WAKE_PROMPT
|
|
2864
|
+
if lines and _is_muse_pane(lines):
|
|
2865
|
+
return _MUSE_WAKE_PROMPT
|
|
2856
2866
|
return _WAKE_PROMPT
|
|
2857
2867
|
|
|
2858
2868
|
|
|
@@ -393,14 +393,21 @@ _CLAUDE_CHANNELS = frozenset({"allowlisted", "dev"})
|
|
|
393
393
|
_MUSE_CHANNELS = frozenset({"ingress"})
|
|
394
394
|
|
|
395
395
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
396
|
+
# Providers whose spawn consumes $SWARPH_CHANNEL. Anything else ignores an
|
|
397
|
+
# inherited value (a Claude cell's shell carries allowlisted; spawning grok
|
|
398
|
+
# from it must not refuse). Measured 2026-10-01: 0.72.0 blamed cell.yaml
|
|
399
|
+
# for that env and exited on grok-researcher.yaml, which has no channel field.
|
|
400
|
+
_ENV_CHANNEL_PROVIDERS = frozenset({"claude", "muse"})
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def _channel_where(source: str) -> str:
|
|
404
|
+
"""Name the place the mode came from. An env value must not read as cell.yaml."""
|
|
405
|
+
if source == "env":
|
|
406
|
+
return "SWARPH_CHANNEL"
|
|
407
|
+
return "cell.yaml: 'channel'"
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def _field_channel(cell: Cell) -> str:
|
|
404
411
|
extra = getattr(cell, "extra", None) or {}
|
|
405
412
|
value = extra.get("channel", "") if isinstance(extra, dict) else ""
|
|
406
413
|
if value is None:
|
|
@@ -413,64 +420,88 @@ def _resolve_channel(cell: Cell) -> str:
|
|
|
413
420
|
return value
|
|
414
421
|
|
|
415
422
|
|
|
416
|
-
def
|
|
423
|
+
def _resolve_channel(cell: Cell) -> tuple[str, str]:
|
|
424
|
+
"""Effective channel mode and where it came from.
|
|
425
|
+
|
|
426
|
+
``$SWARPH_CHANNEL`` wins (incl. "off") only for providers that support
|
|
427
|
+
it: claude (allowlisted/dev/off) and muse (ingress/off). Other providers
|
|
428
|
+
ignore the inherited env, as before 0.72.0, and the cell.yaml field is
|
|
429
|
+
still read. Returns ``(mode, source)`` with source ``env``, ``cell.yaml``,
|
|
430
|
+
or ``""``. Never launches anything; callers validate.
|
|
431
|
+
"""
|
|
432
|
+
env_mode = os.environ.get("SWARPH_CHANNEL") or ""
|
|
433
|
+
provider = getattr(cell, "provider", None)
|
|
434
|
+
# No provider attribute: the stamp probes construct a name-only cell.
|
|
435
|
+
# Those are claude-shaped; the env still applies.
|
|
436
|
+
if env_mode and (provider is None or provider in _ENV_CHANNEL_PROVIDERS):
|
|
437
|
+
return env_mode, "env"
|
|
438
|
+
field = _field_channel(cell)
|
|
439
|
+
return field, ("cell.yaml" if field else "")
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def _channel_marketplace_dir(source: str = "cell.yaml") -> Path:
|
|
417
443
|
"""Install location of the `swarph` Claude marketplace (the allowlist).
|
|
418
444
|
|
|
419
445
|
Resolved through ~/.claude/plugins/known_marketplaces.json, the same
|
|
420
446
|
registry claude reads — never a second hardcoded copy that drifts.
|
|
447
|
+
``source`` names env vs cell.yaml so a missing registry is not blamed
|
|
448
|
+
on the file when the mode came from ``$SWARPH_CHANNEL``.
|
|
421
449
|
"""
|
|
450
|
+
where = _channel_where(source)
|
|
422
451
|
registry = Path.home() / ".claude" / "plugins" / "known_marketplaces.json"
|
|
423
452
|
try:
|
|
424
453
|
data = json.loads(registry.read_text(encoding="utf-8"))
|
|
425
454
|
except (OSError, ValueError) as exc:
|
|
426
455
|
raise CellError(
|
|
427
|
-
f"
|
|
456
|
+
f"{where} 'allowlisted' needs the swarph marketplace, "
|
|
428
457
|
f"but its registry is unreadable: {registry} ({exc})."
|
|
429
458
|
) from exc
|
|
430
459
|
try:
|
|
431
460
|
location = data["swarph"]["installLocation"]
|
|
432
461
|
except (KeyError, TypeError) as exc:
|
|
433
462
|
raise CellError(
|
|
434
|
-
f"
|
|
463
|
+
f"{where} 'allowlisted' needs the swarph marketplace, "
|
|
435
464
|
f"but it is not registered in {registry}."
|
|
436
465
|
) from exc
|
|
437
466
|
path = Path(location)
|
|
438
467
|
if not path.is_dir():
|
|
439
468
|
raise CellError(
|
|
440
|
-
f"
|
|
469
|
+
f"{where} 'allowlisted' needs the swarph marketplace "
|
|
441
470
|
f"at {path}, which is not a directory."
|
|
442
471
|
)
|
|
443
472
|
return path
|
|
444
473
|
|
|
445
474
|
|
|
446
|
-
def _validate_channel(cell: Cell, mode: str) -> str:
|
|
475
|
+
def _validate_channel(cell: Cell, mode: str, source: str = "cell.yaml") -> str:
|
|
447
476
|
"""Fail closed on any channel mode the provider cannot consume.
|
|
448
477
|
|
|
449
478
|
Returns the mode unchanged. "" and "off" are valid everywhere (no-op).
|
|
450
|
-
Raises CellError naming the
|
|
451
|
-
|
|
479
|
+
Raises CellError naming the source (``SWARPH_CHANNEL`` or the cell.yaml
|
|
480
|
+
field) and the file, for a missing marketplace, so the operator fixes
|
|
481
|
+
config, never debugs a deaf cell.
|
|
452
482
|
"""
|
|
453
483
|
if mode in ("", "off"):
|
|
454
484
|
return mode
|
|
485
|
+
where = _channel_where(source)
|
|
455
486
|
provider = cell.provider
|
|
456
487
|
if provider == "claude":
|
|
457
488
|
if mode not in _CLAUDE_CHANNELS:
|
|
458
489
|
raise CellError(
|
|
459
|
-
f"
|
|
490
|
+
f"{where} {mode!r} is not valid for provider "
|
|
460
491
|
f"'claude'. Valid values: {sorted(_CLAUDE_CHANNELS | {'off'})}."
|
|
461
492
|
)
|
|
462
493
|
if mode == "allowlisted":
|
|
463
|
-
_channel_marketplace_dir()
|
|
494
|
+
_channel_marketplace_dir(source)
|
|
464
495
|
return mode
|
|
465
496
|
if provider == "muse":
|
|
466
497
|
if mode not in _MUSE_CHANNELS:
|
|
467
498
|
raise CellError(
|
|
468
|
-
f"
|
|
499
|
+
f"{where} {mode!r} is not valid for provider "
|
|
469
500
|
f"'muse'. Valid values: {sorted(_MUSE_CHANNELS | {'off'})}."
|
|
470
501
|
)
|
|
471
502
|
return mode
|
|
472
503
|
raise CellError(
|
|
473
|
-
f"
|
|
504
|
+
f"{where} {mode!r} is only valid for providers "
|
|
474
505
|
f"'claude' and 'muse'; provider is {provider!r}."
|
|
475
506
|
)
|
|
476
507
|
|
|
@@ -498,7 +529,8 @@ def _build_claude_argv(
|
|
|
498
529
|
argv.extend(["--append-system-prompt", starter])
|
|
499
530
|
|
|
500
531
|
argv.extend(passthrough)
|
|
501
|
-
mode =
|
|
532
|
+
mode, source = _resolve_channel(cell)
|
|
533
|
+
mode = _validate_channel(cell, mode, source)
|
|
502
534
|
if mode == "allowlisted":
|
|
503
535
|
argv.extend(["--channels", "plugin:swarph@swarph"])
|
|
504
536
|
elif mode == "dev":
|
|
@@ -545,7 +577,7 @@ def _spawn_env_base(cell: Cell) -> dict[str, str]:
|
|
|
545
577
|
env = scrub_env_for_subprocess()
|
|
546
578
|
env["SWARPH_SPAWN"] = "1"
|
|
547
579
|
env["SWARPH_SELF"] = cell.name
|
|
548
|
-
mode = _resolve_channel(cell)
|
|
580
|
+
mode, _source = _resolve_channel(cell)
|
|
549
581
|
# NOTE: the marketplace/validity gate lives in _validate_channel, which
|
|
550
582
|
# _build_claude_argv (and the muse env builder) run. This base stays a
|
|
551
583
|
# pure reflection of the resolved mode so every provider's env agrees.
|
|
@@ -587,7 +619,8 @@ def _muse_env(cell: Cell) -> dict[str, str]:
|
|
|
587
619
|
run_spawn choke point; the mode read here agrees with it by construction.
|
|
588
620
|
"""
|
|
589
621
|
env = _claude_env(cell)
|
|
590
|
-
|
|
622
|
+
mode, _source = _resolve_channel(cell)
|
|
623
|
+
if mode == "ingress":
|
|
591
624
|
env["MUSE_EXPERIMENTAL_EXTERNAL_AGENT_INGRESS"] = "on"
|
|
592
625
|
return env
|
|
593
626
|
|
|
@@ -3308,7 +3341,8 @@ def run_spawn(argv: Optional[list[str]] = None) -> int:
|
|
|
3308
3341
|
# must not leave a minted sidecar behind). One choke point for every
|
|
3309
3342
|
# provider; builders below see only validated modes.
|
|
3310
3343
|
try:
|
|
3311
|
-
|
|
3344
|
+
mode, source = _resolve_channel(cell)
|
|
3345
|
+
_validate_channel(cell, mode, source)
|
|
3312
3346
|
except CellError as exc:
|
|
3313
3347
|
print(f"swarph spawn: {exc}", file=sys.stderr)
|
|
3314
3348
|
return 1
|
|
@@ -10,6 +10,11 @@ distinction is not WHICH harness, it is WHERE THE WAKE LIVES):
|
|
|
10
10
|
* ``claude`` / ``codex`` → ARM-INSTRUCTION. The wake lives in the harness:
|
|
11
11
|
emit the watch pipeline (tail -F inbox.log | dm_notify_filter) as
|
|
12
12
|
additionalContext so the agent arms it as a background watch.
|
|
13
|
+
* ``grok`` → the same arm instruction, with the pipeline wrapped in
|
|
14
|
+
``timeout -k 5s 590m`` and one ``[MESH WAKE EXPIRED]`` line. Grok caps a
|
|
15
|
+
background task at 10h (measured 2026-10-01); the wrapper exits 10
|
|
16
|
+
minutes early so the stop is a wake, not a SIGKILL the session never
|
|
17
|
+
sees. The duration is one unit: coreutils timeout rejects ``9h50m``.
|
|
13
18
|
* ``cursor`` → ARM-INSTRUCTION, same pipeline as claude/codex, emitted in
|
|
14
19
|
Cursor's ``additional_context`` envelope (the ``~/.cursor/hooks.json``
|
|
15
20
|
sessionStart shape). The wake is the session-armed tail. A missing or
|
|
@@ -43,7 +48,7 @@ from swarph_cli.cell import (
|
|
|
43
48
|
load_cell,
|
|
44
49
|
)
|
|
45
50
|
|
|
46
|
-
_ARM_HARNESSES = ("claude", "codex", "muse", "opencode")
|
|
51
|
+
_ARM_HARNESSES = ("claude", "codex", "muse", "opencode", "grok")
|
|
47
52
|
_INJECT_HARNESSES = ("antigravity",)
|
|
48
53
|
_VERIFY_HARNESSES = ("cursor",)
|
|
49
54
|
_KNOWN_HARNESSES = _ARM_HARNESSES + _INJECT_HARNESSES + _VERIFY_HARNESSES
|
|
@@ -52,6 +57,12 @@ _KNOWN_HARNESSES = _ARM_HARNESSES + _INJECT_HARNESSES + _VERIFY_HARNESSES
|
|
|
52
57
|
_FILTER_MODULE = "swarph_cli.scripts.dm_notify_filter"
|
|
53
58
|
# Same default as `swarph monitor arm-check --max-age-s` (15 minutes).
|
|
54
59
|
_INBOX_MAX_AGE_S = 15 * 60
|
|
60
|
+
_EXPIRED_LINE = "[MESH WAKE EXPIRED] re-arm the inbox tail now"
|
|
61
|
+
# Harnesses whose background tasks die at a cap. The wrapper is that cap
|
|
62
|
+
# minus 10 minutes, as one unit coreutils timeout accepts. Grok's cap is
|
|
63
|
+
# 10h (grok-researcher, 2026-10-01); "9h50m" is rejected as an invalid
|
|
64
|
+
# time interval on this box.
|
|
65
|
+
_HARNESS_TIMEOUT = {"grok": "590m"}
|
|
55
66
|
|
|
56
67
|
|
|
57
68
|
def _read_stdin_payload() -> dict[str, Any]:
|
|
@@ -233,7 +244,27 @@ def _provenance_note(source: str) -> str:
|
|
|
233
244
|
return f" (identity from {source})"
|
|
234
245
|
|
|
235
246
|
|
|
236
|
-
def
|
|
247
|
+
def _watch_pipeline(inbox: Path, interpreter: str) -> str:
|
|
248
|
+
return f'tail -n 0 -F "{inbox}" | "{interpreter}" -u -m {_FILTER_MODULE}'
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _loud_stop(pipeline: str, duration: str) -> str:
|
|
252
|
+
"""Self-expire before the harness kills the task, then say so.
|
|
253
|
+
|
|
254
|
+
``-k 5s`` sends KILL if the tail is still up after TERM. A single-quoted
|
|
255
|
+
``sh -c`` matches the pipeline, which quotes paths with double quotes.
|
|
256
|
+
"""
|
|
257
|
+
return (
|
|
258
|
+
f"timeout -k 5s {duration} sh -c '{pipeline}'; "
|
|
259
|
+
f"echo '{_EXPIRED_LINE}'"
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _arm_instruction(
|
|
264
|
+
cell_name: Optional[str],
|
|
265
|
+
source: str = "unresolved",
|
|
266
|
+
harness: str = "",
|
|
267
|
+
) -> str:
|
|
237
268
|
interpreter = sys.executable
|
|
238
269
|
if not cell_name:
|
|
239
270
|
# CANNOT-RESOLVE is a LOUD REFUSAL, never a placeholder (card #527
|
|
@@ -259,8 +290,10 @@ def _arm_instruction(cell_name: Optional[str], source: str = "unresolved") -> st
|
|
|
259
290
|
f'"{interpreter}" -m swarph_cli monitor arm-check '
|
|
260
291
|
f'--as {cell_name} --path "{inbox}"'
|
|
261
292
|
)
|
|
262
|
-
|
|
263
|
-
|
|
293
|
+
pipeline = _watch_pipeline(inbox, interpreter)
|
|
294
|
+
cap = _HARNESS_TIMEOUT.get(harness)
|
|
295
|
+
if cap:
|
|
296
|
+
pipeline = _loud_stop(pipeline, cap)
|
|
264
297
|
return (
|
|
265
298
|
"[swarph silent-wake] This cell's DM wake lives in THIS harness. "
|
|
266
299
|
"BEFORE arming, refuse a missing/stale inbox.log (#729):\n"
|
|
@@ -490,7 +523,8 @@ def run_wake_hook_output(argv: Optional[list[str]] = None) -> int:
|
|
|
490
523
|
)
|
|
491
524
|
if harness in _ARM_HARNESSES:
|
|
492
525
|
return _emit(
|
|
493
|
-
{"context": _arm_instruction(cell_name, cell_source)},
|
|
526
|
+
{"context": _arm_instruction(cell_name, cell_source, harness)},
|
|
527
|
+
harness=harness,
|
|
494
528
|
)
|
|
495
529
|
return _emit(
|
|
496
530
|
{"context": _verify_report(cell_name, cell_source)}, harness=harness
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.2
|
|
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
|
|
@@ -248,6 +248,8 @@ Task types: `numeric` (rel-err), `categorical` (exact), `ranking` (Kendall-tau),
|
|
|
248
248
|
|
|
249
249
|
`claude-sonnet-5-5:subscription` runs `claude -p` on the Claude subscription when `claude` is on PATH. The argv is fixed: `--max-turns 1`, `--output-format stream-json`, `--strict-mcp-config`, an empty MCP config, `--tools ""`, `--setting-sources ""`. The prompt goes on stdin. The child environment drops `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, and every `SWARPH_CHANNEL*` name. A result whose `apiKeySource` is not `none` is `billing:<source>`, is not scored, and aborts the rest of the run on every arm. A usage limit is retried after 60s and then 300s; the arm then stops with `--ledger`, and the next run skips tasks that already completed. It is not scored as an answer.
|
|
250
250
|
|
|
251
|
+
`gpt-5.6-sol:codex` runs `codex exec` on the ChatGPT subscription when `codex` is on PATH. The argv is fixed: `--json`, `--ephemeral`, `--skip-git-repo-check`, `--ignore-user-config`, `--ignore-rules`, `--sandbox read-only`, in an empty temporary directory. `codex exec` has no system-prompt flag, so the pack's `system` goes on stdin ahead of the prompt. The child environment drops `OPENAI_API_KEY`, `CODEX_API_KEY`, and every `SWARPH_CHANNEL*` name. The billing guard runs **before** the call: the codex stream reports no key source, so the arm reads `auth_mode` from `$CODEX_HOME/auth.json` and refuses with `billing:<mode>` unless it is `chatgpt` (`billing:unknown` when the file cannot be read). Usage limits follow the claude arm: retried, then resumable with `--ledger`, never scored. The isolation flags drop the operator's MCP servers and plugins only. Measured on codex-cli 0.157.0 with a one-line prompt: 15,472 input tokens by default, 14,410 with the flags. The rest is the CLI's own agent instructions, so this arm's input tokens are not comparable with the claude arm's.
|
|
252
|
+
|
|
251
253
|
### `swarph brain-ask` (v0.14.0)
|
|
252
254
|
|
|
253
255
|
Search the **swarph-brain** (gbrain) — the swarm's sovereign $0 semantic-retrieval memory — over MCP. The "does the swarm already know X?" reflex, as a one-shot.
|
|
@@ -40,6 +40,7 @@ src/swarph_cli.egg-info/top_level.txt
|
|
|
40
40
|
src/swarph_cli/bench/__init__.py
|
|
41
41
|
src/swarph_cli/bench/backends.py
|
|
42
42
|
src/swarph_cli/bench/claude_cli.py
|
|
43
|
+
src/swarph_cli/bench/codex_cli.py
|
|
43
44
|
src/swarph_cli/bench/pack.py
|
|
44
45
|
src/swarph_cli/bench/prices.py
|
|
45
46
|
src/swarph_cli/bench/providers.py
|
|
@@ -270,6 +271,7 @@ tests/test_959_venv_interpreter.py
|
|
|
270
271
|
tests/test_960_channel.py
|
|
271
272
|
tests/test_960_ensure_monitor_heartbeat.py
|
|
272
273
|
tests/test_961_cursor_grok_footer.py
|
|
274
|
+
tests/test_961_loud_stop.py
|
|
273
275
|
tests/test_963_plugin_manifest.py
|
|
274
276
|
tests/test_964_channel_cell.py
|
|
275
277
|
tests/test_965_mesh_wait.py
|
|
@@ -284,6 +286,7 @@ tests/test_artifact_tool.py
|
|
|
284
286
|
tests/test_artifact_uri.py
|
|
285
287
|
tests/test_bench_backends.py
|
|
286
288
|
tests/test_bench_claude_cli.py
|
|
289
|
+
tests/test_bench_codex_cli.py
|
|
287
290
|
tests/test_bench_command.py
|
|
288
291
|
tests/test_bench_pack.py
|
|
289
292
|
tests/test_bench_prices.py
|
|
@@ -309,3 +309,40 @@ def test_live_entry_drops_a_closed_row_and_a_failed_read_sends_nothing(tmp_path,
|
|
|
309
309
|
assert all(argv[:3] != ["swarph", "mesh", "send"] for argv in calls)
|
|
310
310
|
assert all("inbox" not in argv for argv in calls)
|
|
311
311
|
assert not hasattr(pub, "commander_replies")
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def test_in_session_marker_sets_the_flag_and_strips_the_title():
|
|
315
|
+
"""An accept starting [commander][in-session] Re-login... builds
|
|
316
|
+
in_session=true and a title without the marker. A plain [commander]
|
|
317
|
+
row with no deploy or hard-gate words stays false. On main the title
|
|
318
|
+
keeps [in-session] and the flag stays false.
|
|
319
|
+
"""
|
|
320
|
+
pub = _load()
|
|
321
|
+
listing = (ROOT / "tests" / "fixtures" / "session-board" / "listagents-lab.txt").read_text(encoding="utf-8")
|
|
322
|
+
rows = pub.commander_rows([
|
|
323
|
+
{
|
|
324
|
+
"id": 5,
|
|
325
|
+
"holder": "droplet",
|
|
326
|
+
"card_id": 1006,
|
|
327
|
+
"state": "open",
|
|
328
|
+
"accept": "[commander][in-session] Re-login to the board | PASS=the commander re-logs",
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"id": 6,
|
|
332
|
+
"holder": "droplet",
|
|
333
|
+
"card_id": 1006,
|
|
334
|
+
"state": "open",
|
|
335
|
+
"accept": "[commander] Note the weather today | PASS=nothing",
|
|
336
|
+
},
|
|
337
|
+
])
|
|
338
|
+
board = pub.build_board.build(listing, rows)
|
|
339
|
+
questions = [
|
|
340
|
+
q for sess in board["sessions"] if sess["name"] == "droplet" for q in sess["questions"]
|
|
341
|
+
]
|
|
342
|
+
marked = next(q for q in questions if q["obligation"] == 5)
|
|
343
|
+
plain = next(q for q in questions if q["obligation"] == 6)
|
|
344
|
+
assert marked["in_session"] is True
|
|
345
|
+
assert marked["title"] == "Re-login to the board"
|
|
346
|
+
assert "[in-session]" not in marked["title"]
|
|
347
|
+
assert "[commander]" not in marked["title"]
|
|
348
|
+
assert plain["in_session"] is False
|