swarph-cli 0.72.40__tar.gz → 0.72.41__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.40/src/swarph_cli.egg-info → swarph_cli-0.72.41}/PKG-INFO +1 -1
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/pyproject.toml +1 -1
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/__init__.py +1 -1
- swarph_cli-0.72.41/src/swarph_cli/commands/skunkworks.py +280 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/guide/GUIDE.md +3 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/main.py +2 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli.egg-info/SOURCES.txt +4 -0
- swarph_cli-0.72.41/tests/test_1405_skunkworks_basic.py +86 -0
- swarph_cli-0.72.41/tests/test_1405_skunkworks_cli.py +245 -0
- swarph_cli-0.72.41/tests/test_1427_membrane_workflow.py +240 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/LICENSE +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/README.md +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/setup.cfg +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/codex_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/providers.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/signal_score.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/board_cost.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/board_usage.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/commander.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/committee.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/dev_extract.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/mesh.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/roster.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/rowclear_hook.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/sweep.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/triage.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/commit_trailers.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/duplicate_session.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/launchd/swarph-codex-outbox.plist +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/launchd/swarph-codex-outbox.timer.plist +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/launchd/swarph-monitor.plist +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/launchd/swarph-watchdog.plist +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/launchd/swarph-watchdog.timer.plist +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/launchd_render.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/operator/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/operator/__main__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/operator/api.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/operator/cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/operator/config.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/operator/fmt.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/quota_sync.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/redact.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/rowclear.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/scrub.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-triage.service +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/the_ten.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/triage/__init__.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/triage/backend.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/triage/job.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/triage/owners.json +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/triage/router.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/triage/rows.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli/triage/sensor.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1006_board_publisher.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1006_session_board.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1010_strand_only.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1013_spawn_channel.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1017_muse_tui.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1034_copy_mode.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1050_surrogate_wake.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1052_opencode_deaf.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1059_watchdog_unread_env.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1061_roster_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1064_stuck_sweep.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1065_release.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1066_quiet_wakes.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1068_structured_accept_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1071_quota_sync.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1073_triage.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1073_triage_board.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1073_wheel_install.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1075_task_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1083_openai_decisions.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1144_cell_yaml_github.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1197_commander_taps.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1203_swarph_me_refusal.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1206_offer_question.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1214_egress.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1219_egress_probe.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1221_quota_windows.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1222_maybe_start_cap.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1228_quota_reach.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1243_the_ten.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1248_ship_price_table.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1250_price_cache.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1256_commander_wake.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1261_mcp_install.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1262_wake_followups.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1265_wake_note.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1269_triage_label.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1277_close_usage.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1278_dreaming_reach.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1286_dm_unread_cursor.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1297_commander.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1300_authorization_check.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1301_restart_skew.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1320_commit_trailers.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1321_layered_redaction.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1340_router_rollout.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1346_shell_string_gh.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1347_shell_depth_cap.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1353_obligation_release_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1385_duplicate_session_argv.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_1396_dev_extract.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_3130_sender.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_3150_identity_router_install.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_432_rowclear.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_484_codex_queue_sink.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_513_duplicate_session.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_538_signal_bench.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_729_arm_check_delivery_gap.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_735_dm_mcp_tools.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_739_wake_writer.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_931_board_search.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_935_deadline_clock.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_961_cursor_grok_footer.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_961_loud_stop.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_bench_codex_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_board_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_committee_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_copilot_membrane.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_copilot_pane_reader.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_group_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_import_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_init_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_launchd_units.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_main.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mesh_sidecar_muse_sink.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_operator_me.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_scrub.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_security.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_service_app.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_service_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_version_command.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.72.40 → swarph_cli-0.72.41}/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.41
|
|
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.41"
|
|
8
8
|
description = "The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"""``swarph skunkworks`` -- run the Skunkworks research pipeline on subscription lanes.
|
|
2
|
+
|
|
3
|
+
Verbs: ``run``, ``status``, ``show``, ``stop``, ``decide`` (``--as CELL`` and ``--json`` on
|
|
4
|
+
each, as in ``swarph board``). The pipeline itself lives in ``swarph_mesh.skunkworks``
|
|
5
|
+
(swarph-mesh 0.9.1+). Ideation and the architect are jobs on the mesh queue, research is a
|
|
6
|
+
local ``claude -p`` with web tools only, and nothing is metered. There is no daemon: the
|
|
7
|
+
process that ran ``run`` is the run, and a killed process leaves it in ERROR.
|
|
8
|
+
|
|
9
|
+
Runs are refused Monday to Friday 09:30-16:00 America/New_York (no holiday calendar).
|
|
10
|
+
Approval produces no code. ``decide`` has no override: it calls ``Pipeline.approve`` and
|
|
11
|
+
prints the gate's refusal when the architect did not say APPROVED_FOR_BUILD.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import json
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Callable, Optional
|
|
20
|
+
|
|
21
|
+
from swarph_cli.commands._display import sanitize_terminal as _s
|
|
22
|
+
from swarph_cli.commands.board import (
|
|
23
|
+
_card_say_payload,
|
|
24
|
+
_project_owner_orchestrator,
|
|
25
|
+
_thread_recipient,
|
|
26
|
+
)
|
|
27
|
+
from swarph_cli.commands.mesh import (
|
|
28
|
+
_add_common,
|
|
29
|
+
_http_get_json,
|
|
30
|
+
_post_json,
|
|
31
|
+
_resolve_self_name,
|
|
32
|
+
_resolve_token,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# MessagePostRequest.content max_length (gateway server.py), used by POST /messages, which
|
|
36
|
+
# is the route `swarph board cards say` posts a card message through.
|
|
37
|
+
CARD_POST_LIMIT = 200_000
|
|
38
|
+
NEEDS_MESH = ("swarph skunkworks: needs swarph-mesh 0.9.x with skunkworks "
|
|
39
|
+
"(pip install -U 'swarph-mesh>=0.9.1,<0.10')")
|
|
40
|
+
|
|
41
|
+
PostCard = Callable[[int, str, str], None] # (card_id, kind, content); raises on failure
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
45
|
+
p = argparse.ArgumentParser(prog="swarph skunkworks", description=__doc__)
|
|
46
|
+
sub = p.add_subparsers(dest="command", required=True)
|
|
47
|
+
|
|
48
|
+
r = sub.add_parser("run", help="start a run in this process (refused 09:30-16:00 New York, weekdays)")
|
|
49
|
+
r.add_argument("--card", type=int, required=True, help="board card the run reports to")
|
|
50
|
+
r.add_argument("--persona", required=True, help="persona pack name, e.g. swarph")
|
|
51
|
+
r.add_argument("--seed-file", required=True, help="file holding the seed")
|
|
52
|
+
r.add_argument("--blocker-question-file", default=None)
|
|
53
|
+
r.add_argument("--context-file", action="append", default=[],
|
|
54
|
+
help="shown to the architect only; repeatable")
|
|
55
|
+
|
|
56
|
+
s = sub.add_parser("status", help="state of a run")
|
|
57
|
+
s.add_argument("run_id")
|
|
58
|
+
w = sub.add_parser("show", help="print a run's stage outputs")
|
|
59
|
+
w.add_argument("run_id")
|
|
60
|
+
w.add_argument("--stage", choices=["ideation", "research", "architecture"], default=None)
|
|
61
|
+
t = sub.add_parser("stop", help="write the STOP file; checked before each job")
|
|
62
|
+
t.add_argument("run_id")
|
|
63
|
+
d = sub.add_parser("decide", help="record the commander's decision (no override exists)")
|
|
64
|
+
d.add_argument("run_id")
|
|
65
|
+
d.add_argument("verdict", help="APPROVED, REJECTED or REVISE")
|
|
66
|
+
d.add_argument("--quote-file", required=True,
|
|
67
|
+
help="file holding the commander's own words, posted to the card")
|
|
68
|
+
for sp in (r, s, w, t, d):
|
|
69
|
+
sp.add_argument("--json", action="store_true")
|
|
70
|
+
_add_common(sp)
|
|
71
|
+
return p
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _cut(text: str, path: str, limit: int = CARD_POST_LIMIT) -> str:
|
|
75
|
+
if len(text) <= limit:
|
|
76
|
+
return text
|
|
77
|
+
note = f"\n[cut at {limit} characters; full text at {path}]"
|
|
78
|
+
return text[: max(limit - len(note), 0)] + note
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _default_post_card(gw: str, token: str, cell: str, opt_out: bool) -> PostCard:
|
|
82
|
+
"""Post onto the card's thread the way ``swarph board cards say`` does."""
|
|
83
|
+
def post(card_id: int, kind: str, content: str) -> None:
|
|
84
|
+
st, card = _http_get_json(f"{gw}/board/cards/{card_id}", token)
|
|
85
|
+
if st != 200:
|
|
86
|
+
raise RuntimeError(f"cannot read card #{card_id}: {card.get('detail', card)}")
|
|
87
|
+
thread = card.get("thread_uuid")
|
|
88
|
+
if not thread:
|
|
89
|
+
raise RuntimeError(f"card #{card_id} has no bound thread")
|
|
90
|
+
owner = None
|
|
91
|
+
if not card.get("assignee"):
|
|
92
|
+
owner = _project_owner_orchestrator(gw, token, card.get("project_id"))
|
|
93
|
+
to_node, _ = _thread_recipient(card, None, owner_orchestrator=owner)
|
|
94
|
+
st, d = _post_json(f"{gw}/messages",
|
|
95
|
+
_card_say_payload(cell, to_node, kind, content, thread, opt_out=opt_out),
|
|
96
|
+
token)
|
|
97
|
+
if not (st and 200 <= st < 300):
|
|
98
|
+
raise RuntimeError(f"card post refused, HTTP {st or 'unreachable'}: {d.get('detail', d)}")
|
|
99
|
+
return post
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _read(path: str, what: str) -> str:
|
|
103
|
+
try:
|
|
104
|
+
text = Path(path).read_text(encoding="utf-8")
|
|
105
|
+
except OSError as exc:
|
|
106
|
+
raise ValueError(f"cannot read {what} {path!r}: {exc}") from None
|
|
107
|
+
return text
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _emit(obj: dict, as_json: bool, line: str) -> None:
|
|
111
|
+
print(json.dumps(obj, indent=2) if as_json else line)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _summary(st) -> dict:
|
|
115
|
+
return {"run_id": st.run_id, "status": st.status.value, "jobs_used": st.jobs_used,
|
|
116
|
+
"jobs_max": 10, "card_id": st.card_id, "error": st.error,
|
|
117
|
+
"cut_queries": len(st.cut_queries),
|
|
118
|
+
"ideation": st.ideation is not None, "research": st.research is not None,
|
|
119
|
+
"architecture": st.architecture is not None,
|
|
120
|
+
"commander_verdict": st.commander_verdict}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def run_skunkworks(
|
|
124
|
+
argv: list[str],
|
|
125
|
+
*,
|
|
126
|
+
post_card: Optional[PostCard] = None,
|
|
127
|
+
runners_factory=None,
|
|
128
|
+
now=None,
|
|
129
|
+
state_root: Optional[Path] = None,
|
|
130
|
+
persona_dir: Optional[str] = None,
|
|
131
|
+
) -> int:
|
|
132
|
+
try: # an older swarph-mesh has no skunkworks: say so in one line
|
|
133
|
+
from swarph_mesh import skunkworks as sk
|
|
134
|
+
from swarph_mesh.skunkworks import artifacts, ceilings, service
|
|
135
|
+
except ImportError:
|
|
136
|
+
print(NEEDS_MESH, file=sys.stderr)
|
|
137
|
+
return 1
|
|
138
|
+
|
|
139
|
+
args = _build_parser().parse_args(argv)
|
|
140
|
+
aj = args.json
|
|
141
|
+
try:
|
|
142
|
+
cell = _resolve_self_name(args.self_name)
|
|
143
|
+
except RuntimeError as exc:
|
|
144
|
+
print(f"swarph skunkworks: {exc}", file=sys.stderr)
|
|
145
|
+
return 1
|
|
146
|
+
rdir = ceilings.runs_dir_for(cell, state_root)
|
|
147
|
+
|
|
148
|
+
if args.command == "run":
|
|
149
|
+
return _run(args, cell, rdir, sk, service, ceilings, post_card, runners_factory,
|
|
150
|
+
now, state_root, persona_dir, aj)
|
|
151
|
+
|
|
152
|
+
if not service.RUN_ID_RE.match(args.run_id):
|
|
153
|
+
print(f"swarph skunkworks: bad run id {args.run_id!r}", file=sys.stderr)
|
|
154
|
+
return 1
|
|
155
|
+
run_path = rdir / args.run_id
|
|
156
|
+
raw = artifacts.read_json(str(run_path / "state.json"))
|
|
157
|
+
if not isinstance(raw, dict):
|
|
158
|
+
print(f"swarph skunkworks: no run {args.run_id} for cell {cell} under {rdir}", file=sys.stderr)
|
|
159
|
+
return 1
|
|
160
|
+
if args.command == "status":
|
|
161
|
+
service.sweep_dead_runs(rdir) # a killed run shows as ERROR, not as still running
|
|
162
|
+
raw = artifacts.read_json(str(run_path / "state.json")) or raw
|
|
163
|
+
st = sk.RunState.from_dict(raw)
|
|
164
|
+
|
|
165
|
+
if args.command == "status":
|
|
166
|
+
sm = _summary(st)
|
|
167
|
+
_emit(sm, aj, f"{sm['run_id']} {sm['status']} jobs {sm['jobs_used']}/{sm['jobs_max']}"
|
|
168
|
+
+ (f" error: {_s(sm['error'])}" if sm["error"] else ""))
|
|
169
|
+
return 0
|
|
170
|
+
|
|
171
|
+
if args.command == "show":
|
|
172
|
+
names = [args.stage] if args.stage else list(artifacts.RUN_FILES)
|
|
173
|
+
out = {n: artifacts.read_json(str(run_path / artifacts.RUN_FILES[n])) for n in names}
|
|
174
|
+
if all(v is None for v in out.values()):
|
|
175
|
+
print(f"swarph skunkworks: nothing to show yet for {args.run_id} ({st.status.value})",
|
|
176
|
+
file=sys.stderr)
|
|
177
|
+
return 1
|
|
178
|
+
print(json.dumps(out if not args.stage else out[args.stage], indent=2))
|
|
179
|
+
return 0
|
|
180
|
+
|
|
181
|
+
if args.command == "stop":
|
|
182
|
+
stop = run_path / "STOP"
|
|
183
|
+
stop.write_text("stop requested\n")
|
|
184
|
+
_emit({"run_id": args.run_id, "stop_file": str(stop)}, aj, f"wrote {stop}")
|
|
185
|
+
return 0
|
|
186
|
+
|
|
187
|
+
return _decide(args, cell, st, rdir, sk, post_card, aj)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _run(args, cell, rdir, sk, service, ceilings, post_card, runners_factory, now,
|
|
191
|
+
state_root, persona_dir, aj) -> int:
|
|
192
|
+
try:
|
|
193
|
+
seed = _read(args.seed_file, "seed file").strip()
|
|
194
|
+
blocker = (_read(args.blocker_question_file, "blocker file").strip()
|
|
195
|
+
if args.blocker_question_file else None)
|
|
196
|
+
ctx = [str(Path(p).resolve()) for p in args.context_file]
|
|
197
|
+
for p in ctx:
|
|
198
|
+
_read(p, "context file")
|
|
199
|
+
if not seed:
|
|
200
|
+
raise ValueError("the seed file is empty; a run needs a seed")
|
|
201
|
+
request = sk.SkunkworksRequest(requesting_swarm=cell, persona=args.persona, seed=seed,
|
|
202
|
+
card_id=args.card, blocker_question=blocker or None,
|
|
203
|
+
context_md_paths=ctx)
|
|
204
|
+
gw = args.gateway.rstrip("/")
|
|
205
|
+
token = _resolve_token(cell, args.token_file)
|
|
206
|
+
except (ValueError, RuntimeError) as exc:
|
|
207
|
+
print(f"swarph skunkworks run: {exc}", file=sys.stderr)
|
|
208
|
+
return 1
|
|
209
|
+
|
|
210
|
+
post_card = post_card or _default_post_card(gw, token, cell, args.no_redact)
|
|
211
|
+
if runners_factory is None:
|
|
212
|
+
runners_factory = service.default_runners(
|
|
213
|
+
gateway_url=gw, cell=cell,
|
|
214
|
+
post=lambda url, body: _post_json(url, body, token),
|
|
215
|
+
get=lambda url: _http_get_json(url, token))
|
|
216
|
+
|
|
217
|
+
def post(kind: str, content: str) -> None:
|
|
218
|
+
try:
|
|
219
|
+
post_card(args.card, kind, content)
|
|
220
|
+
except Exception as exc: # the run goes on; the artifacts are on disk
|
|
221
|
+
print(f"swarph skunkworks: card post failed: {_s(str(exc))}", file=sys.stderr)
|
|
222
|
+
|
|
223
|
+
def on_stage(st, stage: str) -> None:
|
|
224
|
+
post("status", json.dumps({"type": "skunkworks_status", "run_id": st.run_id,
|
|
225
|
+
"stage": stage, "status": st.status.value,
|
|
226
|
+
"jobs_used": st.jobs_used, "jobs_max": 10,
|
|
227
|
+
"error": st.error}, sort_keys=True))
|
|
228
|
+
path = rdir / st.run_id
|
|
229
|
+
if stage == "ideation":
|
|
230
|
+
post("fyi", _cut(f"skunkworks ideation, run {st.run_id}\n"
|
|
231
|
+
+ json.dumps(st.ideation, indent=2), str(path / "ideation.json")))
|
|
232
|
+
elif stage == "architecture":
|
|
233
|
+
post("fyi", _cut(f"skunkworks architecture, run {st.run_id}\n"
|
|
234
|
+
+ json.dumps(st.architecture, indent=2), str(path / "architecture.json")))
|
|
235
|
+
|
|
236
|
+
kw = {"now": now} if now else {}
|
|
237
|
+
try:
|
|
238
|
+
st = service.start_run(request, runners_factory=runners_factory, state_root=state_root,
|
|
239
|
+
persona_dir=persona_dir, on_stage=on_stage, **kw)
|
|
240
|
+
except ceilings.RunRefused as exc:
|
|
241
|
+
print(f"swarph skunkworks run: {exc}", file=sys.stderr)
|
|
242
|
+
return 1
|
|
243
|
+
except (ValueError, FileNotFoundError) as exc: # unknown persona
|
|
244
|
+
print(f"swarph skunkworks run: {exc}", file=sys.stderr)
|
|
245
|
+
return 1
|
|
246
|
+
sm = _summary(st)
|
|
247
|
+
_emit(sm, aj, f"{sm['run_id']} {sm['status']} jobs {sm['jobs_used']}/{sm['jobs_max']}"
|
|
248
|
+
+ (f" error: {_s(sm['error'])}" if sm["error"] else ""))
|
|
249
|
+
return 0 if sm["status"] == "awaiting_commander" else 1
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _decide(args, cell, st, rdir, sk, post_card, aj) -> int:
|
|
253
|
+
try:
|
|
254
|
+
quote = _read(args.quote_file, "quote file").strip()
|
|
255
|
+
except ValueError as exc:
|
|
256
|
+
print(f"swarph skunkworks decide: {exc}", file=sys.stderr)
|
|
257
|
+
return 1
|
|
258
|
+
if not quote:
|
|
259
|
+
print("swarph skunkworks decide: the quote file is empty; decide records the "
|
|
260
|
+
"commander's own words", file=sys.stderr)
|
|
261
|
+
return 1
|
|
262
|
+
res = sk.Pipeline(runs_dir=str(rdir)).approve(st, args.verdict, notes=quote)
|
|
263
|
+
if "error" in res: # the gate's refusal dict, or a bad verdict / wrong status
|
|
264
|
+
print(json.dumps(res, indent=2))
|
|
265
|
+
return 1
|
|
266
|
+
try:
|
|
267
|
+
gw = args.gateway.rstrip("/")
|
|
268
|
+
post_card = post_card or _default_post_card(
|
|
269
|
+
gw, _resolve_token(cell, args.token_file), cell, args.no_redact)
|
|
270
|
+
post_card(st.card_id, "status",
|
|
271
|
+
f"skunkworks decision, run {st.run_id}: {res['status']} "
|
|
272
|
+
f"(architect verdict {res['arch_verdict_at_decision'] or 'MISSING'}).\n"
|
|
273
|
+
f"Commander's words, quoted from {args.quote_file}:\n{quote}")
|
|
274
|
+
except Exception as exc:
|
|
275
|
+
print(f"swarph skunkworks decide: recorded locally, card post failed: {_s(str(exc))}",
|
|
276
|
+
file=sys.stderr)
|
|
277
|
+
_emit(res, aj, f"{res['run_id']} {res['status']}")
|
|
278
|
+
return 2
|
|
279
|
+
_emit(res, aj, f"{res['run_id']} {res['status']}")
|
|
280
|
+
return 0
|
|
@@ -51,6 +51,8 @@ want, run the command.
|
|
|
51
51
|
| keep my memory from rotting between sessions | `swarph dreaming run --corpus <dir> --out <dir>` |
|
|
52
52
|
| find out who calls a function | `swarph codegraph <symbol>` |
|
|
53
53
|
| find out what happened and when | `swarph timeline around <date>` |
|
|
54
|
+
| run a research pipeline on subscription lanes | `swarph skunkworks run --card <N> --persona swarph --seed-file <path> --as <you>` |
|
|
55
|
+
| see how a pipeline run is doing | `swarph skunkworks status <run_id> --as <you>` |
|
|
54
56
|
| check whether my setup is right | see [Check your own setup](#check-your-own-setup) |
|
|
55
57
|
| get woken when a DM arrives | `swarph install-wake-hook --scope project` |
|
|
56
58
|
| see what a wake hook would print | `swarph wake-hook-output` |
|
|
@@ -558,6 +560,7 @@ answers `--help`; hook-plumbing verbs are the callbacks hooks invoke, not comman
|
|
|
558
560
|
- `swarph scan` -- statically scan an artifact for dangerous patterns before publish.
|
|
559
561
|
- `swarph schedule` -- the gateway's scheduled events: create, list, get, enable, disable, delete, fire-now.
|
|
560
562
|
- `swarph service` -- stand up a $0 subscription-LLM HTTP lane.
|
|
563
|
+
- `swarph skunkworks` -- the research pipeline (card #1405): `run`, `status`, `show`, `stop`, `decide`, each with `--as <you>` and `--json`. Ideation and the architect run on the mesh queue, research on the requesting cell's own Claude quota, nothing metered. Refused Monday to Friday 09:30-16:00 New York time. Approval produces no code. See `docs/skunkworks-howto.md` in the swarph-cli repo.
|
|
561
564
|
- `swarph spawn` -- run a cell from its role name or yaml path.
|
|
562
565
|
- `swarph sweep` -- the card-#1064 stuck-work sweep: blocked rows and unreviewed PRs, DMs the blocker, `swarph sweep --dry-run` reads only.
|
|
563
566
|
- `swarph triage` -- the card-#1073 organ triage router: sensor findings onto owner triage rows (cap 10, carried), `swarph triage --dry-run` reads only.
|
|
@@ -108,6 +108,8 @@ _VERB_HANDLERS: dict[str, str] = {
|
|
|
108
108
|
"peer-reply-drain": "swarph_cli.commands.peer_reply_drain.run_peer_reply_drain",
|
|
109
109
|
"monitor": "swarph_cli.commands.monitor.run_monitor",
|
|
110
110
|
"board": "swarph_cli.commands.board.run_board",
|
|
111
|
+
# card #1405: research pipeline on subscription lanes (library: swarph_mesh.skunkworks).
|
|
112
|
+
"skunkworks": "swarph_cli.commands.skunkworks.run_skunkworks",
|
|
111
113
|
# card #1297: propose a decision or an action. The commander decides.
|
|
112
114
|
"commander": "swarph_cli.commands.commander.run_commander",
|
|
113
115
|
"group": "swarph_cli.commands.group.run_group",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.41
|
|
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
|
|
@@ -127,6 +127,7 @@ src/swarph_cli/commands/rowclear_hook.py
|
|
|
127
127
|
src/swarph_cli/commands/schedule.py
|
|
128
128
|
src/swarph_cli/commands/security.py
|
|
129
129
|
src/swarph_cli/commands/service.py
|
|
130
|
+
src/swarph_cli/commands/skunkworks.py
|
|
130
131
|
src/swarph_cli/commands/spawn.py
|
|
131
132
|
src/swarph_cli/commands/sweep.py
|
|
132
133
|
src/swarph_cli/commands/timeline.py
|
|
@@ -275,6 +276,9 @@ tests/test_1385_duplicate_session_argv.py
|
|
|
275
276
|
tests/test_138_memory_navigate.py
|
|
276
277
|
tests/test_1396_dev_extract.py
|
|
277
278
|
tests/test_139_tool_probe.py
|
|
279
|
+
tests/test_1405_skunkworks_basic.py
|
|
280
|
+
tests/test_1405_skunkworks_cli.py
|
|
281
|
+
tests/test_1427_membrane_workflow.py
|
|
278
282
|
tests/test_183_card_anchor.py
|
|
279
283
|
tests/test_184_notify_honesty.py
|
|
280
284
|
tests/test_201_win32_bash_refusal.py
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Card #1405: the parts of ``swarph skunkworks`` that need no swarph-mesh skunkworks library.
|
|
2
|
+
|
|
3
|
+
These run against the swarph-mesh a fresh install resolves (the pin allows 0.9.0, which has
|
|
4
|
+
no skunkworks package), so they stay green before 0.9.1 ships. The tests that run a pipeline
|
|
5
|
+
are in test_1405_skunkworks_cli.py and skip until swarph-mesh >= 0.9.1 is installed.
|
|
6
|
+
"""
|
|
7
|
+
import ast
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
from swarph_cli.commands import skunkworks as cli
|
|
14
|
+
|
|
15
|
+
_ROOT = Path(__file__).resolve().parents[1]
|
|
16
|
+
_DOCS = {"howto": _ROOT / "docs" / "skunkworks-howto.md",
|
|
17
|
+
"guide": _ROOT / "src" / "swarph_cli" / "guide" / "GUIDE.md"}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_verb_is_registered():
|
|
21
|
+
from swarph_cli.main import _VERB_HANDLERS
|
|
22
|
+
assert _VERB_HANDLERS["skunkworks"] == "swarph_cli.commands.skunkworks.run_skunkworks"
|
|
23
|
+
assert callable(cli.run_skunkworks)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_old_swarph_mesh_gets_a_one_line_message(monkeypatch, capsys):
|
|
27
|
+
monkeypatch.setitem(sys.modules, "swarph_mesh.skunkworks", None)
|
|
28
|
+
assert cli.run_skunkworks(["status", "sk_1_abcd1234", "--as", "x"]) == 1
|
|
29
|
+
err = capsys.readouterr().err
|
|
30
|
+
assert err.count("\n") == 1 and "needs swarph-mesh 0.9.x with skunkworks" in err
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_cut_leaves_short_text_alone():
|
|
34
|
+
assert cli._cut("abc", "/p") == "abc"
|
|
35
|
+
cut = cli._cut("a" * 500, "/p", limit=100)
|
|
36
|
+
assert len(cut) == 100 and cut.startswith("aaa") and cut.endswith("full text at /p]")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_decide_has_no_override_in_the_parser_or_the_source():
|
|
40
|
+
"""Clause 9. Mutation: add an --override flag to decide -> the parser check fails."""
|
|
41
|
+
p = cli._build_parser()
|
|
42
|
+
opts = {o for sp in p._subparsers._group_actions[0].choices.values()
|
|
43
|
+
for a in sp._actions for o in a.option_strings}
|
|
44
|
+
assert not [o for o in opts if "override" in o.lower()], opts
|
|
45
|
+
with pytest.raises(SystemExit):
|
|
46
|
+
cli._build_parser().parse_args(["decide", "sk_1_abcd1234", "APPROVED", "--quote-file",
|
|
47
|
+
"q", "--override", "--as", "x"])
|
|
48
|
+
tree = ast.parse(Path(cli.__file__).read_text())
|
|
49
|
+
names = [n.id for n in ast.walk(tree) if isinstance(n, ast.Name)] + \
|
|
50
|
+
[n.arg for n in ast.walk(tree) if isinstance(n, (ast.arg, ast.keyword)) and n.arg] + \
|
|
51
|
+
[n.attr for n in ast.walk(tree) if isinstance(n, ast.Attribute)]
|
|
52
|
+
assert not [n for n in names if "override" in n.lower()]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_default_card_post_uses_the_board_say_path(monkeypatch):
|
|
56
|
+
calls = []
|
|
57
|
+
|
|
58
|
+
def get(url, token, **kw):
|
|
59
|
+
calls.append(("GET", url))
|
|
60
|
+
return 200, {"thread_uuid": "T-1", "assignee": "peer-b", "id": 7}
|
|
61
|
+
|
|
62
|
+
def post(url, body, token, **kw):
|
|
63
|
+
calls.append(("POST", url, body))
|
|
64
|
+
return 200, {"id": 1}
|
|
65
|
+
monkeypatch.setattr(cli, "_http_get_json", get)
|
|
66
|
+
monkeypatch.setattr(cli, "_post_json", post)
|
|
67
|
+
cli._default_post_card("http://gw.invalid", "tok", "cell-a", False)(7, "status", "hello")
|
|
68
|
+
assert calls[0] == ("GET", "http://gw.invalid/board/cards/7")
|
|
69
|
+
_, url, body = calls[1]
|
|
70
|
+
assert url == "http://gw.invalid/messages"
|
|
71
|
+
assert body == {"from_node": "cell-a", "to_node": "peer-b", "kind": "status",
|
|
72
|
+
"content": "hello", "thread_id": "T-1"}
|
|
73
|
+
monkeypatch.setattr(cli, "_post_json", lambda *a, **k: (403, {"detail": "no grant"}))
|
|
74
|
+
with pytest.raises(RuntimeError, match="403"):
|
|
75
|
+
cli._default_post_card("http://gw.invalid", "tok", "cell-a", False)(7, "status", "x")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@pytest.mark.parametrize("name", ["howto", "guide"])
|
|
79
|
+
def test_docs_name_commands_window_billing_and_no_code(name):
|
|
80
|
+
text = _DOCS[name].read_text(encoding="utf-8")
|
|
81
|
+
low = text.lower()
|
|
82
|
+
for verb in ("run", "status", "show", "stop", "decide"):
|
|
83
|
+
assert f"swarph skunkworks {verb}" in text or f"`{verb}`" in text, (name, verb)
|
|
84
|
+
assert "09:30-16:00" in text and "new york" in low
|
|
85
|
+
assert "claude quota" in low and "queue" in low
|
|
86
|
+
assert "produces no code" in low
|