swarph-cli 0.62.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.62.0/src/swarph_cli.egg-info → swarph_cli-0.64.0}/PKG-INFO +6 -2
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/README.md +5 -1
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/pyproject.toml +1 -1
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/board.py +59 -12
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codegraph.py +63 -8
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codegraph_hook.py +24 -1
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/dreaming.py +8 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/guide.py +55 -2
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/hooks.py +59 -34
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/mcp_server.py +9 -2
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/mesh.py +24 -7
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/monitor.py +4 -2
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/onboard.py +8 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/spawn.py +67 -11
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/watchdog.py +33 -7
- swarph_cli-0.64.0/src/swarph_cli/dreaming/notify.py +96 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/run.py +14 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/guide/GUIDE.md +151 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/main.py +18 -0
- swarph_cli-0.64.0/src/swarph_cli/source_text.py +129 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0/src/swarph_cli.egg-info}/PKG-INFO +6 -2
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/SOURCES.txt +10 -0
- swarph_cli-0.64.0/tests/test_126_pending_from_complete.py +116 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_397_gh_identity_router.py +4 -1
- swarph_cli-0.64.0/tests/test_547_verbs_from_registry.py +59 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_552_codegraph_gateway.py +15 -1
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_556_relay_freshness.py +15 -1
- swarph_cli-0.64.0/tests/test_825_remaining_cap_shred_bind.py +165 -0
- swarph_cli-0.64.0/tests/test_866_doctrine_guide.py +71 -0
- swarph_cli-0.64.0/tests/test_872_identity_refuses_not_warns.py +129 -0
- swarph_cli-0.64.0/tests/test_874_source_text.py +116 -0
- swarph_cli-0.64.0/tests/test_888_opencode_data_dir_can_fail.py +71 -0
- swarph_cli-0.64.0/tests/test_937_dreaming_notify.py +120 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_board_card_thread.py +58 -2
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_codegraph_hook.py +1 -1
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_codegraph_mcp.py +15 -1
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_monitor_state_split.py +2 -1
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_opencode_membrane.py +45 -15
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/LICENSE +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/setup.cfg +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_board_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_group_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_import_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_init_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_main.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_security.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_service_app.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_service_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_version_command.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.62.0 → swarph_cli-0.64.0}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.62.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
|
|
@@ -148,6 +148,7 @@ swarph guide # the whole guide
|
|
|
148
148
|
swarph guide channels # one topic
|
|
149
149
|
swarph guide --list # every topic, with the commands it teaches
|
|
150
150
|
swarph guide --search subscribe # find a topic by INTENT, not by its name
|
|
151
|
+
swarph guide doctrine # the standard of evidence a cell is held to (v0.63.0)
|
|
151
152
|
```
|
|
152
153
|
|
|
153
154
|
Three ways in, because a new cell does not know which word it has:
|
|
@@ -291,9 +292,12 @@ Between-sessions memory pass: **VERIFY · ORGANIZE · ENRICH** against a **CLONE
|
|
|
291
292
|
```
|
|
292
293
|
$ swarph dreaming run --corpus ~/.claude/projects/.../memory --out /tmp/dreaming-out
|
|
293
294
|
$ swarph dreaming run --corpus <dir> --out <dir> --verify-only
|
|
294
|
-
$
|
|
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
|
|
295
297
|
```
|
|
296
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
|
+
|
|
297
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.
|
|
298
302
|
|
|
299
303
|
#### The AI Router (why a tool, not a hook)
|
|
@@ -100,6 +100,7 @@ swarph guide # the whole guide
|
|
|
100
100
|
swarph guide channels # one topic
|
|
101
101
|
swarph guide --list # every topic, with the commands it teaches
|
|
102
102
|
swarph guide --search subscribe # find a topic by INTENT, not by its name
|
|
103
|
+
swarph guide doctrine # the standard of evidence a cell is held to (v0.63.0)
|
|
103
104
|
```
|
|
104
105
|
|
|
105
106
|
Three ways in, because a new cell does not know which word it has:
|
|
@@ -243,9 +244,12 @@ Between-sessions memory pass: **VERIFY · ORGANIZE · ENRICH** against a **CLONE
|
|
|
243
244
|
```
|
|
244
245
|
$ swarph dreaming run --corpus ~/.claude/projects/.../memory --out /tmp/dreaming-out
|
|
245
246
|
$ swarph dreaming run --corpus <dir> --out <dir> --verify-only
|
|
246
|
-
$
|
|
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
|
|
247
249
|
```
|
|
248
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
|
+
|
|
249
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.
|
|
250
254
|
|
|
251
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" }
|
|
@@ -390,8 +390,38 @@ def _thread_url(gateway: str, card_id: int, *, limit: Optional[int] = None) -> s
|
|
|
390
390
|
return f"{base}?limit={limit}" if limit else base
|
|
391
391
|
|
|
392
392
|
|
|
393
|
-
def
|
|
394
|
-
"""
|
|
393
|
+
def _project_owner_orchestrator(gw: str, token: str, project_id) -> Optional[str]:
|
|
394
|
+
"""Resolve ``projects.owner_orchestrator`` for a card's project_id.
|
|
395
|
+
|
|
396
|
+
>>> THE CARD PAYLOAD DOES NOT CARRY THE OWNER (#864). <<< Measured
|
|
397
|
+
2026-09-17: GET /board/cards/{id} has assignee/project_id and no owner
|
|
398
|
+
field; GET /board/projects rows carry ``owner_orchestrator`` (NOT NULL on
|
|
399
|
+
the server). A second call is required — inventing a sentinel peer is the
|
|
400
|
+
#259 failure mode this helper exists to avoid.
|
|
401
|
+
"""
|
|
402
|
+
if project_id is None:
|
|
403
|
+
return None
|
|
404
|
+
st, data = _http_get_json(f"{gw.rstrip('/')}/board/projects", token)
|
|
405
|
+
if st != 200:
|
|
406
|
+
return None
|
|
407
|
+
rows = data if isinstance(data, list) else (data or {}).get("projects", [])
|
|
408
|
+
for row in rows or []:
|
|
409
|
+
if row.get("id") == project_id or str(row.get("id")) == str(project_id):
|
|
410
|
+
owner = (row.get("owner_orchestrator") or "").strip()
|
|
411
|
+
return owner or None
|
|
412
|
+
return None
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def _thread_recipient(
|
|
416
|
+
card: dict,
|
|
417
|
+
explicit_to: Optional[str],
|
|
418
|
+
*,
|
|
419
|
+
owner_orchestrator: Optional[str] = None,
|
|
420
|
+
) -> "tuple[str, str]":
|
|
421
|
+
"""Who a card-thread post is addressed to, and why.
|
|
422
|
+
|
|
423
|
+
Order: ``--to`` > card assignee > project ``owner_orchestrator`` (#864).
|
|
424
|
+
Returns ``(to_node, reason)`` so the confirmation line can name the choice.
|
|
395
425
|
|
|
396
426
|
>>> RAISES RATHER THAN INVENTING A SENTINEL. <<< POST /messages requires
|
|
397
427
|
exactly one of {to_node, channel}, so a card post needs a real recipient. The
|
|
@@ -401,18 +431,21 @@ def _thread_recipient(card: dict, explicit_to: Optional[str]) -> str:
|
|
|
401
431
|
A placeholder here would manufacture that defect once per card post.
|
|
402
432
|
"""
|
|
403
433
|
if explicit_to:
|
|
404
|
-
return explicit_to
|
|
434
|
+
return explicit_to, "--to"
|
|
405
435
|
assignee = card.get("assignee")
|
|
406
436
|
if assignee:
|
|
407
|
-
return assignee
|
|
437
|
+
return assignee, "card assignee"
|
|
438
|
+
if owner_orchestrator:
|
|
439
|
+
return owner_orchestrator, "project owner_orchestrator"
|
|
408
440
|
raise RuntimeError(
|
|
409
|
-
f"card #{card.get('id')} has no assignee
|
|
410
|
-
f"
|
|
411
|
-
f"wire; it needs
|
|
441
|
+
f"card #{card.get('id')} has no assignee and project owner_orchestrator "
|
|
442
|
+
f"is unresolvable, so there is no default recipient for a thread post — "
|
|
443
|
+
f"pass --to <peer>. (A card post is still a DM on the wire; it needs "
|
|
444
|
+
f"someone to be addressed to.)"
|
|
412
445
|
)
|
|
413
446
|
|
|
414
447
|
|
|
415
|
-
def _say_line(resp: dict, card_id, to_node: str) -> str:
|
|
448
|
+
def _say_line(resp: dict, card_id, to_node: str, *, reason: Optional[str] = None) -> str:
|
|
416
449
|
"""The post confirmation — AND any obligation the post just DISCHARGED.
|
|
417
450
|
|
|
418
451
|
>>> THE GATEWAY ALREADY SAID SO AND THIS CLI THREW IT AWAY. <<< POST
|
|
@@ -435,7 +468,11 @@ def _say_line(resp: dict, card_id, to_node: str) -> str:
|
|
|
435
468
|
POLICY (that is #562's own question) -- it is the fix for the holder not
|
|
436
469
|
being told, which is what made six hours of divergence possible.
|
|
437
470
|
"""
|
|
438
|
-
|
|
471
|
+
if reason:
|
|
472
|
+
line = (f"posted id={resp.get('id')} onto card #{card_id} "
|
|
473
|
+
f"(to {to_node}; {reason})")
|
|
474
|
+
else:
|
|
475
|
+
line = f"posted id={resp.get('id')} onto card #{card_id} (to {to_node})"
|
|
439
476
|
closed = resp.get("closed_obligations") or []
|
|
440
477
|
if closed:
|
|
441
478
|
ids = ", ".join(f"#{i}" for i in closed)
|
|
@@ -855,7 +892,8 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
855
892
|
add_content_args(cy)
|
|
856
893
|
cy.add_argument("--kind", default="fyi", help="status|question|answer|unblock|fyi")
|
|
857
894
|
cy.add_argument("--to", dest="to_node", default=None,
|
|
858
|
-
help="recipient peer (default:
|
|
895
|
+
help="recipient peer (default: card assignee, else project "
|
|
896
|
+
"owner_orchestrator; refused if neither resolves)")
|
|
859
897
|
_add_common(cy)
|
|
860
898
|
|
|
861
899
|
ck = cards.add_parser(
|
|
@@ -1278,8 +1316,15 @@ def run_board(argv: list[str]) -> int:
|
|
|
1278
1316
|
f"(it predates #181a). Run scripts/migrate_card_threads.py on "
|
|
1279
1317
|
f"the gateway host.", file=sys.stderr)
|
|
1280
1318
|
return 1
|
|
1319
|
+
# #864: card GET has no owner field — only fetch projects when the
|
|
1320
|
+
# cheaper defaults (explicit --to, card assignee) are absent.
|
|
1321
|
+
owner = None
|
|
1322
|
+
if not args.to_node and not card.get("assignee"):
|
|
1323
|
+
owner = _project_owner_orchestrator(gw, token, card.get("project_id"))
|
|
1281
1324
|
try:
|
|
1282
|
-
to_node = _thread_recipient(
|
|
1325
|
+
to_node, reason = _thread_recipient(
|
|
1326
|
+
card, args.to_node, owner_orchestrator=owner,
|
|
1327
|
+
)
|
|
1283
1328
|
except RuntimeError as exc:
|
|
1284
1329
|
print(f"swarph board cards say: {exc}", file=sys.stderr)
|
|
1285
1330
|
return 1
|
|
@@ -1293,7 +1338,9 @@ def run_board(argv: list[str]) -> int:
|
|
|
1293
1338
|
# explicit `propose` grant. `_out` passes `detail` through whole; it does
|
|
1294
1339
|
# not need help, and a second copy of that logic is a second thing to
|
|
1295
1340
|
# keep in sync.
|
|
1296
|
-
return _out(
|
|
1341
|
+
return _out(
|
|
1342
|
+
st, d, lambda x: _say_line(x, args.id, to_node, reason=reason), aj,
|
|
1343
|
+
)
|
|
1297
1344
|
if args.command == "ready":
|
|
1298
1345
|
st, d = _patch_json(f"{gw}/board/cards/{args.id}", {"actor": self_name, "move_ready": not args.clear}, token)
|
|
1299
1346
|
return _out(st, d, lambda x: f"card #{x.get('id')} move_ready -> {x.get('move_ready')}", aj)
|
|
@@ -37,12 +37,65 @@ import sys
|
|
|
37
37
|
from swarph_cli.commands.codegraph_hook import _match_quality
|
|
38
38
|
|
|
39
39
|
DEFAULT_INDEX = os.path.expanduser("~/.swarph/codegraph/index.db")
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
|
|
40
|
+
# >>> THERE IS NO DEFAULT IDENTITY ANY MORE. THIS CONSTANT IS GONE ON PURPOSE. <<<
|
|
41
|
+
#
|
|
42
|
+
# It used to read `DEFAULT_CALLER_CELL = "lab-ovh"`, and that one line meant every
|
|
43
|
+
# unconfigured caller on lab-ovh queried with the ORCHESTRATOR'S READ AUTHORITY.
|
|
44
|
+
#
|
|
45
|
+
# MEASURED 2026-09-18 (science-claude, mesh 43183/43186/43188). The gateway was never
|
|
46
|
+
# bypassed and nothing was ever spoofed: `_query_via_gateway` sends NO caller field, so
|
|
47
|
+
# the server binds identity from the bearer token, correctly. What the default did was
|
|
48
|
+
# pick WHICH REAL TOKEN got presented — `_resolve_token(self_name, ...)` reads the file
|
|
49
|
+
# that name points at. A cell asking a question on this box authenticated AS lab-ovh,
|
|
50
|
+
# with lab-ovh's genuine credential, and got a full, plausible, correctly-authorised
|
|
51
|
+
# answer belonging to somebody else.
|
|
52
|
+
#
|
|
53
|
+
# >>> A WRONG-IDENTITY WRITE ANNOUNCES ITSELF — a DM arrives signed by the wrong cell
|
|
54
|
+
# and someone notices. A WRONG-IDENTITY READ ANNOUNCES NOTHING. <<< It was found only
|
|
55
|
+
# because a repo its owner KNEW they owned was missing from their own results.
|
|
56
|
+
#
|
|
57
|
+
# WHY REFUSE RATHER THAN WARN (commander, 2026-09-18 04:44Z): a warning on a read that
|
|
58
|
+
# returns a correct-looking answer is a line of text above a result the caller already
|
|
59
|
+
# believes. And the cost of refusing was measured first, not assumed — of 8 executable
|
|
60
|
+
# `swarph` invocations in systemd + cron on lab-ovh, 7 already pass `--as` or
|
|
61
|
+
# `--token-file`, and the 8th (`monitor reexec-on-change`) cannot authenticate at all:
|
|
62
|
+
# no --gateway, no --token-file, no --as exists on that verb. SCHEDULED WORK BREAKS IN
|
|
63
|
+
# ZERO PLACES. The population that pays is interactive use, which is the population
|
|
64
|
+
# that was silently mis-attributed.
|
|
65
|
+
#
|
|
66
|
+
# $SWARPH_SELF STILL WORKS AND IS THE INTENDED PATH. It is a DECLARED identity. What is
|
|
67
|
+
# refused is the *undeclared* case, where a package-level guess stood in for one.
|
|
68
|
+
IDENTITY_UNSET = object() # sentinel: argparse default when --caller-cell is omitted
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class IdentityNotDeclared(RuntimeError):
|
|
72
|
+
"""No caller identity was declared and there is no default to fall back to."""
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def require_caller_cell(explicit=None, *, verb: str) -> str:
|
|
76
|
+
"""Resolve the caller cell, or REFUSE.
|
|
77
|
+
|
|
78
|
+
Order: explicit flag -> $SWARPH_SELF -> $SWARPH_CELL -> refuse.
|
|
79
|
+
|
|
80
|
+
The refusal names the verb and every way to satisfy it, because an error that
|
|
81
|
+
says only "identity unset" moves the work to the reader.
|
|
82
|
+
"""
|
|
83
|
+
if explicit not in (None, IDENTITY_UNSET) and str(explicit).strip():
|
|
84
|
+
return str(explicit).strip()
|
|
85
|
+
for var in ("SWARPH_SELF", "SWARPH_CELL"):
|
|
86
|
+
v = (os.environ.get(var) or "").strip()
|
|
87
|
+
if v:
|
|
88
|
+
return v
|
|
89
|
+
raise IdentityNotDeclared(
|
|
90
|
+
f"swarph {verb}: NO CALLER IDENTITY DECLARED, and there is no default.\n"
|
|
91
|
+
f" This used to fall back to 'lab-ovh', which meant an undeclared caller\n"
|
|
92
|
+
f" queried with that cell's read authority and got somebody else's answer.\n"
|
|
93
|
+
f" Declare one of:\n"
|
|
94
|
+
f" --caller-cell <cell> for this invocation\n"
|
|
95
|
+
f" SWARPH_SELF=<cell> for this shell or unit\n"
|
|
96
|
+
f" SWARPH_CELL=<cell> (MCP hosts)\n"
|
|
97
|
+
f" It is NOT guessable: this box hosts several cells under one uid."
|
|
98
|
+
)
|
|
46
99
|
|
|
47
100
|
# NOT 1 and NOT 2. A distinct code so "nothing was searched" can never be confused
|
|
48
101
|
# with a crash or a usage error, and so a caller can branch on it specifically.
|
|
@@ -332,7 +385,7 @@ def _query_via_gateway(gateway: str, query: str, limit: int, token_file):
|
|
|
332
385
|
from swarph_cli.commands.mesh import _post_json, _resolve_token # local import: keeps
|
|
333
386
|
# the local-only path free of any mesh dependency, so an offline cell still works.
|
|
334
387
|
|
|
335
|
-
self_name =
|
|
388
|
+
self_name = require_caller_cell(verb="codegraph")
|
|
336
389
|
token = _resolve_token(self_name, token_file)
|
|
337
390
|
body = {"query": query, "limit": max(1, min(int(limit), 25))}
|
|
338
391
|
status, payload = _post_json(gateway.rstrip("/") + "/codegraph", body, token)
|
|
@@ -352,7 +405,9 @@ def run_codegraph(argv) -> int:
|
|
|
352
405
|
"is configured (the server searches and returns the answer); falls back to a local index.")
|
|
353
406
|
ap.add_argument("query", help="natural-language query, e.g. 'which function escapes HTML'")
|
|
354
407
|
ap.add_argument("--index", default=DEFAULT_INDEX, help=f"index db (default {DEFAULT_INDEX})")
|
|
355
|
-
ap.add_argument("--caller-cell", default=
|
|
408
|
+
ap.add_argument("--caller-cell", default=IDENTITY_UNSET,
|
|
409
|
+
help="A8 caller identity. NO DEFAULT — else $SWARPH_SELF / $SWARPH_CELL, "
|
|
410
|
+
"else the command REFUSES rather than guessing (it used to guess lab-ovh).")
|
|
356
411
|
ap.add_argument("--limit", type=int, default=8)
|
|
357
412
|
ap.add_argument("--json", action="store_true", help="machine-readable JSON output")
|
|
358
413
|
ap.add_argument("--gateway", default=None,
|
|
@@ -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)
|
|
@@ -130,6 +130,38 @@ def _commands_in(section: str) -> "list[str]":
|
|
|
130
130
|
return out
|
|
131
131
|
|
|
132
132
|
|
|
133
|
+
def verbs_in_guide(topics: "dict[str, str] | None" = None) -> "set[str]":
|
|
134
|
+
"""#547: the verbs the guide TEACHES, counted PER VERB (a topic count said 11 and
|
|
135
|
+
meant nothing). A verb is covered when some section's commands include it."""
|
|
136
|
+
topics = topics if topics is not None else _split_topics(_load_guide())
|
|
137
|
+
out: set[str] = set()
|
|
138
|
+
for body in topics.values():
|
|
139
|
+
for cmd in _commands_in(body):
|
|
140
|
+
parts = cmd.split()
|
|
141
|
+
if len(parts) >= 2:
|
|
142
|
+
out.add(parts[1])
|
|
143
|
+
return out
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _registry() -> "list[str]":
|
|
147
|
+
# Lazy: main dispatches handlers by dotted path and does not import this module,
|
|
148
|
+
# but keep the direction one-way anyway.
|
|
149
|
+
from swarph_cli.main import registered_verbs
|
|
150
|
+
return registered_verbs()
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _verb_entry(topics: "dict[str, str]", verb: str) -> "list[tuple[str, str]]":
|
|
154
|
+
"""The line in each topic that teaches `swarph <verb>` -- one per topic, first hit."""
|
|
155
|
+
pat = re.compile(r"`swarph " + re.escape(verb) + r"(?:[ `])")
|
|
156
|
+
hits: list[tuple[str, str]] = []
|
|
157
|
+
for name, body in topics.items():
|
|
158
|
+
for raw in body.splitlines():
|
|
159
|
+
if pat.search(raw):
|
|
160
|
+
hits.append((name, raw.strip()))
|
|
161
|
+
break
|
|
162
|
+
return hits
|
|
163
|
+
|
|
164
|
+
|
|
133
165
|
_TERM_RE = re.compile(r"\*\*(.+?)\*\*")
|
|
134
166
|
|
|
135
167
|
|
|
@@ -262,13 +294,21 @@ def run_guide(argv: "list[str]") -> int:
|
|
|
262
294
|
# `apropos`: an LLM arrives with an INTENT ("subscribe to updates"), not the
|
|
263
295
|
# topic's name ("channels"). Requiring the name is the #520 discovery defect
|
|
264
296
|
# reproduced inside its own fix.
|
|
297
|
+
term = args.search.strip().lower()
|
|
298
|
+
# #547: a VERB name resolves to the verb's own entry first -- `--search highlight`
|
|
299
|
+
# used to answer with a topic list that did not contain it.
|
|
300
|
+
verb_hits = _verb_entry(topics, term) if term in _registry() else []
|
|
265
301
|
hits = _search(topics, args.search)
|
|
266
|
-
if not hits:
|
|
302
|
+
if not hits and not verb_hits:
|
|
267
303
|
print_safe(f"swarph guide: nothing matches {args.search!r}. "
|
|
268
304
|
f"Topics: {', '.join(topics)}", stream=sys.stderr)
|
|
269
305
|
return 2
|
|
270
|
-
for name, line in
|
|
306
|
+
for name, line in verb_hits:
|
|
271
307
|
print_safe(f"{name:<22} {line}")
|
|
308
|
+
shown = {name for name, _ in verb_hits}
|
|
309
|
+
for name, line in hits:
|
|
310
|
+
if name not in shown:
|
|
311
|
+
print_safe(f"{name:<22} {line}")
|
|
272
312
|
return 0
|
|
273
313
|
|
|
274
314
|
if not args.topic:
|
|
@@ -279,6 +319,19 @@ def run_guide(argv: "list[str]") -> int:
|
|
|
279
319
|
if key in topics:
|
|
280
320
|
print_safe(topics[key])
|
|
281
321
|
return 0
|
|
322
|
+
if key in _registry():
|
|
323
|
+
# #547: every registered verb resolves, per verb (tests/test_547 pins the set):
|
|
324
|
+
# the lines that teach it, then -- when the name is also a topic's substring
|
|
325
|
+
# (`channel` -> channels) -- that one topic, as before.
|
|
326
|
+
for name, line in _verb_entry(topics, key):
|
|
327
|
+
print_safe(f"{name:<22} {line}")
|
|
328
|
+
near = [k for k in topics if key in k]
|
|
329
|
+
if len(near) == 1:
|
|
330
|
+
print_safe("")
|
|
331
|
+
print_safe(topics[near[0]])
|
|
332
|
+
else:
|
|
333
|
+
print_safe(f"\n more: swarph {key} --help")
|
|
334
|
+
return 0
|
|
282
335
|
|
|
283
336
|
# Substring fallback before failing: `swarph guide channel` should find `channels`.
|
|
284
337
|
hits = [k for k in topics if key in k]
|
|
@@ -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()
|
|
@@ -151,7 +151,8 @@ def _codegraph_query(query: str, *, limit: int = 8) -> list[dict]:
|
|
|
151
151
|
|
|
152
152
|
Delegates to :func:`codegraph.structural_query` against the module-level
|
|
153
153
|
``_CODEGRAPH_INDEX`` path, using ``SWARPH_CELL`` (else
|
|
154
|
-
``codegraph.
|
|
154
|
+
``codegraph.require_caller_cell``, which REFUSES rather than defaulting) as
|
|
155
|
+
the A8 caller identity and the
|
|
155
156
|
default operate-what-you-own allowlist (``allowlist=None``).
|
|
156
157
|
|
|
157
158
|
NEVER raises — any exception (missing index, corrupt db, bad query, or
|
|
@@ -162,7 +163,13 @@ def _codegraph_query(query: str, *, limit: int = 8) -> list[dict]:
|
|
|
162
163
|
to keep the tool output tight for the calling agent.
|
|
163
164
|
"""
|
|
164
165
|
try:
|
|
165
|
-
|
|
166
|
+
# NO DEFAULT IDENTITY (2026-09-18). `codegraph.DEFAULT_CALLER_CELL` is gone;
|
|
167
|
+
# an undeclared caller used to become lab-ovh and receive that cell's read
|
|
168
|
+
# authority. require_caller_cell raises IdentityNotDeclared, which the
|
|
169
|
+
# NEVER-RAISES contract below turns into an empty result — FAIL-CLOSED: the
|
|
170
|
+
# MCP host gets nothing rather than somebody else's answer.
|
|
171
|
+
caller_cell = codegraph.require_caller_cell(
|
|
172
|
+
os.environ.get("SWARPH_CELL"), verb="mcp codegraph_query")
|
|
166
173
|
rows = codegraph.structural_query(
|
|
167
174
|
query,
|
|
168
175
|
index_path=_CODEGRAPH_INDEX,
|