swarph-cli 0.72.16__tar.gz → 0.72.17__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.16/src/swarph_cli.egg-info → swarph_cli-0.72.17}/PKG-INFO +1 -1
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/pyproject.toml +1 -1
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/backends.py +341 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/providers.py +7 -3
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/bench.py +21 -5
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/schedule.py +10 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli.egg-info/SOURCES.txt +1 -0
- swarph_cli-0.72.17/tests/test_1083_openai_decisions.py +376 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_323_mistral_backend.py +12 -1
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_schedule_command.py +31 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/LICENSE +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/README.md +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/setup.cfg +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/codex_cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/signal_score.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/mesh.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/roster.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/rowclear_hook.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/sweep.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/triage.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/guide/GUIDE.md +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/operator/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/operator/__main__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/operator/api.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/operator/cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/operator/config.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/operator/fmt.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/rowclear.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/scrub.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-triage.service +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/triage/__init__.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/triage/backend.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/triage/job.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/triage/owners.json +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/triage/router.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/triage/rows.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli/triage/sensor.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1006_board_publisher.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1006_session_board.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1010_strand_only.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1013_spawn_channel.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1017_muse_tui.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1050_surrogate_wake.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1052_opencode_deaf.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1059_watchdog_unread_env.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1061_roster_cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1064_stuck_sweep.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1065_release.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1066_quiet_wakes.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1073_triage.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1073_triage_board.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1073_wheel_install.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_1075_task_cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_432_rowclear.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_484_codex_queue_sink.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_538_signal_bench.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_729_arm_check_delivery_gap.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_735_dm_mcp_tools.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_739_wake_writer.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_961_cursor_grok_footer.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_961_loud_stop.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_bench_codex_cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_board_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_copilot_membrane.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_group_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_import_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_init_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_main.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mesh_sidecar_muse_sink.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_operator_me.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_scrub.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_security.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_service_app.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_service_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_version_command.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.72.16 → swarph_cli-0.72.17}/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.17
|
|
4
4
|
Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "swarph-cli"
|
|
7
|
-
version = "0.72.
|
|
7
|
+
version = "0.72.17"
|
|
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" }
|
|
@@ -22,6 +22,9 @@ Ships these backends:
|
|
|
22
22
|
- :class:`RuleBackend` — in-process ``rule:<module:callable>``. No credentials.
|
|
23
23
|
- :class:`TypedHttpBackend` — POST to a Jev-compatible ``/v1/systemone``
|
|
24
24
|
(laya-serve). No credentials; per-item latency is the HTTP round trip.
|
|
25
|
+
- :class:`DecisionsBackend` — POST ``/v1/decisions``. Translates a pack's
|
|
26
|
+
``{state, questions}`` body into the Decisions shape. It does not send
|
|
27
|
+
the pack body unchanged.
|
|
25
28
|
"""
|
|
26
29
|
from __future__ import annotations
|
|
27
30
|
|
|
@@ -675,3 +678,341 @@ class HttpBackend:
|
|
|
675
678
|
latency_s=round(time.perf_counter() - t0, 6),
|
|
676
679
|
estimated=tin is None or tout is None,
|
|
677
680
|
)
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
# The Decisions endpoint documents one model. ``provider:openai`` puts the
|
|
684
|
+
# registry name in model_id, so the model is not taken from that string.
|
|
685
|
+
_DECISIONS_MODEL = "gpt-6-luna"
|
|
686
|
+
_PREDICATE_TYPES = {"noul", "yes", "yes-no", "predicate"}
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
def decisions_shape_error(body: Any) -> Optional[str]:
|
|
690
|
+
"""Why a POST /v1/decisions body is not the documented shape, or None.
|
|
691
|
+
|
|
692
|
+
A double more permissive than the real API hid live failures before
|
|
693
|
+
(#1077 / #1078). This is the check that double applies.
|
|
694
|
+
"""
|
|
695
|
+
if not isinstance(body, dict):
|
|
696
|
+
return "body is not an object"
|
|
697
|
+
questions = body.get("questions")
|
|
698
|
+
if not isinstance(questions, list):
|
|
699
|
+
return "questions is not a list"
|
|
700
|
+
for i, question in enumerate(questions):
|
|
701
|
+
if not isinstance(question, dict):
|
|
702
|
+
return f"questions[{i}] is not an object"
|
|
703
|
+
for field in ("name", "type", "instructions"):
|
|
704
|
+
value = question.get(field)
|
|
705
|
+
if not isinstance(value, str) or not value.strip():
|
|
706
|
+
return f"questions[{i}] lacks {field}"
|
|
707
|
+
qtype = question.get("type")
|
|
708
|
+
if qtype == "predicate" and ("choices" in question or "levels" in question):
|
|
709
|
+
return f"questions[{i}] is a predicate carrying choices or levels"
|
|
710
|
+
if qtype == "score":
|
|
711
|
+
levels = question.get("levels")
|
|
712
|
+
if not isinstance(levels, list) or not levels:
|
|
713
|
+
return f"questions[{i}] is a score without levels"
|
|
714
|
+
for j, level in enumerate(levels):
|
|
715
|
+
if (not isinstance(level, dict)
|
|
716
|
+
or not isinstance(level.get("label"), str)
|
|
717
|
+
or not level["label"]
|
|
718
|
+
or not isinstance(level.get("description"), str)):
|
|
719
|
+
return (
|
|
720
|
+
f"questions[{i}].levels[{j}] is not "
|
|
721
|
+
"{label, description}")
|
|
722
|
+
continue
|
|
723
|
+
if qtype != "choice":
|
|
724
|
+
continue
|
|
725
|
+
choices = question.get("choices")
|
|
726
|
+
if not isinstance(choices, list) or not choices:
|
|
727
|
+
return f"questions[{i}] is a choice without choices"
|
|
728
|
+
for j, choice in enumerate(choices):
|
|
729
|
+
if (not isinstance(choice, dict)
|
|
730
|
+
or not isinstance(choice.get("value"), str)
|
|
731
|
+
or not choice["value"]
|
|
732
|
+
or not isinstance(choice.get("description"), str)):
|
|
733
|
+
return (
|
|
734
|
+
f"questions[{i}].choices[{j}] is not "
|
|
735
|
+
"{value, description}")
|
|
736
|
+
return None
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
class StrictDecisionsDouble:
|
|
740
|
+
"""Fake POST /v1/decisions. A body that fails the documented shape is 400.
|
|
741
|
+
|
|
742
|
+
``response`` is the JSON object returned when the body is accepted.
|
|
743
|
+
"""
|
|
744
|
+
|
|
745
|
+
def __init__(self, response: Optional[dict] = None):
|
|
746
|
+
self.response = response if response is not None else {"answers": []}
|
|
747
|
+
self.bodies: list = []
|
|
748
|
+
|
|
749
|
+
def __call__(self, endpoint, headers, raw_body):
|
|
750
|
+
try:
|
|
751
|
+
body = json.loads(raw_body.decode() or "null")
|
|
752
|
+
except (UnicodeDecodeError, json.JSONDecodeError):
|
|
753
|
+
return 400, "Bad Request", b'{"error": "body is not JSON"}'
|
|
754
|
+
self.bodies.append(body)
|
|
755
|
+
reason = decisions_shape_error(body)
|
|
756
|
+
if reason:
|
|
757
|
+
return 400, "Bad Request", json.dumps({"error": reason}).encode()
|
|
758
|
+
return 200, "OK", json.dumps(self.response).encode()
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
def _pack_prompt(prompt: str) -> dict:
|
|
762
|
+
try:
|
|
763
|
+
parsed = json.loads(prompt) if isinstance(prompt, str) else None
|
|
764
|
+
except json.JSONDecodeError:
|
|
765
|
+
parsed = None
|
|
766
|
+
if (not isinstance(parsed, dict) or "state" not in parsed
|
|
767
|
+
or not isinstance(parsed.get("questions"), dict)
|
|
768
|
+
or not parsed["questions"]):
|
|
769
|
+
raise ValueError(
|
|
770
|
+
"decisions prompt must be JSON with state and questions")
|
|
771
|
+
return parsed
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
def _answer_block(parsed: dict) -> tuple[str, dict]:
|
|
775
|
+
questions = parsed["questions"]
|
|
776
|
+
block = questions.get("answer")
|
|
777
|
+
if isinstance(block, dict):
|
|
778
|
+
return "answer", block
|
|
779
|
+
name, block = next(iter(questions.items()))
|
|
780
|
+
if not isinstance(block, dict):
|
|
781
|
+
raise ValueError("decisions question is not an object")
|
|
782
|
+
return str(name), block
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
def _translate_question(name: str, block: dict) -> dict:
|
|
786
|
+
raw_type = block.get("type")
|
|
787
|
+
if raw_type in _PREDICATE_TYPES:
|
|
788
|
+
out_type = "predicate"
|
|
789
|
+
else:
|
|
790
|
+
out_type = raw_type
|
|
791
|
+
question: dict = {"name": name, "type": out_type}
|
|
792
|
+
instructions = block.get("instructions")
|
|
793
|
+
if isinstance(instructions, str):
|
|
794
|
+
question["instructions"] = instructions
|
|
795
|
+
if out_type == "choice" and isinstance(block.get("criteria"), dict):
|
|
796
|
+
question["choices"] = [
|
|
797
|
+
{
|
|
798
|
+
"value": key if isinstance(key, str) else str(key),
|
|
799
|
+
"description": val if isinstance(val, str) else str(val),
|
|
800
|
+
}
|
|
801
|
+
for key, val in block["criteria"].items()
|
|
802
|
+
]
|
|
803
|
+
if out_type == "score" and isinstance(block.get("levels"), list):
|
|
804
|
+
question["levels"] = block["levels"]
|
|
805
|
+
return question
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
def _carries_image(node: Any) -> bool:
|
|
809
|
+
"""True when a pack value is an image part. Packs are text only."""
|
|
810
|
+
if isinstance(node, dict):
|
|
811
|
+
kind = node.get("type")
|
|
812
|
+
if kind in {"input_image", "image", "image_url"}:
|
|
813
|
+
return True
|
|
814
|
+
if "image_url" in node or "input_image" in node:
|
|
815
|
+
return True
|
|
816
|
+
return any(_carries_image(value) for value in node.values())
|
|
817
|
+
if isinstance(node, list):
|
|
818
|
+
return any(_carries_image(value) for value in node)
|
|
819
|
+
return False
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def decisions_request(prompt: str) -> tuple[dict, dict]:
|
|
823
|
+
"""Pack prompt -> (original pack object, POST /v1/decisions body)."""
|
|
824
|
+
parsed = _pack_prompt(prompt)
|
|
825
|
+
if _carries_image(parsed.get("state")) or _carries_image(parsed.get("questions")):
|
|
826
|
+
raise ValueError(
|
|
827
|
+
"decisions input carries an image part; packs are text only")
|
|
828
|
+
name, block = _answer_block(parsed)
|
|
829
|
+
return parsed, {
|
|
830
|
+
"model": _DECISIONS_MODEL,
|
|
831
|
+
"input": json.dumps(parsed["state"]),
|
|
832
|
+
"questions": [_translate_question(name, block)],
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
def _decision_block(payload: dict) -> dict:
|
|
837
|
+
answers = payload.get("answers")
|
|
838
|
+
if not isinstance(answers, list) or not answers:
|
|
839
|
+
raise ValueError("decisions response has no answers")
|
|
840
|
+
named = next(
|
|
841
|
+
(a for a in answers if isinstance(a, dict) and a.get("name") == "answer"),
|
|
842
|
+
None)
|
|
843
|
+
block = named if named is not None else next(
|
|
844
|
+
(a for a in answers if isinstance(a, dict)), None)
|
|
845
|
+
if not isinstance(block, dict):
|
|
846
|
+
raise ValueError("decisions answer is not an object")
|
|
847
|
+
return block
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
def _predicate_label(probability: float, question: Optional[dict],
|
|
851
|
+
threshold: Optional[float]) -> str:
|
|
852
|
+
pos, neg = _noul_labels(question)
|
|
853
|
+
cut = _NOUL_THRESHOLD if threshold is None else threshold
|
|
854
|
+
return pos if probability >= cut else neg
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
class DecisionsBackend:
|
|
858
|
+
"""POST a typed pack item to OpenAI ``/v1/decisions``.
|
|
859
|
+
|
|
860
|
+
The pack body is ``{state, questions: {answer: {type, instructions,
|
|
861
|
+
criteria}}}``. This translates it. ``noul`` and yes-no become a
|
|
862
|
+
predicate. Choice ``criteria`` become ``choices`` of ``{value,
|
|
863
|
+
description}``. The model is ``gpt-6-luna``.
|
|
864
|
+
|
|
865
|
+
``KIND`` stays ``typed`` so a typed pack is not a kind mismatch. The
|
|
866
|
+
registry kind that selects this class is ``decisions``.
|
|
867
|
+
|
|
868
|
+
A predicate probability is P(true), mapped with the same 0.50 cut and
|
|
869
|
+
the same template labels as the laya noul path. A refusal is not a
|
|
870
|
+
label. When the response has no usage object, tokens are an estimate
|
|
871
|
+
of the input and ``estimated`` is true.
|
|
872
|
+
"""
|
|
873
|
+
|
|
874
|
+
KIND = "typed"
|
|
875
|
+
|
|
876
|
+
def __init__(self, *, name: str, base_url: str, path: str,
|
|
877
|
+
auth: Optional[dict] = None, usage: Optional[dict] = None,
|
|
878
|
+
price: Optional[dict] = None, egress: str = "external",
|
|
879
|
+
noul_threshold: Optional[float] = None, transport=None):
|
|
880
|
+
self.name = name
|
|
881
|
+
self.base_url = base_url.rstrip("/")
|
|
882
|
+
self.path = path
|
|
883
|
+
self.auth = auth
|
|
884
|
+
self.usage = usage or {}
|
|
885
|
+
self.price = price
|
|
886
|
+
self.egress = egress
|
|
887
|
+
self.noul_threshold = noul_threshold
|
|
888
|
+
self.transport = transport
|
|
889
|
+
self.calls = 0
|
|
890
|
+
|
|
891
|
+
def missing_creds(self) -> list[str]:
|
|
892
|
+
if not self.auth:
|
|
893
|
+
return []
|
|
894
|
+
env = self.auth.get("env") or ""
|
|
895
|
+
if not os.environ.get(env):
|
|
896
|
+
return [f"{env} (provider {self.name})"]
|
|
897
|
+
return []
|
|
898
|
+
|
|
899
|
+
def secrets(self) -> list[tuple[str, str, str]]:
|
|
900
|
+
if not self.auth:
|
|
901
|
+
return []
|
|
902
|
+
env = self.auth.get("env") or ""
|
|
903
|
+
value = os.environ.get(env) or ""
|
|
904
|
+
if not value:
|
|
905
|
+
return []
|
|
906
|
+
return [(value, env, self.auth.get("scheme") or "")]
|
|
907
|
+
|
|
908
|
+
def generate(self, model_id: str, prompt: str, system: str = "") -> BackendResult:
|
|
909
|
+
t0 = time.perf_counter()
|
|
910
|
+
secrets = self.secrets()
|
|
911
|
+
try:
|
|
912
|
+
parsed, body = decisions_request(prompt)
|
|
913
|
+
input_text = body["input"]
|
|
914
|
+
endpoint = self.base_url + self.path
|
|
915
|
+
headers = {"Content-Type": "application/json"}
|
|
916
|
+
if self.auth:
|
|
917
|
+
env = self.auth["env"]
|
|
918
|
+
value = os.environ.get(env) or ""
|
|
919
|
+
scheme = self.auth.get("scheme") or ""
|
|
920
|
+
token = f"{scheme} {value}".strip() if scheme else value
|
|
921
|
+
headers[self.auth["header"]] = token
|
|
922
|
+
raw_body = json.dumps(body).encode()
|
|
923
|
+
self.calls += 1
|
|
924
|
+
if self.transport is not None:
|
|
925
|
+
status, reason, raw = self.transport(endpoint, headers, raw_body)
|
|
926
|
+
else:
|
|
927
|
+
req = urllib.request.Request(
|
|
928
|
+
endpoint, data=raw_body, headers=headers, method="POST")
|
|
929
|
+
try:
|
|
930
|
+
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
931
|
+
status, reason, raw = resp.status, resp.reason, resp.read()
|
|
932
|
+
except urllib.error.HTTPError as exc:
|
|
933
|
+
status, reason, raw = exc.code, exc.reason, exc.read()
|
|
934
|
+
if status < 200 or status >= 300:
|
|
935
|
+
return BackendResult(
|
|
936
|
+
text="", tokens_in=0, tokens_thought=0, tokens_out=0,
|
|
937
|
+
latency_s=round(time.perf_counter() - t0, 6),
|
|
938
|
+
estimated=False,
|
|
939
|
+
error=_redact(f"HTTP {status} {reason}", secrets))
|
|
940
|
+
payload = json.loads(raw.decode() or "{}")
|
|
941
|
+
if not isinstance(payload, dict):
|
|
942
|
+
raise ValueError("decisions response is not an object")
|
|
943
|
+
block = _decision_block(payload)
|
|
944
|
+
question = _answer_block(parsed)[1]
|
|
945
|
+
text, p_true = _render_decision(
|
|
946
|
+
block, question, self.noul_threshold)
|
|
947
|
+
usage = payload.get("usage") if isinstance(payload.get("usage"), dict) else None
|
|
948
|
+
in_path = self.usage.get("in") or "usage.input_tokens"
|
|
949
|
+
out_path = self.usage.get("out") or "usage.output_tokens"
|
|
950
|
+
tin = _dig(payload, in_path) if usage is not None else None
|
|
951
|
+
tout = _dig(payload, out_path) if usage is not None else None
|
|
952
|
+
if usage is not None and tin is not None:
|
|
953
|
+
estimated = False
|
|
954
|
+
tokens_in = int(tin)
|
|
955
|
+
tokens_out = int(tout or 0)
|
|
956
|
+
else:
|
|
957
|
+
estimated = True
|
|
958
|
+
tokens_in = estimate_tokens(input_text)
|
|
959
|
+
tokens_out = 0
|
|
960
|
+
text = _redact(text, secrets)
|
|
961
|
+
except Exception as exc:
|
|
962
|
+
return BackendResult(
|
|
963
|
+
text="", tokens_in=0, tokens_thought=0, tokens_out=0,
|
|
964
|
+
latency_s=round(time.perf_counter() - t0, 6),
|
|
965
|
+
estimated=False, error=_redact(str(exc), secrets))
|
|
966
|
+
return BackendResult(
|
|
967
|
+
text=text,
|
|
968
|
+
tokens_in=tokens_in,
|
|
969
|
+
tokens_thought=0,
|
|
970
|
+
tokens_out=tokens_out,
|
|
971
|
+
latency_s=round(time.perf_counter() - t0, 6),
|
|
972
|
+
estimated=estimated,
|
|
973
|
+
)
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
def _refusal_reason(block: dict) -> str:
|
|
977
|
+
for key in ("reason", "message", "explanation"):
|
|
978
|
+
value = block.get(key)
|
|
979
|
+
if isinstance(value, str) and value.strip():
|
|
980
|
+
return value
|
|
981
|
+
name = block.get("name")
|
|
982
|
+
if isinstance(name, str) and name.strip():
|
|
983
|
+
return name
|
|
984
|
+
return "refusal"
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
def _render_decision(block: dict, question: dict,
|
|
988
|
+
threshold: Optional[float]) -> tuple[str, Optional[float]]:
|
|
989
|
+
"""Result text, and p_true when the answer was a predicate.
|
|
990
|
+
|
|
991
|
+
A refusal has no ``answer`` key, so the runner scores it as a parse
|
|
992
|
+
failure. The reason stays in the text. Choice keeps the probabilities
|
|
993
|
+
beside a flat answer object the scorer can read.
|
|
994
|
+
"""
|
|
995
|
+
if block.get("type") == "score":
|
|
996
|
+
return json.dumps({"refusal": "unsupported answer type: score"}), None
|
|
997
|
+
if block.get("type") == "refusal":
|
|
998
|
+
return json.dumps({"refusal": _refusal_reason(block)}), None
|
|
999
|
+
if block.get("type") == "predicate" or (
|
|
1000
|
+
block.get("type") is None and "probability" in block):
|
|
1001
|
+
p_true = float(block["probability"])
|
|
1002
|
+
label = _predicate_label(p_true, question, threshold)
|
|
1003
|
+
return json.dumps({"answer": label, "p_true": p_true}), p_true
|
|
1004
|
+
if block.get("type") == "choice" or (
|
|
1005
|
+
block.get("type") is None and "choice" in block):
|
|
1006
|
+
label = block.get("choice")
|
|
1007
|
+
if not isinstance(label, str) or not label:
|
|
1008
|
+
raise ValueError("decisions choice has no label")
|
|
1009
|
+
flat = json.dumps({"answer": label})
|
|
1010
|
+
extra = {}
|
|
1011
|
+
if "probabilities" in block:
|
|
1012
|
+
extra["probabilities"] = block["probabilities"]
|
|
1013
|
+
if "confidence" in block:
|
|
1014
|
+
extra["confidence"] = block["confidence"]
|
|
1015
|
+
if extra:
|
|
1016
|
+
return flat + "\n" + json.dumps(extra), None
|
|
1017
|
+
return flat, None
|
|
1018
|
+
raise ValueError("decisions answer is not a choice, predicate, or refusal")
|
|
@@ -52,14 +52,18 @@ def _check(name: str, entry: dict) -> dict:
|
|
|
52
52
|
if unknown:
|
|
53
53
|
raise RegistryError(f"{name}: unknown keys {sorted(unknown)}")
|
|
54
54
|
kind = entry.get("kind")
|
|
55
|
-
if kind not in {"typed", "semantic"}:
|
|
56
|
-
raise RegistryError(f"{name}: kind must be typed or
|
|
55
|
+
if kind not in {"typed", "semantic", "decisions"}:
|
|
56
|
+
raise RegistryError(f"{name}: kind must be typed, semantic, or decisions")
|
|
57
57
|
base = entry.get("base_url")
|
|
58
58
|
if not isinstance(base, str) or not base.strip():
|
|
59
59
|
raise RegistryError(f"{name}: base_url is required")
|
|
60
60
|
path = entry.get("path")
|
|
61
61
|
if path is None:
|
|
62
|
-
path =
|
|
62
|
+
path = {
|
|
63
|
+
"typed": "/v1/systemone",
|
|
64
|
+
"semantic": "/v1/chat/completions",
|
|
65
|
+
"decisions": "/v1/decisions",
|
|
66
|
+
}[kind]
|
|
63
67
|
if not isinstance(path, str) or not path.startswith("/"):
|
|
64
68
|
raise RegistryError(f"{name}: path must start with /")
|
|
65
69
|
egress = entry.get("egress", "external")
|
|
@@ -32,6 +32,7 @@ from swarph_cli.bench.backends import (
|
|
|
32
32
|
SubscriptionBackend,
|
|
33
33
|
TypedHttpBackend,
|
|
34
34
|
HttpBackend,
|
|
35
|
+
DecisionsBackend,
|
|
35
36
|
)
|
|
36
37
|
from swarph_cli.bench.pack import PackError, load_pack, slugify_theme, validate_schema
|
|
37
38
|
from swarph_cli.bench.providers import RegistryError, load_registry, registry_path
|
|
@@ -221,6 +222,24 @@ def _default_packs_dir() -> Path:
|
|
|
221
222
|
return cwd_packs
|
|
222
223
|
|
|
223
224
|
|
|
225
|
+
def _provider_arm(name: str, entry: dict, noul_threshold):
|
|
226
|
+
"""The registry arm for ``provider:<name>``.
|
|
227
|
+
|
|
228
|
+
``kind = "decisions"`` is the OpenAI Decisions translator. ``typed`` and
|
|
229
|
+
``semantic`` stay on :class:`HttpBackend`, which posts a typed pack body
|
|
230
|
+
unchanged.
|
|
231
|
+
"""
|
|
232
|
+
common = dict(
|
|
233
|
+
name=name, base_url=entry["base_url"], path=entry["path"],
|
|
234
|
+
auth=entry.get("auth"), usage=entry.get("usage"),
|
|
235
|
+
price=entry.get("price"), egress=entry["egress"],
|
|
236
|
+
noul_threshold=noul_threshold,
|
|
237
|
+
)
|
|
238
|
+
if entry["kind"] == "decisions":
|
|
239
|
+
return DecisionsBackend(**common)
|
|
240
|
+
return HttpBackend(kind=entry["kind"], **common)
|
|
241
|
+
|
|
242
|
+
|
|
224
243
|
# ── dispatch ───────────────────────────────────────────────────────────────
|
|
225
244
|
|
|
226
245
|
def _cmd_run(args) -> int:
|
|
@@ -249,11 +268,8 @@ def _cmd_run(args) -> int:
|
|
|
249
268
|
entry = registry.get(spec.provider)
|
|
250
269
|
if entry is None:
|
|
251
270
|
continue
|
|
252
|
-
spec.arm =
|
|
253
|
-
|
|
254
|
-
path=entry["path"], auth=entry.get("auth"), usage=entry.get("usage"),
|
|
255
|
-
price=entry.get("price"), egress=entry["egress"],
|
|
256
|
-
noul_threshold=pack.get("noul_threshold"))
|
|
271
|
+
spec.arm = _provider_arm(
|
|
272
|
+
spec.provider, entry, pack.get("noul_threshold"))
|
|
257
273
|
allow_egress = set(args.allow_egress or [])
|
|
258
274
|
runnable, warnings = preflight(
|
|
259
275
|
specs, backends, pack=pack, allow_egress=allow_egress,
|
|
@@ -54,6 +54,14 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
54
54
|
default=None,
|
|
55
55
|
help="minimum seconds between firings",
|
|
56
56
|
)
|
|
57
|
+
create.add_argument(
|
|
58
|
+
"--deliver",
|
|
59
|
+
choices=["wake", "dm"],
|
|
60
|
+
default="wake",
|
|
61
|
+
help="delivery mode: wake (default) types into a host-local tmux pane; "
|
|
62
|
+
"dm schedules a deferred DM to the target peer — use dm for any "
|
|
63
|
+
"cell not on lab's box (card #1081)",
|
|
64
|
+
)
|
|
57
65
|
add_common_args(create)
|
|
58
66
|
|
|
59
67
|
ls = sub.add_parser("list", help="list scheduled events")
|
|
@@ -188,6 +196,8 @@ def _run_create(args: argparse.Namespace) -> int:
|
|
|
188
196
|
body["out_channel"] = args.out_channel
|
|
189
197
|
if args.min_interval is not None:
|
|
190
198
|
body["min_interval_sec"] = args.min_interval
|
|
199
|
+
if args.deliver == "dm":
|
|
200
|
+
body["deliver"] = "dm"
|
|
191
201
|
status, payload = post_json(f"{base}/scheduled-events", body, token)
|
|
192
202
|
if not _ok(status):
|
|
193
203
|
return _fail("create", status, payload)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.17
|
|
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
|
|
@@ -219,6 +219,7 @@ tests/test_1073_triage.py
|
|
|
219
219
|
tests/test_1073_triage_board.py
|
|
220
220
|
tests/test_1073_wheel_install.py
|
|
221
221
|
tests/test_1075_task_cli.py
|
|
222
|
+
tests/test_1083_openai_decisions.py
|
|
222
223
|
tests/test_124_register_merge.py
|
|
223
224
|
tests/test_126_pending_from_complete.py
|
|
224
225
|
tests/test_132_ensure_monitor_state_dir.py
|