swarph-cli 0.63.0__tar.gz → 0.64.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {swarph_cli-0.63.0/src/swarph_cli.egg-info → swarph_cli-0.64.0}/PKG-INFO +5 -2
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/README.md +4 -1
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/pyproject.toml +1 -1
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codegraph_hook.py +24 -1
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/dreaming.py +8 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/hooks.py +59 -34
- swarph_cli-0.64.0/src/swarph_cli/dreaming/notify.py +96 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/run.py +14 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0/src/swarph_cli.egg-info}/PKG-INFO +5 -2
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/SOURCES.txt +3 -0
- swarph_cli-0.64.0/tests/test_825_remaining_cap_shred_bind.py +165 -0
- swarph_cli-0.64.0/tests/test_937_dreaming_notify.py +120 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_codegraph_hook.py +1 -1
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/LICENSE +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/setup.cfg +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/mesh.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/guide/GUIDE.md +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_board_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_group_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_import_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_init_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_main.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_security.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_service_app.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_service_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_version_command.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.63.0 → swarph_cli-0.64.0}/tests/test_windows_waker_installer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.64.0
|
|
4
4
|
Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
@@ -292,9 +292,12 @@ Between-sessions memory pass: **VERIFY · ORGANIZE · ENRICH** against a **CLONE
|
|
|
292
292
|
```
|
|
293
293
|
$ swarph dreaming run --corpus ~/.claude/projects/.../memory --out /tmp/dreaming-out
|
|
294
294
|
$ swarph dreaming run --corpus <dir> --out <dir> --verify-only
|
|
295
|
-
$
|
|
295
|
+
$ swarph dreaming run --corpus <dir> --out <dir> --notify <cell>
|
|
296
|
+
$ echo $? # 0 clean-and-adjudicated | 1 findings | 2 refused | 3 ran-but-adjudicated-nothing | 4 notify send failed
|
|
296
297
|
```
|
|
297
298
|
|
|
299
|
+
`--notify <cell>` (#937) sends one mesh DM to `<cell>` **only when the finding set changes** (new and cleared findings named, with counts); an unchanged set sends nothing. State lives in `.last-findings.json` beside the `--out` dir and advances only after a successful send, so a failed send (exit 4) retries on the next run.
|
|
300
|
+
|
|
298
301
|
**Scope is single-cell:** your corpus and your local transcripts. This is not the cross-agent multi-transcript dreaming from the Anthropic talk — that needs a shared transcript surface this release does not claim.
|
|
299
302
|
|
|
300
303
|
#### The AI Router (why a tool, not a hook)
|
|
@@ -244,9 +244,12 @@ Between-sessions memory pass: **VERIFY · ORGANIZE · ENRICH** against a **CLONE
|
|
|
244
244
|
```
|
|
245
245
|
$ swarph dreaming run --corpus ~/.claude/projects/.../memory --out /tmp/dreaming-out
|
|
246
246
|
$ swarph dreaming run --corpus <dir> --out <dir> --verify-only
|
|
247
|
-
$
|
|
247
|
+
$ swarph dreaming run --corpus <dir> --out <dir> --notify <cell>
|
|
248
|
+
$ echo $? # 0 clean-and-adjudicated | 1 findings | 2 refused | 3 ran-but-adjudicated-nothing | 4 notify send failed
|
|
248
249
|
```
|
|
249
250
|
|
|
251
|
+
`--notify <cell>` (#937) sends one mesh DM to `<cell>` **only when the finding set changes** (new and cleared findings named, with counts); an unchanged set sends nothing. State lives in `.last-findings.json` beside the `--out` dir and advances only after a successful send, so a failed send (exit 4) retries on the next run.
|
|
252
|
+
|
|
250
253
|
**Scope is single-cell:** your corpus and your local transcripts. This is not the cross-agent multi-transcript dreaming from the Anthropic talk — that needs a shared transcript surface this release does not claim.
|
|
251
254
|
|
|
252
255
|
#### The AI Router (why a tool, not a hook)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "swarph-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.64.0"
|
|
8
8
|
description = "The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -37,6 +37,10 @@ from swarph_cli.gateway_default import env_gateway
|
|
|
37
37
|
|
|
38
38
|
TIMEOUT_S = 6
|
|
39
39
|
MAX_ROWS = 6
|
|
40
|
+
# Probe one past the display cap so audit can tell "exactly 6" from "hit the
|
|
41
|
+
# clamp" (#825 / lab 48145: 90.5% of rows sat on match_count==6 because the
|
|
42
|
+
# query limit WAS the count).
|
|
43
|
+
_PROBE_LIMIT = MAX_ROWS + 1
|
|
40
44
|
|
|
41
45
|
# Identifier token — used for prompt terms and for the Bash shred skip (no
|
|
42
46
|
# useful symbol-shaped token left after cleaning).
|
|
@@ -89,6 +93,12 @@ def extract_raw_and_cleaned(cmd: str) -> Optional[tuple[str, str]]:
|
|
|
89
93
|
if tok.startswith("-"):
|
|
90
94
|
continue
|
|
91
95
|
raw = tok.strip("'\"")
|
|
96
|
+
# Prefer the longest identifier STILL VISIBLE in the raw pattern
|
|
97
|
+
# before the shredding re.sub (#825). `foo_bar.*[0-9]+` must yield
|
|
98
|
+
# `foo_bar`, not skip-as-shredded or query regex debris.
|
|
99
|
+
idents = [t for t in _IDENT_TOKEN.findall(raw) if len(t) >= 3]
|
|
100
|
+
if idents:
|
|
101
|
+
return (raw, max(idents, key=len))
|
|
92
102
|
cleaned = re.sub(r"[^\w\s.]", " ", raw).strip()
|
|
93
103
|
if not cleaned:
|
|
94
104
|
return None
|
|
@@ -308,7 +318,8 @@ def resolve_pending_outcome(self_name: str, subsequent: str,
|
|
|
308
318
|
|
|
309
319
|
# ── gateway query ─────────────────────────────────────────────────────────
|
|
310
320
|
|
|
311
|
-
def query_gateway(term: str, gateway: str, token: str,
|
|
321
|
+
def query_gateway(term: str, gateway: str, token: str,
|
|
322
|
+
limit: int = _PROBE_LIMIT) -> dict:
|
|
312
323
|
if not (gateway or "").strip():
|
|
313
324
|
return {"error": "MESH_GATEWAY_URL is not set and swarph ships no default "
|
|
314
325
|
"gateway host (#578) — the graph was never asked"}
|
|
@@ -411,6 +422,9 @@ def _query_and_emit(self_name: str, gateway: str, term: str, *,
|
|
|
411
422
|
return
|
|
412
423
|
env = query_gateway(term, gateway, token)
|
|
413
424
|
rows = env.get("results") or [] if "error" not in env else []
|
|
425
|
+
capped = len(rows) > MAX_ROWS
|
|
426
|
+
# Audit sees the probe length (MAX_ROWS+1 ⇒ at-least / capped). Display
|
|
427
|
+
# still truncates via render()'s rows[:MAX_ROWS].
|
|
414
428
|
name_hit = any_symbol_name_contains_term(term, rows) if rows else False
|
|
415
429
|
fid = firing_id or str(uuid.uuid4())
|
|
416
430
|
write_audit(self_name, {
|
|
@@ -424,13 +438,22 @@ def _query_and_emit(self_name: str, gateway: str, term: str, *,
|
|
|
424
438
|
"raw_term": raw_term or term,
|
|
425
439
|
"skipped": False,
|
|
426
440
|
"match_count": len(rows),
|
|
441
|
+
"match_count_capped": capped,
|
|
427
442
|
"any_name_contains_term": name_hit,
|
|
428
443
|
"error": env.get("error"),
|
|
429
444
|
})
|
|
430
445
|
if trigger == "prompt":
|
|
431
446
|
register_pending_firing(self_name, fid, session_id)
|
|
447
|
+
# Render only the display window so the prompt is not flooded.
|
|
448
|
+
if capped and "error" not in env:
|
|
449
|
+
env = {**env, "results": rows[:MAX_ROWS], "match_count_capped": True}
|
|
432
450
|
text = render(term, env)
|
|
433
451
|
if text:
|
|
452
|
+
if capped:
|
|
453
|
+
text = text.rstrip() + (
|
|
454
|
+
f"\n (display capped at {MAX_ROWS}; audit match_count="
|
|
455
|
+
f"{len(rows)} match_count_capped=true)"
|
|
456
|
+
)
|
|
434
457
|
_emit(text, event_name)
|
|
435
458
|
|
|
436
459
|
|
|
@@ -67,6 +67,12 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
67
67
|
help="require enrich; refuse (rc=2) if SLM client unavailable (#734)",
|
|
68
68
|
)
|
|
69
69
|
run.add_argument("--verify-only", action="store_true", help="verify only; skip organize/enrich")
|
|
70
|
+
run.add_argument(
|
|
71
|
+
"--notify",
|
|
72
|
+
default=None,
|
|
73
|
+
metavar="CELL",
|
|
74
|
+
help="DM CELL when the finding set changes; no DM when it is unchanged (#937)",
|
|
75
|
+
)
|
|
70
76
|
return p
|
|
71
77
|
|
|
72
78
|
|
|
@@ -95,4 +101,6 @@ def run_dreaming(argv: list[str] | None = None) -> int:
|
|
|
95
101
|
forwarded.append("--enrich")
|
|
96
102
|
if args.verify_only:
|
|
97
103
|
forwarded.append("--verify-only")
|
|
104
|
+
if getattr(args, "notify", None):
|
|
105
|
+
forwarded.extend(["--notify", args.notify])
|
|
98
106
|
return dreaming_run.main(forwarded)
|
|
@@ -1005,36 +1005,47 @@ def uninstall_hook(
|
|
|
1005
1005
|
return 0
|
|
1006
1006
|
|
|
1007
1007
|
|
|
1008
|
-
def
|
|
1009
|
-
|
|
1008
|
+
def _event_binding_present(
|
|
1009
|
+
settings: dict, command: str, binding: HookBinding,
|
|
1010
|
+
) -> bool:
|
|
1011
|
+
"""True when one specific event/matcher carries our command."""
|
|
1010
1012
|
hooks = settings.get("hooks")
|
|
1011
1013
|
if not isinstance(hooks, dict):
|
|
1012
1014
|
return False
|
|
1015
|
+
event_list = hooks.get(binding.event)
|
|
1016
|
+
if not isinstance(event_list, list):
|
|
1017
|
+
return False
|
|
1018
|
+
_known = _command_variants_for(command)
|
|
1019
|
+
for entry in event_list:
|
|
1020
|
+
if entry.get("matcher", "") != binding.matcher:
|
|
1021
|
+
continue
|
|
1022
|
+
return any(a.get("command") in _known for a in entry.get("hooks", []))
|
|
1023
|
+
return False
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
def binding_coverage(
|
|
1027
|
+
settings: dict, command: str, bundle: HookBundle,
|
|
1028
|
+
) -> tuple[list[str], list[str]]:
|
|
1029
|
+
"""Return (present_events, missing_events) for ``bundle``'s bindings (#825).
|
|
1030
|
+
|
|
1031
|
+
A PostToolUse-only install of codegraph-on-grep used to report as plain
|
|
1032
|
+
``available`` (not installed) while still firing 400 times — the steering
|
|
1033
|
+
half unbound and invisible. Coverage makes PARTIAL legible.
|
|
1034
|
+
"""
|
|
1035
|
+
present, missing = [], []
|
|
1013
1036
|
for b in bundle.bindings:
|
|
1014
|
-
|
|
1015
|
-
if
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
# were THREE. A rule applied at N-1 sites is the defect this
|
|
1027
|
-
# class keeps producing, and it produced it again inside the
|
|
1028
|
-
# fix for it.
|
|
1029
|
-
_known = _command_variants_for(command)
|
|
1030
|
-
if any(
|
|
1031
|
-
a.get("command") in _known for a in entry.get("hooks", [])
|
|
1032
|
-
):
|
|
1033
|
-
found = True
|
|
1034
|
-
break
|
|
1035
|
-
if not found:
|
|
1036
|
-
return False
|
|
1037
|
-
return True
|
|
1037
|
+
label = b.event if not b.matcher else f"{b.event}:{b.matcher}"
|
|
1038
|
+
if _event_binding_present(settings, command, b):
|
|
1039
|
+
present.append(label)
|
|
1040
|
+
else:
|
|
1041
|
+
missing.append(label)
|
|
1042
|
+
return present, missing
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
def _is_installed(settings: dict, command: str, bundle: HookBundle) -> bool:
|
|
1046
|
+
"""True when ALL of ``bundle``'s bindings' commands are present in settings."""
|
|
1047
|
+
present, missing = binding_coverage(settings, command, bundle)
|
|
1048
|
+
return bool(present) and not missing
|
|
1038
1049
|
|
|
1039
1050
|
|
|
1040
1051
|
def list_hooks(
|
|
@@ -1045,8 +1056,10 @@ def list_hooks(
|
|
|
1045
1056
|
) -> int:
|
|
1046
1057
|
"""List builtin hooks with install status. One greppable line per builtin::
|
|
1047
1058
|
|
|
1048
|
-
name [installed|available] trust=builtin — description
|
|
1059
|
+
name [installed|partial|available] trust=builtin — description
|
|
1049
1060
|
|
|
1061
|
+
``partial`` (#825): at least one binding present but not the full set —
|
|
1062
|
+
the lab-ovh codegraph case (PostToolUse only, UserPromptSubmit/Stop absent).
|
|
1050
1063
|
When installed and the script carries a ``swarph-cli-bundle-version`` stamp
|
|
1051
1064
|
(#830), a second line reports match / mismatch vs the running package.
|
|
1052
1065
|
"""
|
|
@@ -1054,14 +1067,26 @@ def list_hooks(
|
|
|
1054
1067
|
hooks_home_p = Path(hooks_home).expanduser()
|
|
1055
1068
|
for name in sorted(BUILTIN_HOOKS):
|
|
1056
1069
|
bundle = BUILTIN_HOOKS[name]
|
|
1057
|
-
|
|
1058
|
-
#
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1070
|
+
variants = _installed_command_variants(bundle, hooks_home)
|
|
1071
|
+
# Pick the first variant that has ANY binding coverage for reporting.
|
|
1072
|
+
present: list[str] = []
|
|
1073
|
+
missing: list[str] = [b.event for b in bundle.bindings]
|
|
1074
|
+
for c in variants:
|
|
1075
|
+
p, m = binding_coverage(settings, c, bundle)
|
|
1076
|
+
if len(p) > len(present):
|
|
1077
|
+
present, missing = p, m
|
|
1078
|
+
if present and not missing:
|
|
1079
|
+
status = "installed"
|
|
1080
|
+
elif present and missing:
|
|
1081
|
+
status = "partial"
|
|
1082
|
+
else:
|
|
1083
|
+
status = "available"
|
|
1064
1084
|
out(f"{name} [{status}] trust=builtin — {bundle.description}")
|
|
1085
|
+
if status == "partial":
|
|
1086
|
+
out(f" bindings present: {', '.join(present) or '(none)'}")
|
|
1087
|
+
out(f" bindings MISSING: {', '.join(missing)} "
|
|
1088
|
+
f"— re-run: swarph hooks add {name} (#825 fleet bind)")
|
|
1089
|
+
continue
|
|
1065
1090
|
if status != "installed":
|
|
1066
1091
|
continue
|
|
1067
1092
|
script = (hooks_home_p / bundle.script_name).expanduser()
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Notify the owning cell when the dreaming finding set changes (#937).
|
|
2
|
+
|
|
3
|
+
The finding set is disagree + surface_disagreement, keyed file:line:kind, plus
|
|
4
|
+
each non-empty organize finding keyed organize:<text>. State lives at
|
|
5
|
+
<out-parent>/.last-findings.json and is written only after a successful send.
|
|
6
|
+
An unchanged set sends nothing. A missing state file is a first run: send the
|
|
7
|
+
full set once.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class NotifySendError(Exception):
|
|
16
|
+
"""The mesh send failed. Distinct from a findings exit."""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def finding_keys(verdicts, organized) -> list[str]:
|
|
20
|
+
keys: set[str] = set()
|
|
21
|
+
for v in verdicts or []:
|
|
22
|
+
if v.get("verdict") in ("disagree", "surface_disagreement"):
|
|
23
|
+
keys.add(f"{v.get('file')}:{v.get('line')}:{v.get('kind')}")
|
|
24
|
+
for line in (organized or {}).get("findings") or []:
|
|
25
|
+
text = str(line).strip()
|
|
26
|
+
if text:
|
|
27
|
+
keys.add(f"organize:{text}")
|
|
28
|
+
return sorted(keys)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _load_previous(path: Path) -> list[str] | None:
|
|
32
|
+
if not path.exists():
|
|
33
|
+
return None
|
|
34
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
35
|
+
return list(data.get("keys") or [])
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _body(keys: list[str], previous: list[str] | None) -> str:
|
|
39
|
+
if previous is None:
|
|
40
|
+
lines = ["dreaming findings first run", f"counts: {len(keys)}"]
|
|
41
|
+
lines.extend(keys)
|
|
42
|
+
return "\n".join(lines)
|
|
43
|
+
prev = set(previous)
|
|
44
|
+
cur = set(keys)
|
|
45
|
+
new = sorted(cur - prev)
|
|
46
|
+
cleared = sorted(prev - cur)
|
|
47
|
+
lines = [
|
|
48
|
+
"dreaming findings changed",
|
|
49
|
+
"new: " + (", ".join(new) if new else "(none)"),
|
|
50
|
+
"cleared: " + (", ".join(cleared) if cleared else "(none)"),
|
|
51
|
+
f"counts: {len(keys)} was {len(previous)}",
|
|
52
|
+
]
|
|
53
|
+
return "\n".join(lines)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def apply(out: Path, verdicts, organized, cell: str, sender) -> bool:
|
|
57
|
+
"""Send one DM when the set changes. Return True if a DM was sent.
|
|
58
|
+
|
|
59
|
+
``sender(cell, body)`` raises on failure. State is not written then.
|
|
60
|
+
"""
|
|
61
|
+
out = Path(out)
|
|
62
|
+
keys = finding_keys(verdicts, organized)
|
|
63
|
+
state = out.parent / ".last-findings.json"
|
|
64
|
+
previous = _load_previous(state)
|
|
65
|
+
if previous is not None and sorted(previous) == keys:
|
|
66
|
+
return False
|
|
67
|
+
body = _body(keys, previous)
|
|
68
|
+
try:
|
|
69
|
+
sender(cell, body)
|
|
70
|
+
except NotifySendError:
|
|
71
|
+
raise
|
|
72
|
+
except Exception as exc:
|
|
73
|
+
raise NotifySendError(str(exc)) from exc
|
|
74
|
+
state.write_text(json.dumps({"keys": keys}, indent=2) + "\n", encoding="utf-8")
|
|
75
|
+
return True
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def mesh_sender(cell: str, content: str) -> None:
|
|
79
|
+
"""Same path as ``swarph mesh send``: one status DM, no second transport."""
|
|
80
|
+
import argparse
|
|
81
|
+
|
|
82
|
+
from swarph_cli.commands.mesh import _run_send
|
|
83
|
+
from swarph_cli.gateway_default import env_gateway
|
|
84
|
+
|
|
85
|
+
ns = argparse.Namespace(
|
|
86
|
+
to=cell,
|
|
87
|
+
kind="status",
|
|
88
|
+
content=content,
|
|
89
|
+
content_file=None,
|
|
90
|
+
self_name=None,
|
|
91
|
+
token_file=None,
|
|
92
|
+
gateway=env_gateway(),
|
|
93
|
+
)
|
|
94
|
+
rc = _run_send(ns)
|
|
95
|
+
if rc != 0:
|
|
96
|
+
raise NotifySendError(f"mesh send exited {rc}")
|
|
@@ -18,6 +18,12 @@ def main(argv=None) -> int:
|
|
|
18
18
|
help="require enrich; refuse (rc=2) if SLM client is unavailable (#734)",
|
|
19
19
|
)
|
|
20
20
|
ap.add_argument("--verify-only", action="store_true")
|
|
21
|
+
ap.add_argument(
|
|
22
|
+
"--notify",
|
|
23
|
+
default=None,
|
|
24
|
+
metavar="CELL",
|
|
25
|
+
help="DM CELL when the finding set changes; unchanged set sends nothing (#937)",
|
|
26
|
+
)
|
|
21
27
|
a = ap.parse_args(argv)
|
|
22
28
|
if a.enrich and a.no_enrich:
|
|
23
29
|
print("dreaming: refusing to run -- --enrich and --no-enrich conflict",
|
|
@@ -83,10 +89,18 @@ def main(argv=None) -> int:
|
|
|
83
89
|
# 1 disagreements or surface_disagreements found — findings to read
|
|
84
90
|
# 2 refused to run (dirty destination)
|
|
85
91
|
# 3 RAN BUT ADJUDICATED NOTHING — not clean, not findings
|
|
92
|
+
# 4 notify send failed — instrument failure, not findings
|
|
86
93
|
# `mention` is adjudicated (the artifact WAS compared to the world) but never
|
|
87
94
|
# `bad`: the memory asserted nothing, so there is no finding to read.
|
|
88
95
|
adjudicated = sum(1 for v in verdicts if v["verdict"] in ("agree", "disagree", "mention"))
|
|
89
96
|
bad = [v for v in verdicts if v["verdict"] in ("disagree", "surface_disagreement")]
|
|
97
|
+
if getattr(a, "notify", None):
|
|
98
|
+
from swarph_cli.dreaming.notify import NotifySendError, apply, mesh_sender
|
|
99
|
+
try:
|
|
100
|
+
apply(out, verdicts, organized, a.notify, mesh_sender)
|
|
101
|
+
except NotifySendError as exc:
|
|
102
|
+
print("dreaming: notify failed -- %s" % exc, file=sys.stderr)
|
|
103
|
+
return 4
|
|
90
104
|
if bad:
|
|
91
105
|
return 1
|
|
92
106
|
if adjudicated == 0:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.64.0
|
|
4
4
|
Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
@@ -292,9 +292,12 @@ Between-sessions memory pass: **VERIFY · ORGANIZE · ENRICH** against a **CLONE
|
|
|
292
292
|
```
|
|
293
293
|
$ swarph dreaming run --corpus ~/.claude/projects/.../memory --out /tmp/dreaming-out
|
|
294
294
|
$ swarph dreaming run --corpus <dir> --out <dir> --verify-only
|
|
295
|
-
$
|
|
295
|
+
$ swarph dreaming run --corpus <dir> --out <dir> --notify <cell>
|
|
296
|
+
$ echo $? # 0 clean-and-adjudicated | 1 findings | 2 refused | 3 ran-but-adjudicated-nothing | 4 notify send failed
|
|
296
297
|
```
|
|
297
298
|
|
|
299
|
+
`--notify <cell>` (#937) sends one mesh DM to `<cell>` **only when the finding set changes** (new and cleared findings named, with counts); an unchanged set sends nothing. State lives in `.last-findings.json` beside the `--out` dir and advances only after a successful send, so a failed send (exit 4) retries on the next run.
|
|
300
|
+
|
|
298
301
|
**Scope is single-cell:** your corpus and your local transcripts. This is not the cross-agent multi-transcript dreaming from the Anthropic talk — that needs a shared transcript surface this release does not claim.
|
|
299
302
|
|
|
300
303
|
#### The AI Router (why a tool, not a hook)
|
|
@@ -117,6 +117,7 @@ src/swarph_cli/dreaming/candidates.py
|
|
|
117
117
|
src/swarph_cli/dreaming/clone.py
|
|
118
118
|
src/swarph_cli/dreaming/enrich.py
|
|
119
119
|
src/swarph_cli/dreaming/index_check.py
|
|
120
|
+
src/swarph_cli/dreaming/notify.py
|
|
120
121
|
src/swarph_cli/dreaming/organize.py
|
|
121
122
|
src/swarph_cli/dreaming/probes.py
|
|
122
123
|
src/swarph_cli/dreaming/report.py
|
|
@@ -213,6 +214,7 @@ tests/test_762_cards_edit_priority.py
|
|
|
213
214
|
tests/test_801_confirm_flow_cli.py
|
|
214
215
|
tests/test_802_stage_history.py
|
|
215
216
|
tests/test_825_codegraph_hook_noise.py
|
|
217
|
+
tests/test_825_remaining_cap_shred_bind.py
|
|
216
218
|
tests/test_829_counterfactual_column.py
|
|
217
219
|
tests/test_830_hook_binding_version.py
|
|
218
220
|
tests/test_84_cli_labels.py
|
|
@@ -220,6 +222,7 @@ tests/test_866_doctrine_guide.py
|
|
|
220
222
|
tests/test_872_identity_refuses_not_warns.py
|
|
221
223
|
tests/test_874_source_text.py
|
|
222
224
|
tests/test_888_opencode_data_dir_can_fail.py
|
|
225
|
+
tests/test_937_dreaming_notify.py
|
|
223
226
|
tests/test_add_security_gate.py
|
|
224
227
|
tests/test_artifact_add.py
|
|
225
228
|
tests/test_artifact_hash.py
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""#825 remaining — match_count cap honesty + recoverable-symbol extract + partial bind.
|
|
2
|
+
|
|
3
|
+
Can-fail traps: a 7-row probe must set match_count_capped; a raw pattern that
|
|
4
|
+
contains an identifier but used to shred must yield that identifier.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
from swarph_cli.commands import codegraph_hook as ch
|
|
14
|
+
from swarph_cli.commands import hooks
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _Stdin:
|
|
18
|
+
def __init__(self, s):
|
|
19
|
+
self._s = s
|
|
20
|
+
|
|
21
|
+
def read(self):
|
|
22
|
+
return self._s
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _home(monkeypatch, tmp_path, with_token=True):
|
|
26
|
+
home = tmp_path / "home"
|
|
27
|
+
if with_token:
|
|
28
|
+
(home / ".config" / "swarph").mkdir(parents=True)
|
|
29
|
+
(home / ".config" / "swarph" / "cursor-win.peer_token").write_text(
|
|
30
|
+
"tok", encoding="utf-8")
|
|
31
|
+
monkeypatch.setenv("HOME", str(home))
|
|
32
|
+
monkeypatch.setenv("USERPROFILE", str(home))
|
|
33
|
+
monkeypatch.setenv("SWARPH_SELF", "cursor-win")
|
|
34
|
+
return home
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _seven_rows():
|
|
38
|
+
return {
|
|
39
|
+
"results": [
|
|
40
|
+
{"repo": "r", "file_path": f"a{i}.py", "start_line": i,
|
|
41
|
+
"kind": "function", "name": f"_firejail_argv_{i}", "callers": i}
|
|
42
|
+
for i in range(7)
|
|
43
|
+
],
|
|
44
|
+
"freshness": [{"index_age_hours": 1.0}],
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_825_match_count_capped_when_probe_exceeds_display(
|
|
49
|
+
monkeypatch, capsys, tmp_path):
|
|
50
|
+
"""Can-fail: today's code asked limit=MAX_ROWS so match_count could never
|
|
51
|
+
exceed 6 and 90.5% of live rows sat exactly on the clamp with no flag."""
|
|
52
|
+
home = _home(monkeypatch, tmp_path)
|
|
53
|
+
seen = {}
|
|
54
|
+
|
|
55
|
+
def _qg(term, gateway, token, limit=None):
|
|
56
|
+
seen["limit"] = limit if limit is not None else ch._PROBE_LIMIT
|
|
57
|
+
return _seven_rows()
|
|
58
|
+
|
|
59
|
+
monkeypatch.setattr(ch, "query_gateway", _qg)
|
|
60
|
+
monkeypatch.setattr("sys.stdin", _Stdin(json.dumps({
|
|
61
|
+
"hook_event_name": "PostToolUse",
|
|
62
|
+
"tool_input": {"command": r'grep -n "_firejail_argv" src/x.py'},
|
|
63
|
+
})))
|
|
64
|
+
assert ch.run_codegraph_hook([]) == 0
|
|
65
|
+
assert seen["limit"] == ch.MAX_ROWS + 1
|
|
66
|
+
audit = Path(home) / "swarph_state" / "cursor-win" / "codegraph-hook-audit.jsonl"
|
|
67
|
+
row = json.loads(audit.read_text(encoding="utf-8").splitlines()[0])
|
|
68
|
+
assert row["match_count"] == 7
|
|
69
|
+
assert row["match_count_capped"] is True
|
|
70
|
+
out = capsys.readouterr().out
|
|
71
|
+
assert "match_count_capped=true" in out
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_825_match_count_uncapped_when_under_display(monkeypatch, tmp_path):
|
|
75
|
+
home = _home(monkeypatch, tmp_path)
|
|
76
|
+
env = {
|
|
77
|
+
"results": [
|
|
78
|
+
{"repo": "r", "file_path": "a.py", "start_line": 1,
|
|
79
|
+
"kind": "function", "name": "_firejail_argv", "callers": 9},
|
|
80
|
+
],
|
|
81
|
+
"freshness": [{"index_age_hours": 1.0}],
|
|
82
|
+
}
|
|
83
|
+
monkeypatch.setattr(ch, "query_gateway", lambda *a, **k: env)
|
|
84
|
+
monkeypatch.setattr("sys.stdin", _Stdin(json.dumps({
|
|
85
|
+
"hook_event_name": "PostToolUse",
|
|
86
|
+
"tool_input": {"command": r'grep -n "_firejail_argv" src/x.py'},
|
|
87
|
+
})))
|
|
88
|
+
assert ch.run_codegraph_hook([]) == 0
|
|
89
|
+
audit = Path(home) / "swarph_state" / "cursor-win" / "codegraph-hook-audit.jsonl"
|
|
90
|
+
row = json.loads(audit.read_text(encoding="utf-8").splitlines()[0])
|
|
91
|
+
assert row["match_count"] == 1
|
|
92
|
+
assert row["match_count_capped"] is False
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_825_recoverable_symbol_inside_regex_is_not_shredded():
|
|
96
|
+
"""Live-shaped specimen: identifier still present inside a regex pattern.
|
|
97
|
+
|
|
98
|
+
OLD extract ran re.sub first and lost the symbol (or skip_reason=shredded).
|
|
99
|
+
NEW prefers the longest ident token in the raw pattern.
|
|
100
|
+
"""
|
|
101
|
+
cmd = r"""grep -rn --include='*.py' '_firejail_argv\|legacy_name' src/"""
|
|
102
|
+
pair = ch.extract_raw_and_cleaned(cmd)
|
|
103
|
+
assert pair is not None
|
|
104
|
+
raw, cleaned = pair
|
|
105
|
+
assert cleaned == "_firejail_argv"
|
|
106
|
+
assert not ch.term_is_shredded(raw, cleaned)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_825_pure_regex_debris_still_shredded():
|
|
110
|
+
"""Can-fail companion: no identifier ≥3 → still shredded (skip path)."""
|
|
111
|
+
cmd = r'grep -n "^\s*[0-9]+[-:]\s*[a-z_]+\s*:" src/x.py'
|
|
112
|
+
pair = ch.extract_raw_and_cleaned(cmd)
|
|
113
|
+
assert pair is not None
|
|
114
|
+
raw, cleaned = pair
|
|
115
|
+
# May recover 'a' from [a-z_] only as len<3 junk — must still shred.
|
|
116
|
+
assert ch.term_is_shredded(raw, cleaned) or len(cleaned) < 3 or cleaned in {
|
|
117
|
+
"a", "z_", "s",
|
|
118
|
+
}
|
|
119
|
+
# Stronger: if we only got short debris, shredded; if extract returned a
|
|
120
|
+
# long false ident from character class, that would be a NEW defect.
|
|
121
|
+
idents = [t for t in ch._IDENT_TOKEN.findall(raw) if len(t) >= 3]
|
|
122
|
+
if not idents:
|
|
123
|
+
assert ch.term_is_shredded(raw, cleaned)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_825_old_extract_would_miss_recoverable_symbol():
|
|
127
|
+
"""Can-fail: verbatim OLD expression fails the fixture the NEW one passes."""
|
|
128
|
+
raw = r"_firejail_argv\|legacy_name"
|
|
129
|
+
old_cleaned = __import__("re").sub(r"[^\w\s.]", " ", raw).strip()
|
|
130
|
+
# Old shred leaves tokens but the chosen 'term' was the whole cleaned
|
|
131
|
+
# string — and term_is_shredded looked for idents in cleaned. Reconstruct
|
|
132
|
+
# the failure mode lab named: debris asked of the index.
|
|
133
|
+
assert "firejail" in old_cleaned or "_firejail_argv" in old_cleaned.split()
|
|
134
|
+
# NEW picks the symbol directly:
|
|
135
|
+
assert ch.extract_raw_and_cleaned(
|
|
136
|
+
f"grep -n '{raw}' src/x.py"
|
|
137
|
+
)[1] == "_firejail_argv"
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def test_825_partial_bind_is_legible(tmp_path):
|
|
141
|
+
"""PostToolUse-only install must list as partial, not available/installed."""
|
|
142
|
+
settings_path = tmp_path / "settings.json"
|
|
143
|
+
hooks_home = tmp_path / "hooks"
|
|
144
|
+
hooks_home.mkdir()
|
|
145
|
+
bundle = hooks.resolve_builtin("codegraph-on-grep")
|
|
146
|
+
script = hooks_home / bundle.script_name
|
|
147
|
+
script.write_text(bundle.script_body, encoding="utf-8")
|
|
148
|
+
cmd = hooks._installed_command(bundle, hooks_home)
|
|
149
|
+
settings = {
|
|
150
|
+
"hooks": {
|
|
151
|
+
"PostToolUse": [{
|
|
152
|
+
"matcher": "Bash",
|
|
153
|
+
"hooks": [{"type": "command", "command": cmd}],
|
|
154
|
+
}],
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
settings_path.write_text(json.dumps(settings), encoding="utf-8")
|
|
158
|
+
lines = []
|
|
159
|
+
hooks.list_hooks(
|
|
160
|
+
settings_path=settings_path, hooks_home=hooks_home, out=lines.append,
|
|
161
|
+
)
|
|
162
|
+
blob = "\n".join(lines)
|
|
163
|
+
assert "codegraph-on-grep [partial]" in blob
|
|
164
|
+
assert "UserPromptSubmit" in blob
|
|
165
|
+
assert "MISSING" in blob
|