swarph-cli 0.72.33__tar.gz → 0.72.35__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.33/src/swarph_cli.egg-info → swarph_cli-0.72.35}/PKG-INFO +1 -1
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/pyproject.toml +1 -1
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/__init__.py +1 -1
- swarph_cli-0.72.35/src/swarph_cli/commands/commander.py +95 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/mcp_server.py +83 -9
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/guide/GUIDE.md +7 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/main.py +2 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli.egg-info/SOURCES.txt +4 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1065_release.py +2 -0
- swarph_cli-0.72.35/tests/test_1286_dm_unread_cursor.py +192 -0
- swarph_cli-0.72.35/tests/test_1297_commander.py +60 -0
- swarph_cli-0.72.35/tests/test_1301_restart_skew.py +64 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_735_dm_mcp_tools.py +4 -1
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/LICENSE +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/README.md +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/setup.cfg +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/codex_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/providers.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/signal_score.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/mesh.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/roster.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/rowclear_hook.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/sweep.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/triage.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/duplicate_session.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/launchd/swarph-codex-outbox.plist +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/launchd/swarph-codex-outbox.timer.plist +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/launchd/swarph-monitor.plist +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/launchd/swarph-watchdog.plist +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/launchd/swarph-watchdog.timer.plist +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/launchd_render.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/operator/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/operator/__main__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/operator/api.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/operator/cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/operator/config.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/operator/fmt.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/quota_sync.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/rowclear.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/scrub.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-triage.service +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/the_ten.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/triage/__init__.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/triage/backend.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/triage/job.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/triage/owners.json +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/triage/router.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/triage/rows.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli/triage/sensor.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1006_board_publisher.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1006_session_board.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1010_strand_only.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1013_spawn_channel.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1017_muse_tui.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1034_copy_mode.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1050_surrogate_wake.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1052_opencode_deaf.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1059_watchdog_unread_env.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1061_roster_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1064_stuck_sweep.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1066_quiet_wakes.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1068_structured_accept_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1071_quota_sync.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1073_triage.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1073_triage_board.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1073_wheel_install.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1075_task_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1083_openai_decisions.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1144_cell_yaml_github.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1197_commander_taps.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1203_swarph_me_refusal.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1206_offer_question.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1214_egress.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1219_egress_probe.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1221_quota_windows.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1222_maybe_start_cap.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1228_quota_reach.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1243_the_ten.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1248_ship_price_table.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1250_price_cache.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1256_commander_wake.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1261_mcp_install.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1262_wake_followups.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1265_wake_note.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1269_triage_label.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_1278_dreaming_reach.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_432_rowclear.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_484_codex_queue_sink.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_513_duplicate_session.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_538_signal_bench.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_729_arm_check_delivery_gap.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_739_wake_writer.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_931_board_search.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_935_deadline_clock.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_961_cursor_grok_footer.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_961_loud_stop.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_bench_codex_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_board_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_copilot_membrane.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_copilot_pane_reader.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_group_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_import_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_init_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_launchd_units.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_main.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mesh_sidecar_muse_sink.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_operator_me.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_scrub.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_security.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_service_app.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_service_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_version_command.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.72.33 → swarph_cli-0.72.35}/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.35
|
|
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.35"
|
|
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,95 @@
|
|
|
1
|
+
"""``swarph commander`` — propose a decision or an action. Card #1297.
|
|
2
|
+
|
|
3
|
+
The cell asks. The commander decides, from the desktop, with a credential
|
|
4
|
+
this command never holds. ``ask`` posts a decision. ``request`` posts
|
|
5
|
+
``merge_pr`` or ``release_finish``. An MCP tool for the same queue is a
|
|
6
|
+
later card.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
from swarph_cli.commands import mesh as mesh_cmd
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def ask_body(question: str, options: list[str], card: int | None) -> dict:
|
|
17
|
+
body: dict = {"type": "decision", "question": question, "options": options}
|
|
18
|
+
if card is not None:
|
|
19
|
+
body["card_id"] = card
|
|
20
|
+
return body
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def request_body(kind: str, *, repo: str | None, pr: int | None,
|
|
24
|
+
head: str | None, version: str | None, card: int | None) -> dict:
|
|
25
|
+
body: dict = {"type": kind, "pr": pr, "head_sha": head}
|
|
26
|
+
if kind == "merge_pr":
|
|
27
|
+
body["repo"] = repo
|
|
28
|
+
if kind == "release_finish":
|
|
29
|
+
body["version"] = version
|
|
30
|
+
if card is not None:
|
|
31
|
+
body["card_id"] = card
|
|
32
|
+
return body
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
36
|
+
p = argparse.ArgumentParser(prog="swarph commander")
|
|
37
|
+
sub = p.add_subparsers(dest="command", required=True)
|
|
38
|
+
|
|
39
|
+
ask = sub.add_parser("ask", help="propose a decision")
|
|
40
|
+
mesh_cmd._add_common(ask)
|
|
41
|
+
ask.add_argument("--question", required=True)
|
|
42
|
+
ask.add_argument("--options", default=None,
|
|
43
|
+
help="comma-separated choices, e.g. yes,no")
|
|
44
|
+
ask.add_argument("--card", type=int, default=None)
|
|
45
|
+
|
|
46
|
+
req = sub.add_parser("request", help="propose merge_pr or release_finish")
|
|
47
|
+
mesh_cmd._add_common(req)
|
|
48
|
+
req.add_argument("type", choices=["merge_pr", "release_finish"])
|
|
49
|
+
req.add_argument("--repo", default=None)
|
|
50
|
+
req.add_argument("--pr", type=int, default=None)
|
|
51
|
+
req.add_argument("--head", default=None)
|
|
52
|
+
req.add_argument("--version", default=None)
|
|
53
|
+
req.add_argument("--card", type=int, default=None)
|
|
54
|
+
return p
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _options(raw: str | None) -> list[str]:
|
|
58
|
+
if not raw:
|
|
59
|
+
return []
|
|
60
|
+
return [part.strip() for part in raw.split(",") if part.strip()]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def run_commander(argv: list[str]) -> int:
|
|
64
|
+
args = _build_parser().parse_args(argv)
|
|
65
|
+
try:
|
|
66
|
+
self_name = mesh_cmd._resolve_self_name(args.self_name)
|
|
67
|
+
token = mesh_cmd._resolve_token(self_name, args.token_file)
|
|
68
|
+
except RuntimeError as exc:
|
|
69
|
+
print(f"swarph commander: {exc}", file=sys.stderr)
|
|
70
|
+
return 1
|
|
71
|
+
gw = args.gateway.rstrip("/")
|
|
72
|
+
if args.command == "ask":
|
|
73
|
+
body = ask_body(args.question, _options(args.options), args.card)
|
|
74
|
+
else:
|
|
75
|
+
if args.pr is None or not args.head:
|
|
76
|
+
print("swarph commander request: --pr and --head are required",
|
|
77
|
+
file=sys.stderr)
|
|
78
|
+
return 2
|
|
79
|
+
if args.type == "merge_pr" and not args.repo:
|
|
80
|
+
print("swarph commander request: merge_pr requires --repo",
|
|
81
|
+
file=sys.stderr)
|
|
82
|
+
return 2
|
|
83
|
+
if args.type == "release_finish" and not args.version:
|
|
84
|
+
print("swarph commander request: release_finish requires --version",
|
|
85
|
+
file=sys.stderr)
|
|
86
|
+
return 2
|
|
87
|
+
body = request_body(args.type, repo=args.repo, pr=args.pr, head=args.head,
|
|
88
|
+
version=args.version, card=args.card)
|
|
89
|
+
status, payload = mesh_cmd._post_json(f"{gw}/commander/requests", body, token)
|
|
90
|
+
if status in (200, 201):
|
|
91
|
+
print(f"commander request #{payload.get('id')} {payload.get('status')}")
|
|
92
|
+
return 0
|
|
93
|
+
detail = payload.get("detail") if isinstance(payload, dict) else payload
|
|
94
|
+
print(f"swarph commander: {detail}", file=sys.stderr)
|
|
95
|
+
return 1
|
|
@@ -33,9 +33,11 @@ without the SDK installed.
|
|
|
33
33
|
from __future__ import annotations
|
|
34
34
|
|
|
35
35
|
import argparse
|
|
36
|
+
import datetime
|
|
36
37
|
import importlib.metadata
|
|
37
38
|
import json
|
|
38
39
|
import os
|
|
40
|
+
import time
|
|
39
41
|
import urllib.error
|
|
40
42
|
import urllib.request
|
|
41
43
|
|
|
@@ -301,17 +303,82 @@ def _dm_error(exc_or_text) -> dict:
|
|
|
301
303
|
return {"error": str(exc_or_text), "messages": [], "n": 0}
|
|
302
304
|
|
|
303
305
|
|
|
306
|
+
# One poll records the cursor at the newest id it saw. The earlier DMs in that
|
|
307
|
+
# poll are behind the cursor and were not delivered. They stay visible while
|
|
308
|
+
# they are younger than this (card #1286). Older than this, they are hidden
|
|
309
|
+
# and counted.
|
|
310
|
+
_DM_GRACE_S = 24 * 60 * 60
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _created_epoch(message: dict) -> float | None:
|
|
314
|
+
raw = message.get("created_at")
|
|
315
|
+
if raw is None or raw == "":
|
|
316
|
+
return None
|
|
317
|
+
if isinstance(raw, bool):
|
|
318
|
+
return None
|
|
319
|
+
if isinstance(raw, (int, float)):
|
|
320
|
+
return float(raw)
|
|
321
|
+
text = str(raw).strip()
|
|
322
|
+
if text.endswith("Z"):
|
|
323
|
+
text = text[:-1] + "+00:00"
|
|
324
|
+
try:
|
|
325
|
+
return datetime.datetime.fromisoformat(text).timestamp()
|
|
326
|
+
except ValueError:
|
|
327
|
+
return None
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _younger_than_grace(message: dict, now: float) -> bool:
|
|
331
|
+
ts = _created_epoch(message)
|
|
332
|
+
if ts is None:
|
|
333
|
+
return False
|
|
334
|
+
return (now - ts) < _DM_GRACE_S
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def _observation_cursor(who: str) -> int:
|
|
338
|
+
"""The monitor's last_msg_id for this cell. Missing or unreadable is 0.
|
|
339
|
+
|
|
340
|
+
Peek only: nothing here writes cursor.json or marks a message read.
|
|
341
|
+
"""
|
|
342
|
+
path = _mesh._default_sidecar_state_dir(who) / "cursor.json"
|
|
343
|
+
try:
|
|
344
|
+
return int(_mesh._read_cursor(path).get("last_msg_id") or 0)
|
|
345
|
+
except (TypeError, ValueError):
|
|
346
|
+
return 0
|
|
347
|
+
|
|
348
|
+
|
|
304
349
|
def _dm_unread(self_name: str | None = None) -> dict:
|
|
305
|
-
"""
|
|
306
|
-
|
|
307
|
-
`
|
|
350
|
+
"""Unread DMs the monitor has not yet delivered, full bodies, one call.
|
|
351
|
+
|
|
352
|
+
`read_at` is still the reply-ack (#735). The observation cursor advances
|
|
353
|
+
before delivery, so a DM with `id == last_msg_id` was observed and must
|
|
354
|
+
be returned (card #1286). One poll records the cursor at the newest id,
|
|
355
|
+
so the earlier DMs in that batch are behind it. A DM younger than 24 h
|
|
356
|
+
(`created_at`) is never hidden for that reason. A DM strictly behind the
|
|
357
|
+
cursor and not younger than 24 h stays hidden, and `hidden_stale` counts
|
|
358
|
+
those read_at-null DMs. Peek semantics: marks nothing read and does not
|
|
359
|
+
advance the cursor. Above DM_CEILING the oldest DM_CEILING are returned
|
|
360
|
+
in full and `not_returned` says how many remain.
|
|
361
|
+
"""
|
|
308
362
|
try:
|
|
309
363
|
who, gw, tok = _dm_session(self_name)
|
|
310
364
|
st, d = _mesh._http_get_json(
|
|
311
365
|
f"{gw}/messages?to={who}&unread_only=true&limit={DM_GATEWAY_WINDOW}", tok)
|
|
312
366
|
if not (200 <= st < 300):
|
|
313
367
|
return _dm_error(f"gateway {st}: {d.get('detail', d) if isinstance(d, dict) else d}")
|
|
314
|
-
|
|
368
|
+
raw = sorted(d.get("messages", []), key=lambda m: int(m.get("id") or 0))
|
|
369
|
+
last_id = _observation_cursor(who)
|
|
370
|
+
now = time.time()
|
|
371
|
+
msgs = []
|
|
372
|
+
hidden_stale = 0
|
|
373
|
+
for message in raw:
|
|
374
|
+
if message.get("from_node") == who:
|
|
375
|
+
continue
|
|
376
|
+
mid = int(message.get("id") or 0)
|
|
377
|
+
if mid >= last_id or _younger_than_grace(message, now):
|
|
378
|
+
msgs.append(message)
|
|
379
|
+
continue
|
|
380
|
+
if message.get("read_at") in (None, ""):
|
|
381
|
+
hidden_stale += 1
|
|
315
382
|
keep = msgs[:DM_CEILING]
|
|
316
383
|
return {
|
|
317
384
|
"self": who,
|
|
@@ -319,7 +386,8 @@ def _dm_unread(self_name: str | None = None) -> dict:
|
|
|
319
386
|
"n": len(keep),
|
|
320
387
|
"unread_seen": len(msgs),
|
|
321
388
|
"not_returned": len(msgs) - len(keep),
|
|
322
|
-
"
|
|
389
|
+
"hidden_stale": hidden_stale,
|
|
390
|
+
"window_full": len(raw) >= DM_GATEWAY_WINDOW,
|
|
323
391
|
}
|
|
324
392
|
except Exception as exc: # loud, never an empty inbox
|
|
325
393
|
return _dm_error(f"{type(exc).__name__}: {exc}")
|
|
@@ -473,10 +541,16 @@ try:
|
|
|
473
541
|
|
|
474
542
|
@mcp.tool()
|
|
475
543
|
def swarph_dm_unread() -> dict:
|
|
476
|
-
"""
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
544
|
+
"""Unread DMs for this cell, FULL bodies, ONE call (card #735, card #1286).
|
|
545
|
+
|
|
546
|
+
Peek semantics: nothing is marked read and the monitor cursor is not moved.
|
|
547
|
+
The DM whose id equals the cursor was observed and not yet delivered, so
|
|
548
|
+
it is returned. A DM strictly behind the cursor is still returned when
|
|
549
|
+
its created_at is younger than 24 h. Older than that, it stays hidden
|
|
550
|
+
and hidden_stale counts it. No paging parameter.
|
|
551
|
+
Replying with swarph_dm_reply is the ack.
|
|
552
|
+
`not_returned` > 0 means more than the ceiling were unread and the oldest
|
|
553
|
+
were returned in full."""
|
|
480
554
|
return _dm_unread()
|
|
481
555
|
|
|
482
556
|
@mcp.tool()
|
|
@@ -328,6 +328,13 @@ swarph board cards say <id> --to <peer> --content-file <path>
|
|
|
328
328
|
swarph board cards ask <id> "<what is owed>" --step <step> --holder <peer> # mint an obligation
|
|
329
329
|
```
|
|
330
330
|
|
|
331
|
+
Propose a decision or an action. The commander decides it from the desktop; this
|
|
332
|
+
command only posts the request (card #1297).
|
|
333
|
+
|
|
334
|
+
`swarph commander ask --question "..." --options a,b --card N`
|
|
335
|
+
`swarph commander request merge_pr --repo ORG/REPO --pr N --head SHA --card N`
|
|
336
|
+
`swarph commander request release_finish --version V --pr N --head SHA --card N`
|
|
337
|
+
|
|
331
338
|
**Obligations** exist because "waiting on a review" in someone's prose is not a fact
|
|
332
339
|
anyone can query. `ask` writes a row: who owes what, since when. It closes when the holder
|
|
333
340
|
**replies in the thread** -- which is why the distinction between `reply` and `send` above
|
|
@@ -108,6 +108,8 @@ _VERB_HANDLERS: dict[str, str] = {
|
|
|
108
108
|
"peer-reply-drain": "swarph_cli.commands.peer_reply_drain.run_peer_reply_drain",
|
|
109
109
|
"monitor": "swarph_cli.commands.monitor.run_monitor",
|
|
110
110
|
"board": "swarph_cli.commands.board.run_board",
|
|
111
|
+
# card #1297: propose a decision or an action. The commander decides.
|
|
112
|
+
"commander": "swarph_cli.commands.commander.run_commander",
|
|
111
113
|
"group": "swarph_cli.commands.group.run_group",
|
|
112
114
|
"rights": "swarph_cli.commands.group.run_rights",
|
|
113
115
|
"roster": "swarph_cli.commands.roster.run_roster",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.35
|
|
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
|
|
@@ -82,6 +82,7 @@ src/swarph_cli/commands/codegraph.py
|
|
|
82
82
|
src/swarph_cli/commands/codegraph_hook.py
|
|
83
83
|
src/swarph_cli/commands/codex_hook_output.py
|
|
84
84
|
src/swarph_cli/commands/codex_waker.py
|
|
85
|
+
src/swarph_cli/commands/commander.py
|
|
85
86
|
src/swarph_cli/commands/compress.py
|
|
86
87
|
src/swarph_cli/commands/daemon.py
|
|
87
88
|
src/swarph_cli/commands/dreaming.py
|
|
@@ -252,6 +253,9 @@ tests/test_1265_wake_note.py
|
|
|
252
253
|
tests/test_1269_triage_label.py
|
|
253
254
|
tests/test_126_pending_from_complete.py
|
|
254
255
|
tests/test_1278_dreaming_reach.py
|
|
256
|
+
tests/test_1286_dm_unread_cursor.py
|
|
257
|
+
tests/test_1297_commander.py
|
|
258
|
+
tests/test_1301_restart_skew.py
|
|
255
259
|
tests/test_132_ensure_monitor_state_dir.py
|
|
256
260
|
tests/test_138_memory_navigate.py
|
|
257
261
|
tests/test_139_tool_probe.py
|
|
@@ -146,6 +146,7 @@ esac
|
|
|
146
146
|
env["RELEASE_UNITS_FILE"] = str(units)
|
|
147
147
|
env["RELEASE_VERIFY_CMD"] = "true"
|
|
148
148
|
env["RELEASE_PYPI_SLEEP"] = "0"
|
|
149
|
+
env["RELEASE_INSTALL_EPOCH"] = "1"
|
|
149
150
|
proc = _run(["bash", str(RELEASE), "--resume", "9.9.9"], env)
|
|
150
151
|
assert proc.returncode == 0, proc.stderr + proc.stdout
|
|
151
152
|
text = log.read_text()
|
|
@@ -201,6 +202,7 @@ esac
|
|
|
201
202
|
env["RELEASE_UNITS_FILE"] = str(units)
|
|
202
203
|
env["RELEASE_VERIFY_CMD"] = "true"
|
|
203
204
|
env["RELEASE_PYPI_SLEEP"] = "0"
|
|
205
|
+
env["RELEASE_INSTALL_EPOCH"] = "1"
|
|
204
206
|
if extra_env:
|
|
205
207
|
env.update(extra_env)
|
|
206
208
|
proc = _run(["bash", str(RELEASE), "--resume", "9.9.9"], env)
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""Card #1286: swarph_dm_unread agrees with the monitor cursor.
|
|
2
|
+
|
|
3
|
+
A DM with read_at NULL that the cursor has already passed is not unread.
|
|
4
|
+
The call is a peek: cursor.json is not rewritten and nothing is marked read.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import datetime
|
|
9
|
+
import json
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
from swarph_cli.commands import mesh
|
|
13
|
+
from swarph_cli.commands import mcp_server
|
|
14
|
+
from swarph_cli.dm_frame import frame_text
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_1286_stale_unread_behind_the_cursor_is_not_new(monkeypatch, tmp_path):
|
|
18
|
+
monkeypatch.setattr(
|
|
19
|
+
mcp_server, "_dm_session", lambda self_name=None: ("lab-ovh", "http://gw", "tok"),
|
|
20
|
+
)
|
|
21
|
+
state = tmp_path / "mesh-sidecar"
|
|
22
|
+
state.mkdir()
|
|
23
|
+
# Path.home() ignores HOME on Windows, so point the sidecar helper itself.
|
|
24
|
+
monkeypatch.setattr(mcp_server._mesh, "_default_sidecar_state_dir", lambda who: state)
|
|
25
|
+
cursor = state / "cursor.json"
|
|
26
|
+
cursor.write_text(json.dumps({"last_msg_id": 200}), encoding="utf-8")
|
|
27
|
+
before = cursor.read_bytes()
|
|
28
|
+
rows = [
|
|
29
|
+
{"id": 100, "from_node": "cursor-lin", "to_node": "lab-ovh", "kind": "status",
|
|
30
|
+
"content": "STALE1286", "read_at": None},
|
|
31
|
+
{"id": 200, "from_node": "cursor-lin", "to_node": "lab-ovh", "kind": "status",
|
|
32
|
+
"content": "BOUNDARY1286", "read_at": None},
|
|
33
|
+
{"id": 300, "from_node": "cursor-lin", "to_node": "lab-ovh", "kind": "status",
|
|
34
|
+
"content": "NEW1286 full body", "read_at": None},
|
|
35
|
+
{"id": 400, "from_node": "lab-ovh", "to_node": "cursor-lin", "kind": "status",
|
|
36
|
+
"content": "SELF1286", "read_at": None},
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
def fake_get(url, token, **kw):
|
|
40
|
+
assert "unread_only=true" in url
|
|
41
|
+
return 200, {"messages": list(reversed(rows)), "n": len(rows)}
|
|
42
|
+
|
|
43
|
+
monkeypatch.setattr(mcp_server._mesh, "_http_get_json", fake_get)
|
|
44
|
+
out = mcp_server._dm_unread()
|
|
45
|
+
# 200 equals the cursor: observed, not yet delivered, so it is returned.
|
|
46
|
+
# 100 is strictly behind and stays hidden.
|
|
47
|
+
assert [m["id"] for m in out["messages"]] == [200, 300]
|
|
48
|
+
assert out["messages"][1]["content"] == frame_text(rows[2])
|
|
49
|
+
assert "NEW1286 full body" in out["messages"][1]["content"]
|
|
50
|
+
assert "BOUNDARY1286" in out["messages"][0]["content"]
|
|
51
|
+
assert "STALE1286" not in json.dumps(out)
|
|
52
|
+
assert "SELF1286" not in json.dumps(out)
|
|
53
|
+
assert out["n"] == 2 and out["not_returned"] == 0
|
|
54
|
+
# 100 is behind the cursor and has no created_at, so it is not within 24 h.
|
|
55
|
+
assert out.get("hidden_stale") == 1
|
|
56
|
+
assert cursor.read_bytes() == before
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_1286_monitor_iteration_then_unread_returns_the_woken_dm(monkeypatch, tmp_path):
|
|
60
|
+
"""One real monitor iteration observes a new DM, then unread still returns it.
|
|
61
|
+
|
|
62
|
+
The cursor advances before delivery, so the woken id equals last_msg_id.
|
|
63
|
+
On 74347164 unread uses a strict `>` and the DM is gone.
|
|
64
|
+
"""
|
|
65
|
+
state_dir = tmp_path / "mesh-sidecar"
|
|
66
|
+
state_dir.mkdir()
|
|
67
|
+
(state_dir / "cursor.json").write_text(
|
|
68
|
+
json.dumps({"last_msg_id": 100}), encoding="utf-8")
|
|
69
|
+
monkeypatch.setattr(mcp_server._mesh, "_default_sidecar_state_dir", lambda who: state_dir)
|
|
70
|
+
monkeypatch.setattr(
|
|
71
|
+
mcp_server, "_dm_session", lambda self_name=None: ("lab-ovh", "http://gw", "tok"),
|
|
72
|
+
)
|
|
73
|
+
woken = {
|
|
74
|
+
"id": 501, "from_node": "cursor-lin", "to_node": "lab-ovh", "kind": "question",
|
|
75
|
+
"content": "WOKEN1286 full body", "read_at": None,
|
|
76
|
+
}
|
|
77
|
+
stale = {
|
|
78
|
+
"id": 50, "from_node": "cursor-lin", "to_node": "lab-ovh", "kind": "status",
|
|
79
|
+
"content": "BEHIND1286", "read_at": None,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
def fake_get(url, token, **kw):
|
|
83
|
+
return 200, {"messages": [stale, woken]}
|
|
84
|
+
|
|
85
|
+
monkeypatch.setattr(mesh, "_http_get_json", fake_get)
|
|
86
|
+
state = mesh.MonitorState(
|
|
87
|
+
self_name="lab-ovh",
|
|
88
|
+
state_dir=state_dir,
|
|
89
|
+
gateway="http://gw",
|
|
90
|
+
token="tok",
|
|
91
|
+
sinks=[mesh.parse_sink("none")],
|
|
92
|
+
)
|
|
93
|
+
mesh._monitor_iteration(state, poll_channels=False)
|
|
94
|
+
out = mcp_server._dm_unread()
|
|
95
|
+
ids = [m["id"] for m in out["messages"]]
|
|
96
|
+
assert ids == [501]
|
|
97
|
+
assert "WOKEN1286 full body" in out["messages"][0]["content"]
|
|
98
|
+
assert "BEHIND1286" not in json.dumps(out)
|
|
99
|
+
assert out.get("hidden_stale") == 1
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _iso(offset_s: float) -> str:
|
|
103
|
+
stamp = datetime.datetime.fromtimestamp(time.time() + offset_s, datetime.timezone.utc)
|
|
104
|
+
return stamp.isoformat()
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _row(mid: int, content: str, created_at: str) -> dict:
|
|
108
|
+
return {
|
|
109
|
+
"id": mid, "from_node": "cursor-lin", "to_node": "lab-ovh", "kind": "question",
|
|
110
|
+
"content": content, "read_at": None, "created_at": created_at,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _monitor(monkeypatch, tmp_path, rows, *, polls: int = 1, windows=None):
|
|
115
|
+
state_dir = tmp_path / "mesh-sidecar"
|
|
116
|
+
state_dir.mkdir()
|
|
117
|
+
(state_dir / "cursor.json").write_text(
|
|
118
|
+
json.dumps({"last_msg_id": 100}), encoding="utf-8")
|
|
119
|
+
monkeypatch.setattr(mcp_server._mesh, "_default_sidecar_state_dir", lambda who: state_dir)
|
|
120
|
+
monkeypatch.setattr(
|
|
121
|
+
mcp_server, "_dm_session", lambda self_name=None: ("lab-ovh", "http://gw", "tok"),
|
|
122
|
+
)
|
|
123
|
+
seen = {"n": 0}
|
|
124
|
+
|
|
125
|
+
def fake_get(url, token, **kw):
|
|
126
|
+
if "unread_only" in url:
|
|
127
|
+
return 200, {"messages": list(rows)}
|
|
128
|
+
if windows is None:
|
|
129
|
+
return 200, {"messages": list(rows)}
|
|
130
|
+
index = min(seen["n"], len(windows) - 1)
|
|
131
|
+
seen["n"] += 1
|
|
132
|
+
wanted = windows[index]
|
|
133
|
+
return 200, {"messages": [row for row in rows if row["id"] in wanted]}
|
|
134
|
+
|
|
135
|
+
monkeypatch.setattr(mesh, "_http_get_json", fake_get)
|
|
136
|
+
state = mesh.MonitorState(
|
|
137
|
+
self_name="lab-ovh",
|
|
138
|
+
state_dir=state_dir,
|
|
139
|
+
gateway="http://gw",
|
|
140
|
+
token="tok",
|
|
141
|
+
sinks=[mesh.parse_sink("none")],
|
|
142
|
+
)
|
|
143
|
+
for _ in range(polls):
|
|
144
|
+
mesh._monitor_iteration(state, poll_channels=False)
|
|
145
|
+
return mcp_server._dm_unread(), state
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def test_1286_one_poll_observing_three_returns_all_three(monkeypatch, tmp_path):
|
|
149
|
+
"""One poll records the cursor at the newest id. The two earlier DMs are young."""
|
|
150
|
+
young = _iso(0)
|
|
151
|
+
rows = [
|
|
152
|
+
_row(501, "ONE1286", young),
|
|
153
|
+
_row(502, "TWO1286", young),
|
|
154
|
+
_row(503, "THREE1286", young),
|
|
155
|
+
]
|
|
156
|
+
out, state = _monitor(monkeypatch, tmp_path, rows)
|
|
157
|
+
assert state.observed["last_msg_id"] == 503
|
|
158
|
+
assert [m["id"] for m in out["messages"]] == [501, 502, 503]
|
|
159
|
+
assert out.get("hidden_stale") == 0
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_1286_three_polls_then_unread_returns_all_three(monkeypatch, tmp_path):
|
|
163
|
+
"""A busy host calls the tool after three polls, one new DM each."""
|
|
164
|
+
young = _iso(-60)
|
|
165
|
+
rows = [
|
|
166
|
+
_row(501, "POLL1286a", young),
|
|
167
|
+
_row(502, "POLL1286b", young),
|
|
168
|
+
_row(503, "POLL1286c", young),
|
|
169
|
+
]
|
|
170
|
+
out, state = _monitor(
|
|
171
|
+
monkeypatch, tmp_path, rows, polls=3, windows=([501], [501, 502], [501, 502, 503]),
|
|
172
|
+
)
|
|
173
|
+
assert state.observed["last_msg_id"] == 503
|
|
174
|
+
assert [m["id"] for m in out["messages"]] == [501, 502, 503]
|
|
175
|
+
assert "POLL1286a" in out["messages"][0]["content"]
|
|
176
|
+
assert out.get("hidden_stale") == 0
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def test_1286_old_dm_behind_the_cursor_is_hidden_and_counted(monkeypatch, tmp_path):
|
|
180
|
+
young = _iso(0)
|
|
181
|
+
old = _iso(-(25 * 60 * 60))
|
|
182
|
+
rows = [
|
|
183
|
+
_row(50, "OLD1286", old),
|
|
184
|
+
_row(80, "YOUNGBEHIND1286", young),
|
|
185
|
+
_row(501, "FRESH1286", young),
|
|
186
|
+
]
|
|
187
|
+
out, state = _monitor(monkeypatch, tmp_path, rows)
|
|
188
|
+
assert state.observed["last_msg_id"] == 501
|
|
189
|
+
assert "OLD1286" not in json.dumps(out)
|
|
190
|
+
assert out.get("hidden_stale") == 1
|
|
191
|
+
assert [m["id"] for m in out["messages"]] == [80, 501]
|
|
192
|
+
assert "YOUNGBEHIND1286" in out["messages"][0]["content"]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""card #1297 — `swarph commander ask` and `swarph commander request`.
|
|
2
|
+
|
|
3
|
+
On current main the verb is unknown, so these assert exit 0 and fail there.
|
|
4
|
+
"""
|
|
5
|
+
from swarph_cli.main import main
|
|
6
|
+
|
|
7
|
+
HEAD = "a" * 40
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _patch(monkeypatch):
|
|
11
|
+
posted = {}
|
|
12
|
+
|
|
13
|
+
def fake_post(url, body, token, timeout=10.0):
|
|
14
|
+
posted["url"] = url
|
|
15
|
+
posted["body"] = body
|
|
16
|
+
posted["token"] = token
|
|
17
|
+
return 201, {"id": 7, "status": "pending"}
|
|
18
|
+
|
|
19
|
+
monkeypatch.setattr("swarph_cli.commands.mesh._post_json", fake_post)
|
|
20
|
+
monkeypatch.setattr("swarph_cli.commands.mesh._resolve_token", lambda *a, **k: "tok")
|
|
21
|
+
return posted
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_commander_ask_posts_a_decision(monkeypatch):
|
|
25
|
+
posted = _patch(monkeypatch)
|
|
26
|
+
rc = main(["commander", "ask", "--question", "ship it?", "--options", "yes,no",
|
|
27
|
+
"--card", "1297", "--gateway", "http://127.0.0.1:9", "--as", "cursor-lin"])
|
|
28
|
+
assert rc == 0
|
|
29
|
+
assert posted["url"].endswith("/commander/requests")
|
|
30
|
+
assert posted["body"] == {
|
|
31
|
+
"type": "decision",
|
|
32
|
+
"question": "ship it?",
|
|
33
|
+
"options": ["yes", "no"],
|
|
34
|
+
"card_id": 1297,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_commander_request_posts_merge_and_release(monkeypatch):
|
|
39
|
+
posted = _patch(monkeypatch)
|
|
40
|
+
rc = main(["commander", "request", "merge_pr",
|
|
41
|
+
"--repo", "BrainSurfing-tech/swarph-cli", "--pr", "12",
|
|
42
|
+
"--head", HEAD, "--card", "1297",
|
|
43
|
+
"--gateway", "http://127.0.0.1:9", "--as", "cursor-lin"])
|
|
44
|
+
assert rc == 0
|
|
45
|
+
assert posted["body"]["type"] == "merge_pr"
|
|
46
|
+
assert posted["body"]["repo"] == "BrainSurfing-tech/swarph-cli"
|
|
47
|
+
assert posted["body"]["pr"] == 12
|
|
48
|
+
assert posted["body"]["head_sha"] == HEAD
|
|
49
|
+
assert posted["body"]["card_id"] == 1297
|
|
50
|
+
|
|
51
|
+
rc = main(["commander", "request", "release_finish",
|
|
52
|
+
"--version", "0.9.0", "--pr", "12", "--head", HEAD,
|
|
53
|
+
"--gateway", "http://127.0.0.1:9", "--as", "cursor-lin"])
|
|
54
|
+
assert rc == 0
|
|
55
|
+
assert posted["body"] == {
|
|
56
|
+
"type": "release_finish",
|
|
57
|
+
"pr": 12,
|
|
58
|
+
"head_sha": HEAD,
|
|
59
|
+
"version": "0.9.0",
|
|
60
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""card #1301: a same-second restart is not a failed restart.
|
|
2
|
+
|
|
3
|
+
/proc btime is a whole second, so the derived start can read up to 1s
|
|
4
|
+
before the install cutoff. A process that did not restart still fails.
|
|
5
|
+
"""
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
11
|
+
CHECK = ROOT / "scripts" / "release_check.py"
|
|
12
|
+
RELEASE = ROOT / "release.sh"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _run(args, env):
|
|
16
|
+
return subprocess.run(args, cwd=ROOT, env=env, text=True, capture_output=True)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_1301_same_second_restart_passes_and_an_old_process_fails(tmp_path):
|
|
20
|
+
image = tmp_path / "image"
|
|
21
|
+
image.write_bytes(b"swarph_cli-9.9.9.dist-info")
|
|
22
|
+
env = os.environ.copy()
|
|
23
|
+
env["RELEASE_IMAGE"] = str(image)
|
|
24
|
+
env["RELEASE_START_EPOCH"] = "648.800"
|
|
25
|
+
ok = _run(
|
|
26
|
+
["python3", str(CHECK), "verify", "--pid", "42", "--expected", "9.9.9",
|
|
27
|
+
"--install-epoch", "649.000"],
|
|
28
|
+
env,
|
|
29
|
+
)
|
|
30
|
+
assert ok.returncode == 0, ok.stderr
|
|
31
|
+
assert "before the install" not in ok.stderr
|
|
32
|
+
env["RELEASE_START_EPOCH"] = "100.000"
|
|
33
|
+
bad = _run(
|
|
34
|
+
["python3", str(CHECK), "verify", "--pid", "42", "--expected", "9.9.9",
|
|
35
|
+
"--install-epoch", "649.000"],
|
|
36
|
+
env,
|
|
37
|
+
)
|
|
38
|
+
assert bad.returncode != 0
|
|
39
|
+
assert "before the install" in bad.stderr
|
|
40
|
+
env["RELEASE_START_EPOCH"] = "648.800"
|
|
41
|
+
image.write_bytes(b"swarph_cli-0.1.0.dist-info")
|
|
42
|
+
wrong = _run(
|
|
43
|
+
["python3", str(CHECK), "verify", "--pid", "42", "--expected", "9.9.9",
|
|
44
|
+
"--install-epoch", "649.000"],
|
|
45
|
+
env,
|
|
46
|
+
)
|
|
47
|
+
assert wrong.returncode != 0
|
|
48
|
+
assert "0.1.0" in wrong.stderr
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_1301_record_mtime_is_the_install_moment(tmp_path):
|
|
52
|
+
record = tmp_path / "RECORD"
|
|
53
|
+
record.write_bytes(b"x")
|
|
54
|
+
os.utime(record, (649.0, 649.0))
|
|
55
|
+
proc = _run(
|
|
56
|
+
["python3", str(CHECK), "record-mtime", "--version", "9.9.9",
|
|
57
|
+
"--record", str(record)],
|
|
58
|
+
os.environ.copy(),
|
|
59
|
+
)
|
|
60
|
+
assert proc.returncode == 0, proc.stderr
|
|
61
|
+
assert abs(float(proc.stdout.strip()) - 649.0) < 0.01
|
|
62
|
+
text = RELEASE.read_text()
|
|
63
|
+
assert 'record-mtime --version "$VERSION"' in text
|
|
64
|
+
assert "install_epoch=$(date +%s)" not in text
|
|
@@ -44,7 +44,10 @@ FIXTURE = [
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
@pytest.fixture(autouse=True)
|
|
47
|
-
def _session(monkeypatch: pytest.MonkeyPatch):
|
|
47
|
+
def _session(monkeypatch: pytest.MonkeyPatch, tmp_path):
|
|
48
|
+
# Card #1286 reads the monitor cursor. These tests are about the unread
|
|
49
|
+
# payload, so they observe from a private home whose cursor is absent.
|
|
50
|
+
monkeypatch.setenv("HOME", str(tmp_path))
|
|
48
51
|
monkeypatch.setattr(mcp_server, "_dm_session", lambda self_name=None: ("lab-ovh", "http://gw", "tok"))
|
|
49
52
|
if MUTATE == "truncate":
|
|
50
53
|
real = mcp_server._lean
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|