swarph-cli 0.72.43__tar.gz → 0.72.45__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.43/src/swarph_cli.egg-info → swarph_cli-0.72.45}/PKG-INFO +1 -1
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/pyproject.toml +1 -1
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/event.py +51 -4
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/mcp_server.py +9 -3
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/mesh.py +8 -1
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/triage.py +12 -6
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/redact.py +6 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/scrub.py +7 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli.egg-info/SOURCES.txt +2 -0
- swarph_cli-0.72.45/tests/test_1472_redact_boundaries.py +218 -0
- swarph_cli-0.72.45/tests/test_1478_triage_dm.py +99 -0
- swarph_cli-0.72.45/tests/test_event_emit.py +166 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mcp_server.py +39 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_scrub.py +6 -0
- swarph_cli-0.72.43/tests/test_event_emit.py +0 -36
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/LICENSE +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/README.md +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/setup.cfg +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/codex_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/providers.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/signal_score.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/board_cost.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/board_usage.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/commander.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/committee.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/dev_extract.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/roster.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/rowclear_hook.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/skunkworks.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/sweep.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/commit_trailers.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/duplicate_session.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/guide/GUIDE.md +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/launchd/swarph-codex-outbox.plist +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/launchd/swarph-codex-outbox.timer.plist +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/launchd/swarph-monitor.plist +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/launchd/swarph-watchdog.plist +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/launchd/swarph-watchdog.timer.plist +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/launchd_render.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/operator/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/operator/__main__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/operator/api.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/operator/cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/operator/config.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/operator/fmt.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/quota_sync.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/rowclear.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-triage.service +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/the_ten.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/triage/__init__.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/triage/backend.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/triage/job.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/triage/owners.json +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/triage/router.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/triage/rows.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli/triage/sensor.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1006_board_publisher.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1006_session_board.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1010_strand_only.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1013_spawn_channel.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1017_muse_tui.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1034_copy_mode.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1050_surrogate_wake.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1052_opencode_deaf.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1059_watchdog_unread_env.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1061_roster_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1064_stuck_sweep.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1065_release.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1066_quiet_wakes.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1068_structured_accept_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1071_quota_sync.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1073_triage.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1073_triage_board.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1073_wheel_install.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1075_task_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1083_openai_decisions.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1144_cell_yaml_github.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1197_commander_taps.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1203_swarph_me_refusal.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1206_offer_question.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1214_egress.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1219_egress_probe.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1221_quota_windows.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1222_maybe_start_cap.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1228_quota_reach.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1243_the_ten.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1248_ship_price_table.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1250_price_cache.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1256_commander_wake.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1261_mcp_install.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1262_wake_followups.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1265_wake_note.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1269_triage_label.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1277_close_usage.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1278_dreaming_reach.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1286_dm_unread_cursor.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1297_commander.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1300_authorization_check.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1301_restart_skew.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1320_commit_trailers.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1321_layered_redaction.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1340_router_rollout.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1346_shell_string_gh.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1347_shell_depth_cap.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1353_obligation_release_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1385_duplicate_session_argv.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1396_dev_extract.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1405_skunkworks_basic.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1405_skunkworks_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1427_membrane_workflow.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1436_dev_extract_freshness.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1452_rework1_engine.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1452_rework2_engine.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1452_rework3_engine.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1452_standing_wake_expiry.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_1470_gh_router_fail_closed.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_3130_sender.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_3150_identity_router_install.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_432_rowclear.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_484_codex_queue_sink.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_513_duplicate_session.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_538_signal_bench.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_729_arm_check_delivery_gap.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_735_dm_mcp_tools.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_739_wake_writer.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_931_board_search.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_935_deadline_clock.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_961_cursor_grok_footer.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_961_loud_stop.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_bench_codex_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_board_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_committee_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_copilot_membrane.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_copilot_pane_reader.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_group_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_import_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_init_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_launchd_units.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_main.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mesh_sidecar_muse_sink.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_operator_me.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_security.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_service_app.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_service_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_version_command.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.72.43 → swarph_cli-0.72.45}/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.45
|
|
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.45"
|
|
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" }
|
|
@@ -20,7 +20,7 @@ from ._gateway_client import (
|
|
|
20
20
|
resolve_self_name,
|
|
21
21
|
resolve_token,
|
|
22
22
|
)
|
|
23
|
-
from swarph_cli.redact import redact_text
|
|
23
|
+
from swarph_cli.redact import encode_outbound_json, redact_text
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
def _build_parser() -> argparse.ArgumentParser:
|
|
@@ -47,6 +47,34 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
47
47
|
return p
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
class ChainTokenAttachError(RuntimeError):
|
|
51
|
+
"""The redacted event bytes are not JSON, so the chain token is not sent."""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _attach_chain_token(data: bytes, chain_token: str) -> bytes:
|
|
55
|
+
"""Add the CLI chain token onto an already-redacted event body.
|
|
56
|
+
|
|
57
|
+
Same shape as ``mcp_server._search``: redact first, then set the one
|
|
58
|
+
field that must reach the wire. A pasted chain_token line in the payload
|
|
59
|
+
was already scrubbed and is not this value.
|
|
60
|
+
|
|
61
|
+
Redaction can rewrite a quote inside the content string and leave bytes
|
|
62
|
+
that are not JSON. That refusal is by name (``JSONDecodeError`` or
|
|
63
|
+
``UnicodeDecodeError``). The token is not copied into the error, and the
|
|
64
|
+
caller sends nothing.
|
|
65
|
+
"""
|
|
66
|
+
try:
|
|
67
|
+
body_obj = json.loads(data.decode("utf-8"))
|
|
68
|
+
inner = json.loads(body_obj["content"])
|
|
69
|
+
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
|
|
70
|
+
raise ChainTokenAttachError(
|
|
71
|
+
f"_attach_chain_token refused: {type(exc).__name__}"
|
|
72
|
+
) from None
|
|
73
|
+
inner["swarph_event"]["chain_token"] = chain_token
|
|
74
|
+
body_obj["content"] = json.dumps(inner, separators=(",", ":"), sort_keys=True)
|
|
75
|
+
return json.dumps(body_obj).encode("utf-8")
|
|
76
|
+
|
|
77
|
+
|
|
50
78
|
def _post_channel(
|
|
51
79
|
*,
|
|
52
80
|
channel: str,
|
|
@@ -76,8 +104,6 @@ def _post_channel(
|
|
|
76
104
|
base = (gateway or env_gateway()).rstrip("/")
|
|
77
105
|
payload = redact_text(payload, caller="event.emit") or ""
|
|
78
106
|
ev: dict = {"event": event, "payload": payload}
|
|
79
|
-
if chain_token is not None: # carry an explicit "" through; only omit when unset
|
|
80
|
-
ev["chain_token"] = chain_token
|
|
81
107
|
# Sentinel-wrapped so P1's guard can UNAMBIGUOUSLY identify an event post: a
|
|
82
108
|
# normal channel message won't carry the top-level `swarph_event` key, so the
|
|
83
109
|
# guard keys off `content.swarph_event` — never a false-positive on a plain
|
|
@@ -91,7 +117,28 @@ def _post_channel(
|
|
|
91
117
|
"kind": "fyi",
|
|
92
118
|
"content": json.dumps(content, separators=(",", ":"), sort_keys=True),
|
|
93
119
|
}
|
|
94
|
-
|
|
120
|
+
# Redact with no chain token in the body. Attach the CLI value after, so
|
|
121
|
+
# only that value skips redaction. An explicit "" is carried; omit only
|
|
122
|
+
# when the flag was unset. Card #1472.
|
|
123
|
+
if chain_token is None:
|
|
124
|
+
status, resp = post_json(f"{base}/messages", body, token)
|
|
125
|
+
else:
|
|
126
|
+
# Attach after redaction. If those bytes are not JSON, name the
|
|
127
|
+
# refusal and return before post_json: nothing is sent, no traceback.
|
|
128
|
+
try:
|
|
129
|
+
encoded = _attach_chain_token(
|
|
130
|
+
encode_outbound_json(body, caller="event.emit"),
|
|
131
|
+
chain_token,
|
|
132
|
+
)
|
|
133
|
+
except ChainTokenAttachError as exc:
|
|
134
|
+
print(f"swarph event: {exc}", file=sys.stderr)
|
|
135
|
+
return 2
|
|
136
|
+
status, resp = post_json(
|
|
137
|
+
f"{base}/messages",
|
|
138
|
+
body,
|
|
139
|
+
token,
|
|
140
|
+
encoded=encoded,
|
|
141
|
+
)
|
|
95
142
|
if 200 <= status < 300:
|
|
96
143
|
print(f"emitted event={event} channel={channel} id={resp.get('id')}")
|
|
97
144
|
return 0
|
|
@@ -89,10 +89,16 @@ def _search(query: str, *, url: str, token: str | None = None) -> list[dict]:
|
|
|
89
89
|
transport exception.
|
|
90
90
|
"""
|
|
91
91
|
endpoint = url.rstrip("/") + "/api/ask"
|
|
92
|
-
|
|
92
|
+
# Redact the query only. The auth token is the credential this call
|
|
93
|
+
# presents to the search face. Putting it in the dict that
|
|
94
|
+
# encode_outbound_json walks replaces a credential-shaped value
|
|
95
|
+
# (secrets.token_urlsafe(32), the gateway mint) with
|
|
96
|
+
# [REDACTED:HIGH_ENTROPY] before the request is sent. Card #1472.
|
|
97
|
+
data = encode_outbound_json({"message": query}, caller="mcp_server._search")
|
|
93
98
|
if token:
|
|
94
|
-
|
|
95
|
-
|
|
99
|
+
body_obj = json.loads(data.decode("utf-8"))
|
|
100
|
+
body_obj["token"] = token
|
|
101
|
+
data = json.dumps(body_obj).encode("utf-8")
|
|
96
102
|
req = urllib.request.Request(
|
|
97
103
|
endpoint,
|
|
98
104
|
data=data,
|
|
@@ -444,9 +444,16 @@ def _post_json(
|
|
|
444
444
|
token: str,
|
|
445
445
|
*,
|
|
446
446
|
timeout: float = 10.0,
|
|
447
|
+
encoded: bytes | None = None,
|
|
447
448
|
) -> tuple[int, dict]:
|
|
448
449
|
_require_absolute_gateway_url(url)
|
|
449
|
-
|
|
450
|
+
# event.emit redacts with no chain token, then passes the bytes with the
|
|
451
|
+
# CLI --chain-token already attached. Encoding those bytes again would
|
|
452
|
+
# strip that one value. Every other caller leaves encoded unset.
|
|
453
|
+
if encoded is None:
|
|
454
|
+
data = encode_outbound_json(body, caller="mesh._post_json")
|
|
455
|
+
else:
|
|
456
|
+
data = encoded
|
|
450
457
|
req = urllib.request.Request(
|
|
451
458
|
url,
|
|
452
459
|
data=data,
|
|
@@ -62,8 +62,9 @@ def _stuck_records(rows, by_id, peers, http_get, gateway, token, now,
|
|
|
62
62
|
if waiter.get("status") != "open" or not waiter.get("taken_at"):
|
|
63
63
|
continue
|
|
64
64
|
step = waiter.get("step")
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
# A waiter with no step still matches a graph entry whose step is
|
|
66
|
+
# the same empty value. The DM prints a dash, not None (#1478).
|
|
67
|
+
waiter_step = step if step else "-"
|
|
67
68
|
card_id = waiter.get("card_id")
|
|
68
69
|
if not isinstance(card_id, int) or isinstance(card_id, bool):
|
|
69
70
|
continue
|
|
@@ -91,6 +92,8 @@ def _stuck_records(rows, by_id, peers, http_get, gateway, token, now,
|
|
|
91
92
|
base = {
|
|
92
93
|
"source_organ": _sensor.ORGAN_STUCK,
|
|
93
94
|
"waiter_id": waiter.get("id"),
|
|
95
|
+
"waiter": waiter.get("holder"),
|
|
96
|
+
"waiter_step": waiter_step,
|
|
94
97
|
"card_id": card_id,
|
|
95
98
|
"need": need.get("step"),
|
|
96
99
|
"need_id": rid,
|
|
@@ -109,6 +112,7 @@ def _stuck_records(rows, by_id, peers, http_get, gateway, token, now,
|
|
|
109
112
|
holder = dep.get("holder")
|
|
110
113
|
blocker = (holder if holder and dep.get("holder_known", True)
|
|
111
114
|
else None)
|
|
115
|
+
age_days = None
|
|
112
116
|
if dep.get("status") == "closed":
|
|
113
117
|
classified = _sensor.map_stuck_finding(
|
|
114
118
|
{"blocker": blocker, "id": waiter.get("id"),
|
|
@@ -118,6 +122,7 @@ def _stuck_records(rows, by_id, peers, http_get, gateway, token, now,
|
|
|
118
122
|
changed = _sweep._row_last_change(dep)
|
|
119
123
|
if changed is None or now - changed < _sweep._STUCK_H * 3600:
|
|
120
124
|
continue
|
|
125
|
+
age_days = _sweep._age_days(now, changed)
|
|
121
126
|
need_card_id = dep.get("card_id")
|
|
122
127
|
due_at = (_need_card_due_at(http_get, gateway, token,
|
|
123
128
|
need_card_id, card_cache)
|
|
@@ -135,7 +140,7 @@ def _stuck_records(rows, by_id, peers, http_get, gateway, token, now,
|
|
|
135
140
|
evidence=_sensor.stuck_evidence(waiter.get("id"), rid),
|
|
136
141
|
item_id=(f"stuck:{waiter.get('id')}:{rid}:"
|
|
137
142
|
f"{need.get('step')}"),
|
|
138
|
-
security=False)
|
|
143
|
+
security=False, age_days=age_days)
|
|
139
144
|
records.append(record)
|
|
140
145
|
return records
|
|
141
146
|
|
|
@@ -175,16 +180,17 @@ def run_triage(*, gateway, token, sender, owners_map, state_file,
|
|
|
175
180
|
sent = _load_state(state_file)
|
|
176
181
|
|
|
177
182
|
def dm_sender(record, owner):
|
|
183
|
+
raw_step = record.get("waiter_step")
|
|
178
184
|
finding = {
|
|
179
185
|
"kind": "row",
|
|
180
186
|
"waiter_id": record.get("waiter_id"),
|
|
181
|
-
"waiter":
|
|
182
|
-
"waiter_step":
|
|
187
|
+
"waiter": record.get("waiter"),
|
|
188
|
+
"waiter_step": raw_step if raw_step else "-",
|
|
183
189
|
"card_id": record.get("card_id"),
|
|
184
190
|
"need": record.get("need"),
|
|
185
191
|
"need_id": record.get("need_id"),
|
|
186
192
|
"blocker": record.get("owner_hint"),
|
|
187
|
-
"age_days":
|
|
193
|
+
"age_days": record.get("age_days"),
|
|
188
194
|
}
|
|
189
195
|
key = _sweep._finding_key(finding)
|
|
190
196
|
try:
|
|
@@ -132,6 +132,11 @@ _ANTHROPIC_RE = re.compile(r"\bsk-ant-[A-Za-z0-9\-_]{8,}\b")
|
|
|
132
132
|
_OPENAI_RE = re.compile(r"\bsk-(?!ant-)(?:proj-|svcacct-)?[A-Za-z0-9\-_]{16,}\b")
|
|
133
133
|
_XAI_RE = re.compile(r"\bxai-[A-Za-z0-9\-_]{16,}\b")
|
|
134
134
|
_GCP_RE = re.compile(r"\bAIza[0-9A-Za-z\-_]{35}\b")
|
|
135
|
+
_GCP_FINAL_RE = re.compile(
|
|
136
|
+
r"(?:\bAIza[0-9A-Za-z\-_]{34}(?:-|[0-9A-Za-z_](?![0-9A-Za-z_]))"
|
|
137
|
+
r"|(?<=[0-9A-Za-z_])AIza[0-9A-Za-z\-_]{34}[0-9A-Za-z_](?![0-9A-Za-z_])"
|
|
138
|
+
r"|(?<=\w)AIza[0-9A-Za-z\-_]{34}-)"
|
|
139
|
+
)
|
|
135
140
|
_SLACK_RE = re.compile(r"\bxox[baprs]-[A-Za-z0-9\-]{8,}\b")
|
|
136
141
|
_AWS_KEY_RE = re.compile(r"\b(?:AKIA|ASIA)[0-9A-Z]{16}\b")
|
|
137
142
|
_AWS_SECRET_RE = re.compile(
|
|
@@ -332,6 +337,7 @@ def redact_text(
|
|
|
332
337
|
# Layer 6: Shannon Entropy Scoring
|
|
333
338
|
out = _SECRET_ASSIGN_RE.sub(_replace_secret_assignment, out)
|
|
334
339
|
out = _replace_standalone_tokens(out)
|
|
340
|
+
out = _GCP_FINAL_RE.sub("[REDACTED:GCP_API_KEY]", out)
|
|
335
341
|
|
|
336
342
|
return out
|
|
337
343
|
|
|
@@ -39,6 +39,13 @@ _SECRET_PATTERNS = [
|
|
|
39
39
|
# password/token/secret assignments.
|
|
40
40
|
(re.compile(r"(?i)\b(password|passwd|pwd|api[_-]?key|auth[_-]?token|secret)\b\s*[:=]\s*\S+"),
|
|
41
41
|
r"\1=[REDACTED]"),
|
|
42
|
+
(re.compile(r"\bsk-(?!ant-)(?:proj-|svcacct-)?[A-Za-z0-9\-_]{16,}\b"),
|
|
43
|
+
"[REDACTED-API-KEY]"),
|
|
44
|
+
(re.compile(
|
|
45
|
+
r"(?:\bAIza[0-9A-Za-z\-_]{34}(?:-|[0-9A-Za-z_](?![0-9A-Za-z_]))"
|
|
46
|
+
r"|(?<=[0-9A-Za-z_])AIza[0-9A-Za-z\-_]{34}[0-9A-Za-z_](?![0-9A-Za-z_])"
|
|
47
|
+
r"|(?<=\w)AIza[0-9A-Za-z\-_]{34}-)"),
|
|
48
|
+
"[REDACTED-API-KEY]"),
|
|
42
49
|
]
|
|
43
50
|
|
|
44
51
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.45
|
|
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
|
|
@@ -285,6 +285,8 @@ tests/test_1452_rework2_engine.py
|
|
|
285
285
|
tests/test_1452_rework3_engine.py
|
|
286
286
|
tests/test_1452_standing_wake_expiry.py
|
|
287
287
|
tests/test_1470_gh_router_fail_closed.py
|
|
288
|
+
tests/test_1472_redact_boundaries.py
|
|
289
|
+
tests/test_1478_triage_dm.py
|
|
288
290
|
tests/test_183_card_anchor.py
|
|
289
291
|
tests/test_184_notify_honesty.py
|
|
290
292
|
tests/test_201_win32_bash_refusal.py
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"""Card #1472: pasted chain_token text stays scrubbed, and a trailing-dash
|
|
2
|
+
AIza key is scrubbed too.
|
|
3
|
+
|
|
4
|
+
Every secret is built at runtime. No realistic key literal.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
|
|
10
|
+
from swarph_cli.redact import encode_outbound_json, redact_text
|
|
11
|
+
from swarph_cli.scrub import scrub_text
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _sk_proj() -> str:
|
|
15
|
+
return "sk-proj-" + ("n7" * 12)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _ghp() -> str:
|
|
19
|
+
return "ghp_" + ("Ab" * 16)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _aiza_trailing_dash() -> str:
|
|
23
|
+
# AIza + 35 chars, last character '-'. No digits, so the entropy
|
|
24
|
+
# layer does not also eat it: only the AIza rule can.
|
|
25
|
+
secret = "AI" + "za" + ("m" * 34) + "-"
|
|
26
|
+
assert len(secret) == 39
|
|
27
|
+
assert secret.endswith("-")
|
|
28
|
+
return secret
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_dm_body_pasted_chain_token_line_is_fully_redacted():
|
|
32
|
+
"""Drop's measured leak: keys sit inside a pasted "chain_token": "..." value.
|
|
33
|
+
|
|
34
|
+
encode_outbound_json is what mesh._post_json sends. Both keys must be
|
|
35
|
+
gone from those bytes. A shield that puts the quoted span back fails this.
|
|
36
|
+
"""
|
|
37
|
+
sk = _sk_proj()
|
|
38
|
+
ghp = _ghp()
|
|
39
|
+
content = (
|
|
40
|
+
'pasted log "chain_token": "\n'
|
|
41
|
+
f"export OPENAI_API_KEY={sk}\n"
|
|
42
|
+
f"GITHUB={ghp}\n"
|
|
43
|
+
'" end'
|
|
44
|
+
)
|
|
45
|
+
followed = f"chain_token: note\n{sk}\n{ghp}"
|
|
46
|
+
for text in (content, followed):
|
|
47
|
+
body = {
|
|
48
|
+
"from_node": "friendly-coder",
|
|
49
|
+
"to_node": "lab-ovh",
|
|
50
|
+
"kind": "answer",
|
|
51
|
+
"content": text,
|
|
52
|
+
}
|
|
53
|
+
raw = encode_outbound_json(body, caller="t").decode("utf-8")
|
|
54
|
+
assert sk not in raw
|
|
55
|
+
assert ghp not in raw
|
|
56
|
+
assert "REDACTED" in raw
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_redact_text_redacts_chain_token_json_holding_an_sk_proj_key():
|
|
60
|
+
sk = _sk_proj()
|
|
61
|
+
blob = '{"chain_token": "' + sk + '"}'
|
|
62
|
+
out = redact_text(blob, caller="t")
|
|
63
|
+
assert sk not in out
|
|
64
|
+
assert "REDACTED" in out
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_chain_placeholder_literal_is_left_alone():
|
|
68
|
+
literal = "SWARPH.CHAIN.0.END"
|
|
69
|
+
assert redact_text(f"see {literal} here", caller="t") == f"see {literal} here"
|
|
70
|
+
sk = _sk_proj()
|
|
71
|
+
text = literal + '\n{"chain_token": "' + sk + '"}'
|
|
72
|
+
out = redact_text(text, caller="t")
|
|
73
|
+
assert out.startswith(literal)
|
|
74
|
+
assert sk not in out
|
|
75
|
+
assert json.loads(out.split("\n", 1)[1])["chain_token"] != sk
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_aiza_key_then_hyphen_suffix_is_redacted():
|
|
79
|
+
"""A '-' after the 35-character body is a boundary, not a longer tail.
|
|
80
|
+
|
|
81
|
+
key-x and key-- must be scrubbed. Putting '-' back into the lookahead
|
|
82
|
+
(?![0-9A-Za-z\\-_]) hides both, because the next character is '-'.
|
|
83
|
+
"""
|
|
84
|
+
secret = "AI" + "za" + ("m" * 35)
|
|
85
|
+
assert len(secret) == 39
|
|
86
|
+
assert not secret.endswith("-")
|
|
87
|
+
for suffix in ("-x", "--"):
|
|
88
|
+
text = secret + suffix
|
|
89
|
+
scrubbed = scrub_text(text)
|
|
90
|
+
assert scrubbed is not None
|
|
91
|
+
assert secret not in scrubbed
|
|
92
|
+
assert "REDACTED" in scrubbed
|
|
93
|
+
redacted = redact_text(text, caller="t")
|
|
94
|
+
assert secret not in redacted
|
|
95
|
+
assert "REDACTED" in redacted
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _assert_scrub_and_redact(text: str, *secrets: str) -> None:
|
|
99
|
+
scrubbed = scrub_text(text)
|
|
100
|
+
assert scrubbed is not None
|
|
101
|
+
redacted = redact_text(text, caller="t")
|
|
102
|
+
for secret in secrets:
|
|
103
|
+
assert secret not in scrubbed
|
|
104
|
+
assert secret not in redacted
|
|
105
|
+
assert "REDACTED" in scrubbed
|
|
106
|
+
assert "REDACTED" in redacted
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_aiza_dash_key_followed_by_word_char_is_redacted():
|
|
110
|
+
"""A 35th character of '-' then x, _, or 'abc def' (drop #4429).
|
|
111
|
+
|
|
112
|
+
{35}(?![0-9A-Za-z_]) refuses that follower, so the key stays visible.
|
|
113
|
+
Both scrub_text and redact_text have to take the dash.
|
|
114
|
+
"""
|
|
115
|
+
secret = _aiza_trailing_dash()
|
|
116
|
+
for suffix in ("x", "_", "abc def"):
|
|
117
|
+
_assert_scrub_and_redact(secret + suffix, secret)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_dash_ending_aiza_then_api_key_hides_key_and_secret():
|
|
121
|
+
""":<dash-ending key>api_key=<secret> leaves neither (drop #4437).
|
|
122
|
+
|
|
123
|
+
The match stops on the key. A greedy tail would swallow api_key, and
|
|
124
|
+
the secret would stay where the keyword-value rule should have put
|
|
125
|
+
[REDACTED:DSN_CREDENTIAL].
|
|
126
|
+
"""
|
|
127
|
+
key = _aiza_trailing_dash()
|
|
128
|
+
secret = "plain-" + "secret-value"
|
|
129
|
+
text = f":{key}api_key={secret}"
|
|
130
|
+
scrubbed = scrub_text(text)
|
|
131
|
+
assert scrubbed is not None
|
|
132
|
+
assert key not in scrubbed
|
|
133
|
+
assert secret not in scrubbed
|
|
134
|
+
assert "api_key=[REDACTED]" in scrubbed
|
|
135
|
+
redacted = redact_text(text, caller="t")
|
|
136
|
+
assert key not in redacted
|
|
137
|
+
assert secret not in redacted
|
|
138
|
+
assert "api_key=[REDACTED:DSN_CREDENTIAL]" in redacted
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_dash_ending_aiza_glued_through_chain_token_redacts_both_keys():
|
|
142
|
+
"""token=<dash-ending key>--chain_token<full key> leaves neither key.
|
|
143
|
+
|
|
144
|
+
A match that stops on the first key leaves the second glued to the
|
|
145
|
+
word character at the end of chain_token. Values are built here, with
|
|
146
|
+
no digits, so the entropy layer cannot hide a miss.
|
|
147
|
+
"""
|
|
148
|
+
dash_key = _aiza_trailing_dash()
|
|
149
|
+
full_key = "AI" + "za" + ("n" * 35)
|
|
150
|
+
assert len(full_key) == 39
|
|
151
|
+
assert "-" not in full_key
|
|
152
|
+
text = f"token={dash_key}--chain_token{full_key}"
|
|
153
|
+
_assert_scrub_and_redact(text, dash_key, full_key)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_drop_4452_chain_and_proj_shapes_leave_no_key():
|
|
157
|
+
"""Drop #4452's two shapes, on scrub_text and redact_text.
|
|
158
|
+
|
|
159
|
+
chain_token<dash key>x<full key>{ leaves neither key. A proj key glued
|
|
160
|
+
to a dash-ending key and then api_key=<another dash key> leaves none of
|
|
161
|
+
the three. The keyword value below is a low-entropy secret: scrub_text
|
|
162
|
+
must hide it. redact_text's OpenAI rule is main's, and it still runs
|
|
163
|
+
before the keyword rule, so that low-entropy value can remain there.
|
|
164
|
+
"""
|
|
165
|
+
dash = _aiza_trailing_dash()
|
|
166
|
+
full = "AI" + "za" + ("n" * 35)
|
|
167
|
+
_assert_scrub_and_redact(f"chain_token{dash}x{full}{{", dash, full)
|
|
168
|
+
|
|
169
|
+
proj = "sk-proj-" + ("n7" * 12)
|
|
170
|
+
trail = "AI" + "za" + ("p" * 34) + "-"
|
|
171
|
+
assert len(trail) == 39 and trail.endswith("-")
|
|
172
|
+
_assert_scrub_and_redact(f"{proj}{dash}api_key={trail}", proj, dash, trail)
|
|
173
|
+
|
|
174
|
+
secret = "plain-" + "secret-value"
|
|
175
|
+
text = f"{proj}{dash}api_key={secret}"
|
|
176
|
+
scrubbed = scrub_text(text)
|
|
177
|
+
assert scrubbed is not None
|
|
178
|
+
assert proj not in scrubbed
|
|
179
|
+
assert dash not in scrubbed
|
|
180
|
+
assert secret not in scrubbed
|
|
181
|
+
redacted = redact_text(text, caller="t")
|
|
182
|
+
assert proj not in redacted
|
|
183
|
+
assert dash not in redacted
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def test_dash_ending_key_glued_after_word_char_is_redacted():
|
|
187
|
+
"""A dash-ending key glued after x, _, another key, or é is redacted.
|
|
188
|
+
|
|
189
|
+
No digits, so the entropy layer cannot hide a miss. Both scrub_text
|
|
190
|
+
and redact_text have to take the key.
|
|
191
|
+
"""
|
|
192
|
+
dash = _aiza_trailing_dash()
|
|
193
|
+
other = "AI" + "za" + ("q" * 35)
|
|
194
|
+
assert len(other) == 39
|
|
195
|
+
for prefix in ("x", "_", other, "é"):
|
|
196
|
+
_assert_scrub_and_redact(prefix + dash, dash)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_aiza_key_ending_in_dash_is_redacted_before_space_quote_or_punctuation():
|
|
200
|
+
secret = _aiza_trailing_dash()
|
|
201
|
+
samples = [
|
|
202
|
+
f"prefix {secret} suffix",
|
|
203
|
+
f'"{secret}"',
|
|
204
|
+
f"'{secret}'",
|
|
205
|
+
secret,
|
|
206
|
+
f"{secret}.",
|
|
207
|
+
f"{secret},",
|
|
208
|
+
f"({secret})",
|
|
209
|
+
f"{secret}\nnext",
|
|
210
|
+
]
|
|
211
|
+
for text in samples:
|
|
212
|
+
scrubbed = scrub_text(text)
|
|
213
|
+
assert scrubbed is not None
|
|
214
|
+
assert secret not in scrubbed
|
|
215
|
+
assert "REDACTED" in scrubbed
|
|
216
|
+
redacted = redact_text(text, caller="t")
|
|
217
|
+
assert secret not in redacted
|
|
218
|
+
assert "REDACTED" in redacted
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""card #1478 — stuck-row DMs name the waiter, the step, and the age.
|
|
2
|
+
|
|
3
|
+
run_triage.dm_sender used to hand sweep._dm_content a finding whose
|
|
4
|
+
waiter, waiter_step, and age_days were None, so a blocker read
|
|
5
|
+
"row #N (None, None, card #C) ... unchanged Noned". Rows in this file
|
|
6
|
+
are built in the test, not loaded from a fixture.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
|
|
12
|
+
from swarph_cli.commands import triage as triage_cmd
|
|
13
|
+
from swarph_cli.triage import backend as backend
|
|
14
|
+
from swarph_cli.triage import router as router
|
|
15
|
+
|
|
16
|
+
NOW = 1_790_000_000.0
|
|
17
|
+
HOLDER = "holder-rowan"
|
|
18
|
+
BLOCKER = "blocker-peer"
|
|
19
|
+
STEP = "validate"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _iso(age_s):
|
|
23
|
+
return datetime.fromtimestamp(NOW - age_s, timezone.utc).isoformat()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _http(graph_steps):
|
|
27
|
+
posts = []
|
|
28
|
+
|
|
29
|
+
def http_get(url, token):
|
|
30
|
+
if url.endswith("/board/cards/7/graph"):
|
|
31
|
+
return 200, {"steps": graph_steps}
|
|
32
|
+
if url.endswith("/board/cards/8"):
|
|
33
|
+
return 200, {"id": 8, "due_at": None}
|
|
34
|
+
raise AssertionError(f"unexpected GET {url}")
|
|
35
|
+
|
|
36
|
+
def http_post(url, body, token):
|
|
37
|
+
posts.append((url, body))
|
|
38
|
+
return 200, {"id": 1, **body}
|
|
39
|
+
|
|
40
|
+
return http_get, http_post, posts
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _run(tmp_path, waiter, dep, graph_steps):
|
|
44
|
+
http_get, http_post, posts = _http(graph_steps)
|
|
45
|
+
rows = [waiter, dep]
|
|
46
|
+
rc, summary = triage_cmd.run_triage(
|
|
47
|
+
gateway="http://gw:9", token="tok", sender="triage",
|
|
48
|
+
owners_map=router.load_owners(triage_cmd._OWNERS_DEFAULT),
|
|
49
|
+
state_file=str(tmp_path / "state.json"),
|
|
50
|
+
store_backend=backend.MemoryBackend(),
|
|
51
|
+
peers_fetcher=None,
|
|
52
|
+
board_fetcher=lambda: (rows, {r["id"]: r for r in rows}, {BLOCKER}),
|
|
53
|
+
http_get=http_get, http_post=http_post, now=NOW)
|
|
54
|
+
assert rc == 0 and summary["dm_sent"] == 1
|
|
55
|
+
assert len(posts) == 1 and posts[0][0].endswith("/messages")
|
|
56
|
+
return posts[0][1]["content"]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _waiter(step):
|
|
60
|
+
row = {
|
|
61
|
+
"id": 8, "status": "open", "holder": HOLDER, "card_id": 7,
|
|
62
|
+
"taken_at": _iso(86400), "created_at": _iso(10 * 86400),
|
|
63
|
+
"holder_known": True,
|
|
64
|
+
}
|
|
65
|
+
if step is not None:
|
|
66
|
+
row["step"] = step
|
|
67
|
+
return row
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _dep():
|
|
71
|
+
"""Open need whose last change (_row_last_change) is taken_at, 3 days ago."""
|
|
72
|
+
return {
|
|
73
|
+
"id": 9, "status": "open", "holder": BLOCKER, "card_id": 8,
|
|
74
|
+
"holder_known": True,
|
|
75
|
+
"taken_at": _iso(3 * 86400),
|
|
76
|
+
"created_at": _iso(10 * 86400),
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_stuck_dm_names_holder_step_and_age(tmp_path):
|
|
81
|
+
"""Known waiter, dependency last changed 3 days ago: holder, step, 3d, no None."""
|
|
82
|
+
content = _run(
|
|
83
|
+
tmp_path, _waiter(STEP), _dep(),
|
|
84
|
+
[{"step": STEP, "needs": [
|
|
85
|
+
{"step": "build", "row_id": 9, "satisfied": False}]}])
|
|
86
|
+
assert HOLDER in content
|
|
87
|
+
assert STEP in content
|
|
88
|
+
assert "3d" in content
|
|
89
|
+
assert "None" not in content
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_waiter_with_no_step_prints_dash_not_none(tmp_path):
|
|
93
|
+
"""A waiter with no step prints a dash in the DM, not the string None."""
|
|
94
|
+
content = _run(
|
|
95
|
+
tmp_path, _waiter(None), _dep(),
|
|
96
|
+
[{"step": None, "needs": [
|
|
97
|
+
{"step": "build", "row_id": 9, "satisfied": False}]}])
|
|
98
|
+
assert f"({HOLDER}, -, card #7)" in content
|
|
99
|
+
assert "None" not in content
|