swarph-cli 0.72.41__tar.gz → 0.72.43__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {swarph_cli-0.72.41/src/swarph_cli.egg-info → swarph_cli-0.72.43}/PKG-INFO +1 -1
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/pyproject.toml +1 -1
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/dev_extract.py +382 -19
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/gh_route.py +10 -8
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/mesh.py +391 -31
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/gh_identity.py +19 -8
- {swarph_cli-0.72.41 → swarph_cli-0.72.43/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli.egg-info/SOURCES.txt +6 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1065_release.py +174 -1
- swarph_cli-0.72.43/tests/test_1436_dev_extract_freshness.py +1207 -0
- swarph_cli-0.72.43/tests/test_1452_rework1_engine.py +300 -0
- swarph_cli-0.72.43/tests/test_1452_rework2_engine.py +283 -0
- swarph_cli-0.72.43/tests/test_1452_rework3_engine.py +264 -0
- swarph_cli-0.72.43/tests/test_1452_standing_wake_expiry.py +145 -0
- swarph_cli-0.72.43/tests/test_1470_gh_router_fail_closed.py +69 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_397_gh_identity_router.py +5 -7
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_484_codex_queue_sink.py +1 -1
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mesh_sidecar_muse_sink.py +3 -2
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_tmux_wake_runstate_defer.py +4 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/LICENSE +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/README.md +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/setup.cfg +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/codex_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/providers.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/signal_score.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/board_cost.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/board_usage.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/commander.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/committee.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/roster.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/rowclear_hook.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/skunkworks.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/sweep.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/triage.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/commit_trailers.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/duplicate_session.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/guide/GUIDE.md +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/launchd/swarph-codex-outbox.plist +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/launchd/swarph-codex-outbox.timer.plist +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/launchd/swarph-monitor.plist +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/launchd/swarph-watchdog.plist +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/launchd/swarph-watchdog.timer.plist +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/launchd_render.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/operator/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/operator/__main__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/operator/api.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/operator/cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/operator/config.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/operator/fmt.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/quota_sync.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/redact.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/rowclear.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/scrub.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-triage.service +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/the_ten.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/triage/__init__.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/triage/backend.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/triage/job.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/triage/owners.json +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/triage/router.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/triage/rows.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli/triage/sensor.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1006_board_publisher.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1006_session_board.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1010_strand_only.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1013_spawn_channel.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1017_muse_tui.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1034_copy_mode.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1050_surrogate_wake.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1052_opencode_deaf.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1059_watchdog_unread_env.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1061_roster_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1064_stuck_sweep.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1066_quiet_wakes.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1068_structured_accept_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1071_quota_sync.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1073_triage.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1073_triage_board.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1073_wheel_install.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1075_task_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1083_openai_decisions.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1144_cell_yaml_github.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1197_commander_taps.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1203_swarph_me_refusal.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1206_offer_question.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1214_egress.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1219_egress_probe.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1221_quota_windows.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1222_maybe_start_cap.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1228_quota_reach.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1243_the_ten.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1248_ship_price_table.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1250_price_cache.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1256_commander_wake.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1261_mcp_install.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1262_wake_followups.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1265_wake_note.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1269_triage_label.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1277_close_usage.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1278_dreaming_reach.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1286_dm_unread_cursor.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1297_commander.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1300_authorization_check.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1301_restart_skew.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1320_commit_trailers.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1321_layered_redaction.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1340_router_rollout.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1346_shell_string_gh.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1347_shell_depth_cap.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1353_obligation_release_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1385_duplicate_session_argv.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1396_dev_extract.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1405_skunkworks_basic.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1405_skunkworks_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_1427_membrane_workflow.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_3130_sender.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_3150_identity_router_install.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_432_rowclear.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_513_duplicate_session.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_538_signal_bench.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_729_arm_check_delivery_gap.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_735_dm_mcp_tools.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_739_wake_writer.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_931_board_search.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_935_deadline_clock.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_961_cursor_grok_footer.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_961_loud_stop.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_bench_codex_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_board_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_committee_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_copilot_membrane.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_copilot_pane_reader.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_group_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_import_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_init_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_launchd_units.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_main.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_operator_me.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_scrub.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_security.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_service_app.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_service_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_version_command.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.72.41 → swarph_cli-0.72.43}/tests/test_windows_waker_installer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.43
|
|
4
4
|
Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "swarph-cli"
|
|
7
|
-
version = "0.72.
|
|
7
|
+
version = "0.72.43"
|
|
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" }
|
|
@@ -10,6 +10,25 @@ The extract JOINS two halves, each with its own as-of pin:
|
|
|
10
10
|
the report header stamp plus ``Layer N:`` lines only, and deploy units
|
|
11
11
|
for visible repos — no rels/depends-on/blast-radius/arrow/import lines.
|
|
12
12
|
STALE when older than the last repo.merged for a repo.
|
|
13
|
+
A local ref is not evidence when it cannot be trusted (card #1436):
|
|
14
|
+
``git fetch origin main`` fails, origin is not the index slug, or the
|
|
15
|
+
branch tracks a remote other than that slug. Slug compare is
|
|
16
|
+
case-insensitive. A missing FETCH_HEAD is not itself stale — the fetch
|
|
17
|
+
runs, including under ``--print-only``, and writes FETCH_HEAD and
|
|
18
|
+
``refs/remotes/origin/main`` only (15s, one repo at a time). Other
|
|
19
|
+
``refs/remotes/origin/*`` refs do not move. A recorded fetch older than
|
|
20
|
+
``FETCH_TRUST_BOUND_HOURS`` is not evidence. FETCH_HEAD is
|
|
21
|
+
``git rev-parse FETCH_HEAD``; unreadable FETCH_HEAD, or a commit that
|
|
22
|
+
is not the ref commit, is not evidence. ``fresh`` requires that same
|
|
23
|
+
commit on the compared ref, and a report stamp for it. The line names
|
|
24
|
+
the commit the report described and the ref compared. Printed origin
|
|
25
|
+
URLs drop every userinfo form (user-only, ``user:password``, scp
|
|
26
|
+
``user@host:path``) and carry no query or fragment. Fetch errors are
|
|
27
|
+
redacted before the 180-character cut. A malformed origin URL reads
|
|
28
|
+
not fresh and does not abort the other repos. swarph-cli defines no
|
|
29
|
+
canonical-remote map; the codegraph index
|
|
30
|
+
``repos.slug`` is the identity already stored, and an empty slug says
|
|
31
|
+
the canonical remote is not defined.
|
|
13
32
|
|
|
14
33
|
Posting uses the board path when ``--card`` is given WITHOUT
|
|
15
34
|
``--print-only``; otherwise prints and posts nothing. Nothing is deployed.
|
|
@@ -39,6 +58,7 @@ import os
|
|
|
39
58
|
import re
|
|
40
59
|
import sqlite3
|
|
41
60
|
import subprocess
|
|
61
|
+
import time
|
|
42
62
|
|
|
43
63
|
DEFAULT_INDEX = os.path.expanduser("~/.swarph/codegraph/index.db")
|
|
44
64
|
DEFAULT_FED_REPORT = os.path.expanduser("~/.swarph/codegraph/federation-report.txt")
|
|
@@ -58,6 +78,16 @@ DEFAULT_MAX_LINES = 60
|
|
|
58
78
|
FLOOR_CALLERS = "0 callers (floor: HTTP callers not linked yet)"
|
|
59
79
|
FLOOR_ROUTES = "0 routes (floor: route registry not linked for this symbol)"
|
|
60
80
|
|
|
81
|
+
# swarph-cli does not define a canonical git remote or a fetch-age bound.
|
|
82
|
+
# ``repos.slug`` in the codegraph index (owner/repo) is the identity that
|
|
83
|
+
# index already stores. A remote URL is that remote when its owner/repo
|
|
84
|
+
# matches the slug. A recorded fetch older than this many hours is not
|
|
85
|
+
# evidence the local ref is current (card #1436).
|
|
86
|
+
FETCH_TRUST_BOUND_HOURS = 24
|
|
87
|
+
COMPARED_REF = "refs/remotes/origin/main"
|
|
88
|
+
_REPO_STAMP_RE = re.compile(r"^# repo (\S+) ([0-9a-f]{7,40}) (\S+)\s*$")
|
|
89
|
+
_SHA_RE = re.compile(r"^[0-9a-f]{7,40}$")
|
|
90
|
+
|
|
61
91
|
_TOKEN_RE = re.compile(r"`([^`]+)`")
|
|
62
92
|
_SNAKE_RE = re.compile(r"(?<![A-Za-z0-9_])_?[a-z][a-z0-9]*(?:_[a-z0-9]+){1,}")
|
|
63
93
|
_ROUTE_RE = re.compile(r"(?:POST|GET|PUT|PATCH|DELETE)\s+/\S+|/\S*chat\S*|/\S*sync\S*")
|
|
@@ -175,6 +205,14 @@ def repo_registry(con) -> dict:
|
|
|
175
205
|
for name, p in paths.items():
|
|
176
206
|
if name in out:
|
|
177
207
|
out[name]["path"] = p
|
|
208
|
+
try:
|
|
209
|
+
slugs = dict(con.execute(
|
|
210
|
+
"SELECT name, slug FROM repos LIMIT 100").fetchall())
|
|
211
|
+
except sqlite3.Error:
|
|
212
|
+
slugs = {}
|
|
213
|
+
for name, slug in slugs.items():
|
|
214
|
+
if name in out and isinstance(slug, str):
|
|
215
|
+
out[name]["slug"] = slug
|
|
178
216
|
return out
|
|
179
217
|
|
|
180
218
|
|
|
@@ -414,9 +452,15 @@ def read_fed_report(path: str,
|
|
|
414
452
|
if not generated:
|
|
415
453
|
return {"status": "unavailable: no header stamp"}
|
|
416
454
|
layers = [ln.strip() for ln in lines if _LAYER_RE.match(ln)]
|
|
455
|
+
repo_commits = {}
|
|
456
|
+
for ln in lines:
|
|
457
|
+
m = _REPO_STAMP_RE.match(ln.strip())
|
|
458
|
+
if m:
|
|
459
|
+
repo_commits[m.group(1)] = m.group(2)
|
|
417
460
|
return {
|
|
418
461
|
"status": "ok", "generated": generated,
|
|
419
462
|
"layers": layers, "cut": cut, "scanned": min(len(lines), line_cap),
|
|
463
|
+
"repo_commits": repo_commits,
|
|
420
464
|
}
|
|
421
465
|
|
|
422
466
|
|
|
@@ -458,18 +502,287 @@ def read_structurizr(path: str, repos: list) -> dict:
|
|
|
458
502
|
}
|
|
459
503
|
|
|
460
504
|
|
|
461
|
-
def
|
|
462
|
-
|
|
463
|
-
|
|
505
|
+
def _one_line(text: str, limit: int = 180) -> str:
|
|
506
|
+
line = " ".join((text or "").split())
|
|
507
|
+
return line[:limit]
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def owner_repo(url: str) -> str | None:
|
|
511
|
+
"""``owner/repo`` from a git remote URL, or None when it has no such pair."""
|
|
512
|
+
raw = (url or "").strip().rstrip("/")
|
|
513
|
+
if raw.endswith(".git"):
|
|
514
|
+
raw = raw[:-4]
|
|
515
|
+
if raw.startswith("file://"):
|
|
516
|
+
from urllib.parse import unquote
|
|
517
|
+
raw = unquote(raw[7:])
|
|
518
|
+
elif "://" in raw:
|
|
519
|
+
raw = raw.split("://", 1)[1]
|
|
520
|
+
host = raw.split("/", 1)[0]
|
|
521
|
+
if "@" in host:
|
|
522
|
+
raw = raw.split("@", 1)[1]
|
|
523
|
+
elif re.match(r"^[A-Za-z]:", raw):
|
|
524
|
+
pass # Windows path — drive letter is not scp-style host:path
|
|
525
|
+
elif ":" in raw:
|
|
526
|
+
raw = raw.split(":", 1)[1]
|
|
527
|
+
parts = [p for p in re.split(r"[/\\]+", raw) if p]
|
|
528
|
+
if len(parts) < 2:
|
|
464
529
|
return None
|
|
530
|
+
return f"{parts[-2]}/{parts[-1]}"
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def _same_slug(owner: str | None, slug: str) -> bool:
|
|
534
|
+
"""Index slug vs remote owner/repo. Case-insensitive (PROVEN vs proven)."""
|
|
535
|
+
return owner is not None and owner.casefold() == slug.casefold()
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
_URL_USERINFO_RE = re.compile(
|
|
539
|
+
r"(?P<scheme>[a-z][a-z0-9+.-]*://)(?:[^/\s@]+)(?::[^/\s@]*)?@",
|
|
540
|
+
re.IGNORECASE,
|
|
541
|
+
)
|
|
542
|
+
# Query or fragment on a scheme URL inside a git error line.
|
|
543
|
+
_PRINTED_QUERY_RE = re.compile("(://[^\\s'\"]*?)[?#][^\\s'\"]*")
|
|
544
|
+
# ``user@host:`` as ssh prints it (``user@host: Permission denied``).
|
|
545
|
+
_SCP_USER_RE = re.compile("(?<![\\w./-])[^\\s/:@'\"]+@(?=[^\\s/:@'\"]+:)")
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def _strip_scp_user(url: str) -> str:
|
|
549
|
+
"""``user@host:path`` → ``host:path``. A Windows drive is not scp."""
|
|
550
|
+
if re.match(r"^[A-Za-z]:", url):
|
|
551
|
+
return url
|
|
552
|
+
if "@" not in url:
|
|
553
|
+
return url
|
|
554
|
+
_user, rest = url.split("@", 1)
|
|
555
|
+
if ":" not in rest or not rest.split(":", 1)[0]:
|
|
556
|
+
return url
|
|
557
|
+
return rest
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
def _strip_userinfo_parsed(url: str) -> str:
|
|
561
|
+
"""Strip userinfo, query, and fragment. Raises ValueError on a bad URL."""
|
|
562
|
+
from urllib.parse import urlsplit, urlunsplit
|
|
563
|
+
if "://" not in url:
|
|
564
|
+
return re.split(r"[?#]", _strip_scp_user(url))[0]
|
|
565
|
+
parts = urlsplit(url)
|
|
566
|
+
# ``.port`` / ``.hostname`` raise ValueError for ``:notaport`` and ``[bad``.
|
|
567
|
+
if parts.username is None and parts.password is None:
|
|
568
|
+
return urlunsplit((parts.scheme, parts.netloc, parts.path, "", ""))
|
|
569
|
+
host = parts.hostname or ""
|
|
570
|
+
if ":" in host and not host.startswith("["):
|
|
571
|
+
host = f"[{host}]"
|
|
572
|
+
netloc = f"{host}:{parts.port}" if parts.port else host
|
|
573
|
+
return urlunsplit((parts.scheme, netloc, parts.path, "", ""))
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def _strip_userinfo(url: str) -> str:
|
|
577
|
+
"""Drop userinfo before an origin URL is printed.
|
|
578
|
+
|
|
579
|
+
Covers user-only (``https://TOKEN@host``, ``ssh://TOKEN@host``),
|
|
580
|
+
``user:password``, and scp-style ``TOKEN@host:path``. A printed origin
|
|
581
|
+
keeps neither a query nor a fragment. A malformed URL (``ValueError``
|
|
582
|
+
from urllib) is redacted and does not propagate.
|
|
583
|
+
"""
|
|
584
|
+
try:
|
|
585
|
+
return _strip_userinfo_parsed(url)
|
|
586
|
+
except ValueError:
|
|
587
|
+
return re.split(
|
|
588
|
+
r"[?#]", _URL_USERINFO_RE.sub(r"\g<scheme>", url or ""))[0]
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def _redact_printed(text: str) -> str:
|
|
592
|
+
"""Drop userinfo and any query or fragment embedded in a git error line.
|
|
593
|
+
|
|
594
|
+
Scheme URLs lose userinfo, then query and fragment. An scp denial
|
|
595
|
+
(``user@host: Permission denied``) loses the user too.
|
|
596
|
+
"""
|
|
597
|
+
if not text:
|
|
598
|
+
return text
|
|
599
|
+
text = _PRINTED_QUERY_RE.sub(r"\1", _URL_USERINFO_RE.sub(r"\g<scheme>", text))
|
|
600
|
+
return _SCP_USER_RE.sub("", text)
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
def _same_commit(report_sha, ref_sha) -> bool:
|
|
604
|
+
"""True only when both shas name one commit (full or unique prefix)."""
|
|
605
|
+
if not isinstance(report_sha, str) or not isinstance(ref_sha, str):
|
|
606
|
+
return False
|
|
607
|
+
a, b = report_sha.strip().lower(), ref_sha.strip().lower()
|
|
608
|
+
if not _SHA_RE.fullmatch(a) or not _SHA_RE.fullmatch(b):
|
|
609
|
+
return False
|
|
610
|
+
if a == b:
|
|
611
|
+
return True
|
|
612
|
+
short, long_ = (a, b) if len(a) < len(b) else (b, a)
|
|
613
|
+
return long_.startswith(short)
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def _git(repo: str, args: list, timeout: int = 10):
|
|
617
|
+
"""One git invocation. None on timeout or if git cannot be started."""
|
|
465
618
|
try:
|
|
466
|
-
|
|
467
|
-
["git", "
|
|
468
|
-
|
|
469
|
-
encoding="utf-8", errors="replace"
|
|
470
|
-
|
|
471
|
-
|
|
619
|
+
return subprocess.run(
|
|
620
|
+
["git", "-C", repo, "-c", "core.hooksPath=/dev/null", *args],
|
|
621
|
+
capture_output=True, text=True, timeout=timeout,
|
|
622
|
+
encoding="utf-8", errors="replace",
|
|
623
|
+
env={**os.environ, "GIT_TERMINAL_PROMPT": "0"},
|
|
624
|
+
)
|
|
625
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
626
|
+
return None
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
def _git_out(repo: str, args: list, timeout: int = 10) -> str | None:
|
|
630
|
+
proc = _git(repo, args, timeout=timeout)
|
|
631
|
+
if proc is None or proc.returncode != 0:
|
|
632
|
+
return None
|
|
633
|
+
text = (proc.stdout or "").strip()
|
|
634
|
+
return text or None
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
def _ref_snapshot(repo_path: str) -> dict:
|
|
638
|
+
"""Local ``refs/remotes/origin/main`` sha and committer time, if present."""
|
|
639
|
+
sha = _git_out(repo_path, ["rev-parse", "--verify", COMPARED_REF])
|
|
640
|
+
if not sha or not _SHA_RE.fullmatch(sha):
|
|
641
|
+
sha = None
|
|
642
|
+
merged = _git_out(repo_path, ["log", "-1", "--format=%cI", COMPARED_REF])
|
|
643
|
+
return {"sha": sha, "merged_at": merged}
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
def _remote_untrusted(repo_path: str, canonical_slug: str | None) -> str | None:
|
|
647
|
+
"""Origin or the upstream's remote is not the canonical slug.
|
|
648
|
+
|
|
649
|
+
The upstream check reads that remote's URL and compares owner/repo.
|
|
650
|
+
It does not match the literal ``fork/main``. ``upstream/main`` and
|
|
651
|
+
``fork/dev`` are not fresh when those remotes are not canonical.
|
|
652
|
+
"""
|
|
653
|
+
slug = (canonical_slug or "").strip()
|
|
654
|
+
if not slug:
|
|
655
|
+
return ("canonical remote is not defined "
|
|
656
|
+
"(swarph-cli has no canonical-remote map; index slug is empty)")
|
|
657
|
+
url = _git_out(repo_path, ["remote", "get-url", "origin"])
|
|
658
|
+
if not url:
|
|
659
|
+
return (f"origin is not the canonical remote {slug} "
|
|
660
|
+
"(origin URL unreadable)")
|
|
661
|
+
if not _same_slug(owner_repo(url), slug):
|
|
662
|
+
return f"origin {_strip_userinfo(url)} is not the canonical remote {slug}"
|
|
663
|
+
upstream = _git_out(
|
|
664
|
+
repo_path, ["rev-parse", "--abbrev-ref", "@{upstream}"])
|
|
665
|
+
if not upstream:
|
|
666
|
+
return None
|
|
667
|
+
short = upstream[len("refs/remotes/"):] if upstream.startswith(
|
|
668
|
+
"refs/remotes/") else upstream
|
|
669
|
+
remote_name = short.split("/", 1)[0]
|
|
670
|
+
remote_url = (_git_out(repo_path, ["remote", "get-url", remote_name])
|
|
671
|
+
if remote_name else None)
|
|
672
|
+
if not remote_url or not _same_slug(owner_repo(remote_url), slug):
|
|
673
|
+
return f"branch tracks {short}"
|
|
674
|
+
return None
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
def _fetch_age_untrusted(repo_path: str, now: float) -> str | None:
|
|
678
|
+
"""Recorded fetch older than ``FETCH_TRUST_BOUND_HOURS``.
|
|
679
|
+
|
|
680
|
+
A missing FETCH_HEAD is not stale. A fresh clone or worktree falls
|
|
681
|
+
through so the fetch below can record one.
|
|
682
|
+
"""
|
|
683
|
+
bound = f"{FETCH_TRUST_BOUND_HOURS}h"
|
|
684
|
+
rel = _git_out(repo_path, ["rev-parse", "--git-path", "FETCH_HEAD"])
|
|
685
|
+
path = None
|
|
686
|
+
if rel:
|
|
687
|
+
path = rel if os.path.isabs(rel) else os.path.join(repo_path, rel)
|
|
688
|
+
if not path or not os.path.isfile(path):
|
|
689
|
+
return None
|
|
690
|
+
mtime = os.path.getmtime(path)
|
|
691
|
+
if now - mtime > FETCH_TRUST_BOUND_HOURS * 3600:
|
|
692
|
+
import datetime as _dt
|
|
693
|
+
stamp = _dt.datetime.fromtimestamp(
|
|
694
|
+
mtime, _dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
695
|
+
return f"last fetch {stamp} is older than {bound}"
|
|
696
|
+
return None
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
def _fetch_untrusted(repo_path: str) -> str | None:
|
|
700
|
+
"""``git fetch origin main`` failed, so a remote merge is invisible.
|
|
701
|
+
|
|
702
|
+
The refspec is ``origin main``, as merge_watch fetches it, so an
|
|
703
|
+
unrelated branch conflict does not fail a healthy main. This writes
|
|
704
|
+
FETCH_HEAD and the origin main ref in the checkout, including under
|
|
705
|
+
``--print-only``. One repo at a time, 15s.
|
|
706
|
+
"""
|
|
707
|
+
proc = _git(repo_path, ["fetch", "--quiet", "--no-tags", "origin", "main"],
|
|
708
|
+
timeout=15)
|
|
709
|
+
if proc is not None and proc.returncode == 0:
|
|
472
710
|
return None
|
|
711
|
+
if proc is None:
|
|
712
|
+
detail = "git fetch origin main failed"
|
|
713
|
+
else:
|
|
714
|
+
raw = proc.stderr or proc.stdout or ""
|
|
715
|
+
detail = _one_line(_redact_printed(raw)) or "git fetch origin main failed"
|
|
716
|
+
return f"fetch failed: {detail}"
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def _fetch_head_sha(repo_path: str) -> str | None:
|
|
720
|
+
"""Sha from ``git rev-parse FETCH_HEAD``, or None when that fails."""
|
|
721
|
+
sha = (_git_out(repo_path, ["rev-parse", "FETCH_HEAD"]) or "").lower()
|
|
722
|
+
if not _SHA_RE.fullmatch(sha):
|
|
723
|
+
return None
|
|
724
|
+
return sha
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
def read_ref_trust(repo_path: str | None,
|
|
728
|
+
canonical_slug: str | None = None,
|
|
729
|
+
*, now: float | None = None) -> dict:
|
|
730
|
+
"""Whether local origin/main may be compared to the federation build.
|
|
731
|
+
|
|
732
|
+
Untrusted results still name the local ref. A trusted result is a
|
|
733
|
+
canonical origin whose upstream remote is that same owner/repo,
|
|
734
|
+
fetched inside the bound, whose ``git fetch origin main`` succeeded
|
|
735
|
+
just now and whose FETCH_HEAD names that same ref. The ref is read
|
|
736
|
+
again after the fetch, including when the fetch fails.
|
|
737
|
+
"""
|
|
738
|
+
moment = time.time() if now is None else now
|
|
739
|
+
base = {
|
|
740
|
+
"ref": COMPARED_REF, "ref_sha": None, "merged_at": None,
|
|
741
|
+
"trusted": False, "reason": None, "report_sha": None,
|
|
742
|
+
}
|
|
743
|
+
if not repo_path or not os.path.isdir(repo_path):
|
|
744
|
+
base["reason"] = "repo path is not a directory"
|
|
745
|
+
return base
|
|
746
|
+
snap = _ref_snapshot(repo_path)
|
|
747
|
+
base["ref_sha"] = snap["sha"]
|
|
748
|
+
base["merged_at"] = snap["merged_at"]
|
|
749
|
+
# Remote check (card #1436): origin, or the upstream's remote, is not canonical.
|
|
750
|
+
remote_reason = _remote_untrusted(repo_path, canonical_slug)
|
|
751
|
+
if remote_reason:
|
|
752
|
+
base["reason"] = remote_reason
|
|
753
|
+
return base
|
|
754
|
+
# Age check (card #1436): a recorded fetch older than the bound.
|
|
755
|
+
# Missing FETCH_HEAD falls through to the fetch.
|
|
756
|
+
age_reason = _fetch_age_untrusted(repo_path, moment)
|
|
757
|
+
if age_reason:
|
|
758
|
+
base["reason"] = age_reason
|
|
759
|
+
return base
|
|
760
|
+
# Fetch ``origin main``. Re-read the ref after the attempt, success or
|
|
761
|
+
# failure, so the compared sha is not the pre-fetch commit.
|
|
762
|
+
fetch_reason = _fetch_untrusted(repo_path)
|
|
763
|
+
snap = _ref_snapshot(repo_path)
|
|
764
|
+
base["ref_sha"] = snap["sha"]
|
|
765
|
+
base["merged_at"] = snap["merged_at"]
|
|
766
|
+
if fetch_reason:
|
|
767
|
+
base["reason"] = fetch_reason
|
|
768
|
+
return base
|
|
769
|
+
# A good fetch can still leave origin/main behind: no refspec, or a
|
|
770
|
+
# narrow one, writes FETCH_HEAD and does not move the ref. Those
|
|
771
|
+
# commits differ, so the ref is not fresh. Unreadable FETCH_HEAD is
|
|
772
|
+
# not fresh either — do not skip the compare.
|
|
773
|
+
fetched = _fetch_head_sha(repo_path)
|
|
774
|
+
if not fetched:
|
|
775
|
+
base["reason"] = "FETCH_HEAD unreadable after fetch"
|
|
776
|
+
return base
|
|
777
|
+
if snap["sha"] and not _same_commit(fetched, snap["sha"]):
|
|
778
|
+
base["reason"] = "fetched commit differs from the ref commit"
|
|
779
|
+
return base
|
|
780
|
+
if not snap["merged_at"]:
|
|
781
|
+
base["reason"] = "origin/main has no commit time after fetch"
|
|
782
|
+
return base
|
|
783
|
+
base["trusted"] = True
|
|
784
|
+
base["reason"] = None
|
|
785
|
+
return base
|
|
473
786
|
|
|
474
787
|
|
|
475
788
|
def indexed_sha(repo_path: str | None) -> str | None:
|
|
@@ -533,7 +846,7 @@ def build_extract(*, tokens: list, index_path: str = DEFAULT_INDEX,
|
|
|
533
846
|
card_allowlist_path: str | None = DEFAULT_CARD_ALLOWLIST,
|
|
534
847
|
entitled: bool = False) -> dict:
|
|
535
848
|
"""Assemble the extract dict. Never raises on bad sources (unavailable)."""
|
|
536
|
-
|
|
849
|
+
merged_override = merged_lookup
|
|
537
850
|
tokens = [_normalize_token(t) for t in (tokens or [])]
|
|
538
851
|
tokens = [t for t in tokens if t and is_lookup_token(t)]
|
|
539
852
|
fed_docs = fed_docs_state(fed_docs_db)
|
|
@@ -593,10 +906,28 @@ def build_extract(*, tokens: list, index_path: str = DEFAULT_INDEX,
|
|
|
593
906
|
# Shape-only federation half: header stamp + `Layer N:` lines only.
|
|
594
907
|
struct = read_structurizr(structurizr_ws, repos_hit)
|
|
595
908
|
fed = read_fed_report(fed_report)
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
909
|
+
report_commits = fed.get("repo_commits") or {}
|
|
910
|
+
pins = {}
|
|
911
|
+
for repo in repos_hit:
|
|
912
|
+
reg = registry.get(repo) or {}
|
|
913
|
+
path = reg.get("path")
|
|
914
|
+
described = report_commits.get(repo)
|
|
915
|
+
pin = {"sha": indexed_sha(path),
|
|
916
|
+
"indexed_at": reg.get("indexed_at"),
|
|
917
|
+
"report_sha": described}
|
|
918
|
+
if merged_override is None:
|
|
919
|
+
trust = read_ref_trust(
|
|
920
|
+
path, reg.get("slug") if isinstance(reg.get("slug"), str) else None)
|
|
921
|
+
trust["report_sha"] = described
|
|
922
|
+
pin["ref_trust"] = trust
|
|
923
|
+
pin["merged_at"] = trust.get("merged_at") if trust.get("trusted") else None
|
|
924
|
+
else:
|
|
925
|
+
pin["merged_at"] = merged_override(path)
|
|
926
|
+
pins[repo] = pin
|
|
927
|
+
# repo_commits names every stamped repo, including withheld ones.
|
|
928
|
+
# Do not return that map past the pin loop (card #1436).
|
|
929
|
+
if isinstance(fed, dict):
|
|
930
|
+
fed.pop("repo_commits", None)
|
|
600
931
|
fed_build = (_stamp_time(fed.get("generated"))
|
|
601
932
|
if fed.get("status") == "ok" else None)
|
|
602
933
|
return {
|
|
@@ -639,6 +970,18 @@ def is_stale_fed_build(fed_build, merged_at) -> bool | None:
|
|
|
639
970
|
return None if fb is None or mg is None else fb < mg
|
|
640
971
|
|
|
641
972
|
|
|
973
|
+
def _ref_names(pin: dict) -> str:
|
|
974
|
+
"""``; report described <sha>; compared <ref>@<sha>`` for a real read."""
|
|
975
|
+
trust = pin.get("ref_trust")
|
|
976
|
+
if not isinstance(trust, dict):
|
|
977
|
+
return ""
|
|
978
|
+
described = trust.get("report_sha") or pin.get("report_sha") or "no commit"
|
|
979
|
+
ref = trust.get("ref") or COMPARED_REF
|
|
980
|
+
sha = trust.get("ref_sha")
|
|
981
|
+
compared = f"{ref}@{sha}" if sha else ref
|
|
982
|
+
return f"; report described {described}; compared {compared}"
|
|
983
|
+
|
|
984
|
+
|
|
642
985
|
def render(ex: dict, max_lines: int = DEFAULT_MAX_LINES,
|
|
643
986
|
post_safe: bool = False) -> str:
|
|
644
987
|
"""Render the extract text; post-safe mode names no withheld/missing repo."""
|
|
@@ -774,23 +1117,43 @@ def render(ex: dict, max_lines: int = DEFAULT_MAX_LINES,
|
|
|
774
1117
|
for repo, p in ex.get("pins", {}).items():
|
|
775
1118
|
merged = p.get("merged_at")
|
|
776
1119
|
fb = ex.get("fed_build")
|
|
1120
|
+
names = _ref_names(p)
|
|
1121
|
+
trust = p.get("ref_trust")
|
|
1122
|
+
if isinstance(trust, dict) and not trust.get("trusted"):
|
|
1123
|
+
reason = trust.get("reason") or "local ref is not trusted"
|
|
1124
|
+
tail.append(f"- {repo}: not fresh ({reason}){names}")
|
|
1125
|
+
continue
|
|
777
1126
|
if not fb:
|
|
778
|
-
tail.append(f"- {repo}: freshness unavailable (no federation build time)"
|
|
1127
|
+
tail.append(f"- {repo}: freshness unavailable (no federation build time)"
|
|
1128
|
+
f"{names}")
|
|
779
1129
|
elif not merged:
|
|
780
1130
|
tail.append(f"- {repo}: freshness unavailable "
|
|
781
|
-
"(last repo.merged unknown for this repo)"
|
|
1131
|
+
"(last repo.merged unknown for this repo)"
|
|
1132
|
+
f"{names}")
|
|
782
1133
|
else:
|
|
783
1134
|
stale = is_stale_fed_build(fb, merged)
|
|
1135
|
+
report_sha = p.get("report_sha")
|
|
1136
|
+
ref_sha = None
|
|
1137
|
+
if isinstance(trust, dict):
|
|
1138
|
+
report_sha = trust.get("report_sha") or report_sha
|
|
1139
|
+
ref_sha = trust.get("ref_sha")
|
|
784
1140
|
if stale is None:
|
|
785
1141
|
tail.append(f"- {repo}: freshness unavailable "
|
|
786
|
-
"(unparseable federation-build or repo.merged time)"
|
|
1142
|
+
"(unparseable federation-build or repo.merged time)"
|
|
1143
|
+
f"{names}")
|
|
787
1144
|
elif stale:
|
|
788
1145
|
tail.append(f"- {repo}: STALE (federation build {fb} older than "
|
|
789
1146
|
f"last repo.merged {merged}; merge-time is an "
|
|
790
|
-
"origin/main-HEAD proxy)")
|
|
1147
|
+
f"origin/main-HEAD proxy){names}")
|
|
1148
|
+
elif isinstance(trust, dict) and not _same_commit(report_sha, ref_sha):
|
|
1149
|
+
# Same commit, and only that, reads fresh. A commit dated
|
|
1150
|
+
# before the report and pushed after it is not fresh.
|
|
1151
|
+
tail.append(f"- {repo}: not fresh "
|
|
1152
|
+
"(report commit differs from the ref commit)"
|
|
1153
|
+
f"{names}")
|
|
791
1154
|
else:
|
|
792
1155
|
tail.append(f"- {repo}: fresh (federation build {fb} >= "
|
|
793
|
-
f"last repo.merged {merged})")
|
|
1156
|
+
f"last repo.merged {merged}){names}")
|
|
794
1157
|
if len(head) + len(tail) + (1 if cut_notes else 0) > max_lines:
|
|
795
1158
|
cut_notes.append(f"output capped at {max_lines} lines "
|
|
796
1159
|
"(render budget; freshness + withheld kept)")
|
|
@@ -51,17 +51,19 @@ def _allow_unchanged() -> int:
|
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
def run_hook(stdin_text: Optional[str] = None) -> int:
|
|
54
|
+
try:
|
|
55
|
+
return _run_hook(stdin_text)
|
|
56
|
+
except Exception as exc:
|
|
57
|
+
# A hook crash otherwise leaves gh on the ambient shared identity.
|
|
58
|
+
return _deny(f"identity routing failed ({type(exc).__name__}); "
|
|
59
|
+
"correct the command or hook payload and retry")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _run_hook(stdin_text: Optional[str] = None) -> int:
|
|
54
63
|
raw = stdin_text if stdin_text is not None else sys.stdin.read()
|
|
55
64
|
# PS 5.1 native pipes prefix a (double) UTF-8 BOM; strip before parse.
|
|
56
65
|
raw = (raw or "").lstrip("\ufeff")
|
|
57
|
-
|
|
58
|
-
payload = json.loads(raw or "{}")
|
|
59
|
-
except Exception:
|
|
60
|
-
# >>> FAIL OPEN ON A MALFORMED PAYLOAD, NOT CLOSED. <<< A router that cannot
|
|
61
|
-
# parse its input has learned nothing about the command, so denying would
|
|
62
|
-
# brick every Bash call on a harness change. It is the UNMAPPED CELL that
|
|
63
|
-
# must fail closed, not the unreadable envelope.
|
|
64
|
-
return _allow_unchanged()
|
|
66
|
+
payload = json.loads(raw or "{}")
|
|
65
67
|
|
|
66
68
|
command = (payload.get("tool_input") or {}).get("command") or ""
|
|
67
69
|
if not ghid.targets_gh(command):
|