swarph-cli 0.72.35__tar.gz → 0.72.37__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.35/src/swarph_cli.egg-info → swarph_cli-0.72.37}/PKG-INFO +1 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/pyproject.toml +1 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/backends.py +5 -3
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/board.py +106 -37
- swarph_cli-0.72.37/src/swarph_cli/commands/board_cost.py +199 -0
- swarph_cli-0.72.37/src/swarph_cli/commands/board_usage.py +378 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/brain_ask.py +2 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/cell_probe.py +3 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/channel.py +8 -4
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/codegraph_hook.py +2 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/commander.py +82 -5
- swarph_cli-0.72.37/src/swarph_cli/commands/committee.py +247 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/event.py +2 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/gh_route.py +21 -14
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/group.py +2 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/highlight.py +19 -6
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/hooks.py +42 -6
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/mcp_server.py +3 -2
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/memory_emit_hook.py +6 -2
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/memory_sync.py +17 -3
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/mesh.py +100 -20
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/onboard.py +2 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/ratify.py +2 -2
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/roster.py +5 -3
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/sweep.py +197 -24
- swarph_cli-0.72.37/src/swarph_cli/commit_trailers.py +31 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dm_frame.py +19 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/slm.py +4 -2
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/duplicate_session.py +144 -16
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/gateway/server.py +3 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/gh_identity.py +343 -2
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/guide/GUIDE.md +3 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/main.py +1 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/operator/api.py +7 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/peer_service_reply.py +2 -0
- swarph_cli-0.72.37/src/swarph_cli/redact.py +417 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/scripts/dm_notify_filter.py +5 -2
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/stall_alert.py +31 -24
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/triage/backend.py +6 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli.egg-info/SOURCES.txt +15 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1006_session_board.py +30 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1064_stuck_sweep.py +224 -9
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1068_structured_accept_cli.py +6 -2
- swarph_cli-0.72.37/tests/test_1277_close_usage.py +307 -0
- swarph_cli-0.72.37/tests/test_1300_authorization_check.py +83 -0
- swarph_cli-0.72.37/tests/test_1320_commit_trailers.py +56 -0
- swarph_cli-0.72.37/tests/test_1321_layered_redaction.py +1072 -0
- swarph_cli-0.72.37/tests/test_1340_router_rollout.py +79 -0
- swarph_cli-0.72.37/tests/test_1346_shell_string_gh.py +125 -0
- swarph_cli-0.72.37/tests/test_1347_shell_depth_cap.py +105 -0
- swarph_cli-0.72.37/tests/test_3130_sender.py +28 -0
- swarph_cli-0.72.37/tests/test_3150_identity_router_install.py +44 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_397_router_preflight.py +12 -12
- swarph_cli-0.72.37/tests/test_513_duplicate_session.py +489 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_591_cli_step_graph.py +3 -1
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_board_obligation_close.py +8 -2
- swarph_cli-0.72.37/tests/test_committee_command.py +160 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hooks_init.py +12 -2
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_stall_alert.py +61 -32
- swarph_cli-0.72.35/tests/test_513_duplicate_session.py +0 -215
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/LICENSE +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/README.md +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/setup.cfg +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/codex_cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/providers.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/signal_score.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/rowclear_hook.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/spawn.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/triage.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/launchd/swarph-codex-outbox.plist +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/launchd/swarph-codex-outbox.timer.plist +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/launchd/swarph-monitor.plist +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/launchd/swarph-watchdog.plist +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/launchd/swarph-watchdog.timer.plist +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/launchd_render.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/operator/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/operator/__main__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/operator/cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/operator/config.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/operator/fmt.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/quota_sync.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/rowclear.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/scrub.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-stuck-sweep.service +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-stuck-sweep.timer +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-triage.service +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-triage.timer +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/the_ten.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/triage/__init__.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/triage/job.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/triage/owners.json +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/triage/router.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/triage/rows.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli/triage/sensor.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1006_board_publisher.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1010_strand_only.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1013_spawn_channel.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1017_muse_tui.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1034_copy_mode.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1050_surrogate_wake.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1052_opencode_deaf.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1059_watchdog_unread_env.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1061_roster_cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1065_release.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1066_quiet_wakes.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1071_quota_sync.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1073_triage.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1073_triage_board.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1073_wheel_install.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1075_task_cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1083_openai_decisions.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1144_cell_yaml_github.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1197_commander_taps.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1203_swarph_me_refusal.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1206_offer_question.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1214_egress.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1219_egress_probe.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1221_quota_windows.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1222_maybe_start_cap.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1228_quota_reach.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1243_the_ten.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1248_ship_price_table.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1250_price_cache.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1256_commander_wake.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1261_mcp_install.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1262_wake_followups.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1265_wake_note.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1269_triage_label.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1278_dreaming_reach.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1286_dm_unread_cursor.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1297_commander.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_1301_restart_skew.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_432_rowclear.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_484_codex_queue_sink.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_538_signal_bench.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_729_arm_check_delivery_gap.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_735_dm_mcp_tools.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_739_wake_writer.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_931_board_search.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_935_deadline_clock.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_961_cursor_grok_footer.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_961_loud_stop.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_bench_codex_cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_board_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_copilot_membrane.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_copilot_pane_reader.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_group_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_import_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_init_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_launchd_units.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_main.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mesh_sidecar_muse_sink.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_monitor_cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_monitor_state_split.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_operator_me.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_scrub.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_security.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_service_app.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_service_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_tmux_wake_runstate_defer.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_tmux_wake_session_reanchor.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_tmux_wake_stale.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_tmux_wake_submit_verify.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_version_command.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.72.35 → swarph_cli-0.72.37}/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.37
|
|
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.37"
|
|
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" }
|
|
@@ -38,6 +38,8 @@ import urllib.request
|
|
|
38
38
|
from dataclasses import dataclass
|
|
39
39
|
from typing import Any, Callable, Optional, Protocol
|
|
40
40
|
|
|
41
|
+
from swarph_cli.redact import encode_outbound_json
|
|
42
|
+
|
|
41
43
|
|
|
42
44
|
@dataclass
|
|
43
45
|
class BackendResult:
|
|
@@ -510,7 +512,7 @@ class TypedHttpBackend:
|
|
|
510
512
|
body = _request_body(prompt, system)
|
|
511
513
|
req = urllib.request.Request(
|
|
512
514
|
endpoint,
|
|
513
|
-
data=
|
|
515
|
+
data=encode_outbound_json(body, caller="bench.SystemOneBackend.generate"),
|
|
514
516
|
headers={"Content-Type": "application/json"},
|
|
515
517
|
method="POST",
|
|
516
518
|
)
|
|
@@ -626,7 +628,7 @@ class HttpBackend:
|
|
|
626
628
|
scheme = self.auth.get("scheme") or ""
|
|
627
629
|
token = f"{scheme} {value}".strip() if scheme else value
|
|
628
630
|
headers[self.auth["header"]] = token
|
|
629
|
-
raw_body =
|
|
631
|
+
raw_body = encode_outbound_json(body, caller="bench.HttpBackend.generate")
|
|
630
632
|
self.calls += 1
|
|
631
633
|
if self.transport is not None:
|
|
632
634
|
status, reason, raw = self.transport(endpoint, headers, raw_body)
|
|
@@ -919,7 +921,7 @@ class DecisionsBackend:
|
|
|
919
921
|
scheme = self.auth.get("scheme") or ""
|
|
920
922
|
token = f"{scheme} {value}".strip() if scheme else value
|
|
921
923
|
headers[self.auth["header"]] = token
|
|
922
|
-
raw_body =
|
|
924
|
+
raw_body = encode_outbound_json(body, caller="bench.DecisionsBackend.generate")
|
|
923
925
|
self.calls += 1
|
|
924
926
|
if self.transport is not None:
|
|
925
927
|
status, reason, raw = self.transport(endpoint, headers, raw_body)
|
|
@@ -43,6 +43,7 @@ from swarph_cli.commands.mesh import (
|
|
|
43
43
|
_resolve_self_name,
|
|
44
44
|
_resolve_token,
|
|
45
45
|
)
|
|
46
|
+
from swarph_cli.redact import redact_text, redact_value, encode_outbound_json
|
|
46
47
|
|
|
47
48
|
|
|
48
49
|
_SENTINEL = object()
|
|
@@ -51,7 +52,7 @@ _SENTINEL = object()
|
|
|
51
52
|
# ── HTTP: PATCH (mesh.py has GET + POST; the board needs PATCH for move/link) ──
|
|
52
53
|
|
|
53
54
|
def _patch_json(url: str, body: dict, token: str, *, timeout: float = 10.0) -> tuple[int, dict]:
|
|
54
|
-
data =
|
|
55
|
+
data = encode_outbound_json(body, caller="board._patch_json")
|
|
55
56
|
req = urllib.request.Request(
|
|
56
57
|
url, data=data, method="PATCH",
|
|
57
58
|
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
|
@@ -89,11 +90,12 @@ def _normalize_due_at(value: str) -> str:
|
|
|
89
90
|
|
|
90
91
|
|
|
91
92
|
def _card_add_payload(actor, project_id, title, *, body=None, ai2=False, priority=0,
|
|
92
|
-
labels=None, due_at=None) -> dict:
|
|
93
|
+
labels=None, due_at=None, opt_out=False) -> dict:
|
|
94
|
+
title = redact_text(title, opt_out=opt_out, caller="board.cards.add")
|
|
93
95
|
p = {"actor": actor, "project_id": int(project_id), "title": title,
|
|
94
96
|
"ai2": bool(ai2), "priority": int(priority)}
|
|
95
97
|
if body:
|
|
96
|
-
p["body"] = body
|
|
98
|
+
p["body"] = redact_text(body, opt_out=opt_out, caller="board.cards.add")
|
|
97
99
|
if labels:
|
|
98
100
|
p["labels"] = list(labels)
|
|
99
101
|
if due_at is not None:
|
|
@@ -151,7 +153,7 @@ def _format_obligations(data: dict) -> str:
|
|
|
151
153
|
|
|
152
154
|
|
|
153
155
|
def _card_edit_payload(actor, title, body, *, due_at=_SENTINEL, project_id=None,
|
|
154
|
-
priority=None) -> dict:
|
|
156
|
+
priority=None, opt_out=False) -> dict:
|
|
155
157
|
"""#191: the edit patch — title and/or body, the two fields that made a
|
|
156
158
|
card's text write-once until the gateway grew them (BoardCardPatch).
|
|
157
159
|
|
|
@@ -173,9 +175,9 @@ def _card_edit_payload(actor, title, body, *, due_at=_SENTINEL, project_id=None,
|
|
|
173
175
|
"""
|
|
174
176
|
patch = {"actor": actor}
|
|
175
177
|
if title is not None:
|
|
176
|
-
patch["title"] = title
|
|
178
|
+
patch["title"] = redact_text(title, opt_out=opt_out, caller="board.cards.edit")
|
|
177
179
|
if body is not None:
|
|
178
|
-
patch["body"] = body
|
|
180
|
+
patch["body"] = redact_text(body, opt_out=opt_out, caller="board.cards.edit")
|
|
179
181
|
if due_at is not _SENTINEL:
|
|
180
182
|
# "" is the gateway's CLEAR sentinel; None means "not mentioned" and the
|
|
181
183
|
# write is skipped while the old date is echoed back (#901).
|
|
@@ -190,7 +192,7 @@ def _card_edit_payload(actor, title, body, *, due_at=_SENTINEL, project_id=None,
|
|
|
190
192
|
return patch
|
|
191
193
|
|
|
192
194
|
|
|
193
|
-
def _write_card_preimage(actor, gateway, card_id, card, patch) -> Path:
|
|
195
|
+
def _write_card_preimage(actor, gateway, card_id, card, patch, *, opt_out=False) -> Path:
|
|
194
196
|
"""Append the card's CURRENT title and body to a local log BEFORE an edit
|
|
195
197
|
replaces them. Returns the path written.
|
|
196
198
|
|
|
@@ -213,10 +215,10 @@ def _write_card_preimage(actor, gateway, card_id, card, patch) -> Path:
|
|
|
213
215
|
"gateway": gateway,
|
|
214
216
|
"card": card_id,
|
|
215
217
|
"body_version": card.get("body_version"),
|
|
216
|
-
"prev_title": card.get("title"),
|
|
217
|
-
"prev_body": card.get("body"),
|
|
218
|
-
"new_title": patch.get("title"),
|
|
219
|
-
"new_body": patch.get("body"),
|
|
218
|
+
"prev_title": redact_text(card.get("title"), opt_out=opt_out, caller="board.cards.edit"),
|
|
219
|
+
"prev_body": redact_text(card.get("body"), opt_out=opt_out, caller="board.cards.edit"),
|
|
220
|
+
"new_title": redact_text(patch.get("title"), opt_out=opt_out, caller="board.cards.edit"),
|
|
221
|
+
"new_body": redact_text(patch.get("body"), opt_out=opt_out, caller="board.cards.edit"),
|
|
220
222
|
}
|
|
221
223
|
path = card_preimage_path()
|
|
222
224
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -251,10 +253,11 @@ def _apply_label(current: list, action: str, label: str) -> list:
|
|
|
251
253
|
return [x for x in cur if x != lab]
|
|
252
254
|
|
|
253
255
|
|
|
254
|
-
def _project_add_payload(actor, slug, title, *, goal=None) -> dict:
|
|
256
|
+
def _project_add_payload(actor, slug, title, *, goal=None, opt_out: bool = False) -> dict:
|
|
257
|
+
title = redact_text(title, opt_out=opt_out, caller="board.projects")
|
|
255
258
|
p = {"actor": actor, "slug": slug, "title": title}
|
|
256
259
|
if goal:
|
|
257
|
-
p["goal"] = goal
|
|
260
|
+
p["goal"] = redact_text(goal, opt_out=opt_out, caller="board.projects")
|
|
258
261
|
return p
|
|
259
262
|
|
|
260
263
|
|
|
@@ -546,7 +549,8 @@ def _say_line(resp: dict, card_id, to_node: str, *, reason: Optional[str] = None
|
|
|
546
549
|
|
|
547
550
|
|
|
548
551
|
def _card_say_payload(from_node: str, to_node: str, kind: str, content: str,
|
|
549
|
-
thread_uuid: str) -> dict:
|
|
552
|
+
thread_uuid: str, *, opt_out=False) -> dict:
|
|
553
|
+
content = redact_text(content, opt_out=opt_out, caller="board.cards.say")
|
|
550
554
|
return {
|
|
551
555
|
"from_node": from_node,
|
|
552
556
|
"to_node": to_node,
|
|
@@ -726,7 +730,7 @@ def _json_flag(flag: str, value: str):
|
|
|
726
730
|
|
|
727
731
|
def _ask_payload(self_name, what, *, holder=None, step=None, needs=None, hours=None,
|
|
728
732
|
done=None, accept=None, accept_json=None, kind="action",
|
|
729
|
-
timeout_hours=None, task=None, task_needs=None) -> dict:
|
|
733
|
+
timeout_hours=None, task=None, task_needs=None, opt_out=False) -> dict:
|
|
730
734
|
"""POST /board/cards/{id}/ask body. None = not mentioned = key ABSENT (#191's
|
|
731
735
|
rule; test_532 pins that a null `accept` on the wire would overwrite the
|
|
732
736
|
gateway's own normalization). No holder → `requested`; `me` → the caller's
|
|
@@ -736,6 +740,7 @@ def _ask_payload(self_name, what, *, holder=None, step=None, needs=None, hours=N
|
|
|
736
740
|
if accept is not None and accept_json is not None:
|
|
737
741
|
raise ValueError("pass --accept or --accept-json, not both — "
|
|
738
742
|
"one check per row")
|
|
743
|
+
what = redact_text(what, opt_out=opt_out, caller="board.cards.ask")
|
|
739
744
|
p = {"what": what, "created_by": self_name, "kind": kind}
|
|
740
745
|
if holder is not None:
|
|
741
746
|
p["holder"] = self_name if holder == "me" else holder
|
|
@@ -746,11 +751,11 @@ def _ask_payload(self_name, what, *, holder=None, step=None, needs=None, hours=N
|
|
|
746
751
|
if hours is not None:
|
|
747
752
|
p["hours"] = hours
|
|
748
753
|
if done is not None:
|
|
749
|
-
p["done"] = done
|
|
754
|
+
p["done"] = redact_text(done, opt_out=opt_out, caller="board.cards.ask")
|
|
750
755
|
if accept is not None:
|
|
751
|
-
p["accept"] = accept
|
|
756
|
+
p["accept"] = redact_text(accept, opt_out=opt_out, caller="board.cards.ask")
|
|
752
757
|
if accept_json is not None:
|
|
753
|
-
p["accept_json"] = accept_json
|
|
758
|
+
p["accept_json"] = redact_value(accept_json, opt_out=opt_out, caller="board.cards.ask")
|
|
754
759
|
if timeout_hours is not None:
|
|
755
760
|
p["timeout_hours"] = timeout_hours
|
|
756
761
|
if task is not None:
|
|
@@ -830,7 +835,7 @@ def _ask_line(d) -> str:
|
|
|
830
835
|
return line
|
|
831
836
|
|
|
832
837
|
|
|
833
|
-
def _confirm_flow_payload(actor: str, holders, what=None) -> dict:
|
|
838
|
+
def _confirm_flow_payload(actor: str, holders, what=None, *, opt_out=False) -> dict:
|
|
834
839
|
"""#801: {actor, holders: {step: peer}, what}. `--holder STEP=PEER` is parsed here so a
|
|
835
840
|
malformed override is refused before the request, naming the form."""
|
|
836
841
|
body = {"actor": actor}
|
|
@@ -844,7 +849,7 @@ def _confirm_flow_payload(actor: str, holders, what=None) -> dict:
|
|
|
844
849
|
out[step] = peer
|
|
845
850
|
body["holders"] = out
|
|
846
851
|
if what:
|
|
847
|
-
body["what"] = what
|
|
852
|
+
body["what"] = redact_text(what, opt_out=opt_out, caller="board.cards.confirm-flow")
|
|
848
853
|
return body
|
|
849
854
|
|
|
850
855
|
|
|
@@ -924,25 +929,47 @@ def _move_line(x) -> str:
|
|
|
924
929
|
return line
|
|
925
930
|
|
|
926
931
|
|
|
927
|
-
def _close_payload(outcome, evidence=None, evidence_json=None
|
|
932
|
+
def _close_payload(outcome, evidence=None, evidence_json=None, *, opt_out=False,
|
|
933
|
+
usage=None) -> dict:
|
|
928
934
|
"""POST /board/obligations/{id}/close body (#1068): --evidence and/or
|
|
929
935
|
--evidence-json, at least one. The CLI cannot know the row's stored
|
|
930
936
|
accept, so it sends what it was given — the gateway requires the map
|
|
931
|
-
for a JSON pass, the string everywhere else.
|
|
937
|
+
for a JSON pass, the string everywhere else.
|
|
938
|
+
|
|
939
|
+
Card #1277: usage is attached on every close. When the caller does not
|
|
940
|
+
pass it, it is read from this cell's transcript (or left unknown)."""
|
|
932
941
|
if evidence is None and evidence_json is None:
|
|
933
942
|
raise ValueError("nothing observed — pass --evidence and/or "
|
|
934
943
|
"--evidence-json")
|
|
935
|
-
|
|
944
|
+
if usage is None:
|
|
945
|
+
from swarph_cli.commands.board_usage import read_close_usage
|
|
946
|
+
usage = read_close_usage()
|
|
947
|
+
p = {"outcome": outcome, "usage": usage}
|
|
936
948
|
if evidence is not None:
|
|
937
|
-
p["evidence"] = evidence
|
|
949
|
+
p["evidence"] = redact_text(evidence, opt_out=opt_out, caller="board.obligations.close")
|
|
938
950
|
if evidence_json is not None:
|
|
939
|
-
p["evidence_json"] = evidence_json
|
|
951
|
+
p["evidence_json"] = redact_value(evidence_json, opt_out=opt_out, caller="board.obligations.close")
|
|
940
952
|
return p
|
|
941
953
|
|
|
942
954
|
|
|
955
|
+
def _obligation_taken_at(gw: str, token: str, obligation_id: int):
|
|
956
|
+
"""The row's taken_at, or None when the list does not show it.
|
|
957
|
+
|
|
958
|
+
The transcript sum is bounded by this instant. Without it the close
|
|
959
|
+
sends unknown rather than summing some other window."""
|
|
960
|
+
status, body = _http_get_json(
|
|
961
|
+
f"{gw}/board/obligations?obligation_id={obligation_id}", token)
|
|
962
|
+
if not (status and 200 <= status < 300) or not isinstance(body, dict):
|
|
963
|
+
return None
|
|
964
|
+
for item in body.get("obligations") or []:
|
|
965
|
+
if isinstance(item, dict) and item.get("id") == obligation_id:
|
|
966
|
+
return item.get("taken_at")
|
|
967
|
+
return None
|
|
968
|
+
|
|
969
|
+
|
|
943
970
|
def _amend_payload(step=None, holder=None, accept=None, hours=None,
|
|
944
971
|
needs_add=None, needs_remove=None, needs=None,
|
|
945
|
-
accept_json=None) -> dict:
|
|
972
|
+
accept_json=None, *, opt_out=False) -> dict:
|
|
946
973
|
"""PATCH /board/obligations/{id}/amend body. None = not mentioned; an empty
|
|
947
974
|
`holder` is a REAL value (clears → `requested`), so the test is
|
|
948
975
|
`is not None`, never truthiness (#191). `needs` is the contract's signed
|
|
@@ -953,6 +980,10 @@ def _amend_payload(step=None, holder=None, accept=None, hours=None,
|
|
|
953
980
|
if accept is not None and accept_json is not None:
|
|
954
981
|
raise ValueError("pass --accept or --accept-json, not both — "
|
|
955
982
|
"one check per row")
|
|
983
|
+
if accept is not None:
|
|
984
|
+
accept = redact_text(accept, opt_out=opt_out, caller="board.obligations")
|
|
985
|
+
if accept_json is not None:
|
|
986
|
+
accept_json = redact_value(accept_json, opt_out=opt_out, caller="board.obligations")
|
|
956
987
|
signed = _step_list(needs)
|
|
957
988
|
add = _step_list(needs_add) + [x for x in signed if not x.startswith("-")]
|
|
958
989
|
rem = _step_list(needs_remove) + [x[1:] for x in signed if x.startswith("-")]
|
|
@@ -1268,6 +1299,13 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
1268
1299
|
ow.add_argument("--reason", required=True,
|
|
1269
1300
|
help="why the row is withdrawn; whitespace is refused")
|
|
1270
1301
|
ow.add_argument("--json", action="store_true"); _add_common(ow)
|
|
1302
|
+
cost = top.add_parser(
|
|
1303
|
+
"cost",
|
|
1304
|
+
help="tokens by job, the perfect-run rate, and cost per accepted outcome")
|
|
1305
|
+
cost.add_argument("--card", type=int, default=None)
|
|
1306
|
+
cost.add_argument("--since", default=None, metavar="DATE")
|
|
1307
|
+
cost.add_argument("--json", action="store_true")
|
|
1308
|
+
_add_common(cost)
|
|
1271
1309
|
return p
|
|
1272
1310
|
|
|
1273
1311
|
|
|
@@ -1313,9 +1351,27 @@ def run_board(argv: list[str]) -> int:
|
|
|
1313
1351
|
st, d = _http_get_json(f"{gw}/board/projects", token)
|
|
1314
1352
|
return _out(st, d, _format_projects, aj)
|
|
1315
1353
|
if args.command == "add":
|
|
1316
|
-
st, d = _post_json(f"{gw}/board/projects", _project_add_payload(self_name, args.slug, args.title, goal=args.goal), token)
|
|
1354
|
+
st, d = _post_json(f"{gw}/board/projects", _project_add_payload(self_name, args.slug, args.title, goal=args.goal, opt_out=getattr(args, "no_redact", False)), token)
|
|
1317
1355
|
return _out(st, d, lambda x: f"created project #{x.get('id')} ({x.get('slug')})", aj)
|
|
1318
1356
|
|
|
1357
|
+
if args.group == "cost":
|
|
1358
|
+
from swarph_cli.commands.board_cost import format_cost
|
|
1359
|
+
query = []
|
|
1360
|
+
if getattr(args, "card", None) is not None:
|
|
1361
|
+
query.append(f"card={args.card}")
|
|
1362
|
+
if getattr(args, "since", None):
|
|
1363
|
+
query.append("since=" + args.since)
|
|
1364
|
+
url = f"{gw}/board/cost" + (("?" + "&".join(query)) if query else "")
|
|
1365
|
+
st, d = _http_get_json(url, token)
|
|
1366
|
+
rates = None
|
|
1367
|
+
if st and 200 <= st < 300:
|
|
1368
|
+
try:
|
|
1369
|
+
from swarph_shared.llm_cost import fetch_price_base
|
|
1370
|
+
rates = fetch_price_base()
|
|
1371
|
+
except Exception:
|
|
1372
|
+
rates = None
|
|
1373
|
+
return _out(st, d, lambda body: format_cost(body, rates), aj)
|
|
1374
|
+
|
|
1319
1375
|
if args.group == "obligations":
|
|
1320
1376
|
if args.command == "close":
|
|
1321
1377
|
# #562's CLI half: the explicit close act. The gateway guards the
|
|
@@ -1332,7 +1388,12 @@ def run_board(argv: list[str]) -> int:
|
|
|
1332
1388
|
try:
|
|
1333
1389
|
evidence_json = (_json_flag("--evidence-json", args.evidence_json)
|
|
1334
1390
|
if args.evidence_json is not None else None)
|
|
1335
|
-
|
|
1391
|
+
taken_at = _obligation_taken_at(gw, token, args.id)
|
|
1392
|
+
from swarph_cli.commands.board_usage import read_close_usage
|
|
1393
|
+
usage = read_close_usage(agent=self_name, taken_at=taken_at)
|
|
1394
|
+
payload = _close_payload(args.outcome, evidence, evidence_json,
|
|
1395
|
+
opt_out=getattr(args, "no_redact", False),
|
|
1396
|
+
usage=usage)
|
|
1336
1397
|
except ValueError as exc:
|
|
1337
1398
|
print(f"swarph board obligations close: {exc}", file=sys.stderr)
|
|
1338
1399
|
return 2
|
|
@@ -1362,8 +1423,9 @@ def run_board(argv: list[str]) -> int:
|
|
|
1362
1423
|
st, d = _post_json(f"{gw}/board/obligations/{args.id}/take", {}, token)
|
|
1363
1424
|
return _out(st, d, _obligation_act_line, aj)
|
|
1364
1425
|
if args.command == "decline":
|
|
1426
|
+
why = redact_text(args.why, opt_out=getattr(args, "no_redact", False), caller="board.obligations")
|
|
1365
1427
|
st, d = _post_json(f"{gw}/board/obligations/{args.id}/decline",
|
|
1366
|
-
{"why":
|
|
1428
|
+
{"why": why}, token)
|
|
1367
1429
|
return _out(st, d, _obligation_act_line, aj)
|
|
1368
1430
|
if args.command == "amend":
|
|
1369
1431
|
try:
|
|
@@ -1373,7 +1435,8 @@ def run_board(argv: list[str]) -> int:
|
|
|
1373
1435
|
accept=args.accept, hours=args.hours,
|
|
1374
1436
|
needs_add=args.needs_add,
|
|
1375
1437
|
needs_remove=args.needs_remove, needs=args.needs,
|
|
1376
|
-
accept_json=accept_json
|
|
1438
|
+
accept_json=accept_json,
|
|
1439
|
+
opt_out=getattr(args, "no_redact", False))
|
|
1377
1440
|
except ValueError as exc:
|
|
1378
1441
|
print(f"swarph board obligations amend: {exc}", file=sys.stderr)
|
|
1379
1442
|
return 2
|
|
@@ -1385,6 +1448,7 @@ def run_board(argv: list[str]) -> int:
|
|
|
1385
1448
|
print("swarph board obligations withdraw: --reason is "
|
|
1386
1449
|
"whitespace-only", file=sys.stderr)
|
|
1387
1450
|
return 2
|
|
1451
|
+
reason = redact_text(reason, opt_out=getattr(args, "no_redact", False), caller="board.obligations")
|
|
1388
1452
|
st, d = _post_json(
|
|
1389
1453
|
f"{gw}/board/obligations/{args.id}/withdraw",
|
|
1390
1454
|
{"reason": reason}, token)
|
|
@@ -1441,7 +1505,7 @@ def run_board(argv: list[str]) -> int:
|
|
|
1441
1505
|
st, d = _post_json(f"{gw}/board/cards", _card_add_payload(
|
|
1442
1506
|
self_name, pid, title, body=body, ai2=args.ai2,
|
|
1443
1507
|
priority=args.priority, labels=getattr(args, "labels", None),
|
|
1444
|
-
due_at=args.due), token)
|
|
1508
|
+
due_at=args.due, opt_out=getattr(args, "no_redact", False)), token)
|
|
1445
1509
|
return _out(st, d, lambda x: f"created card #{x.get('id')} [{x.get('stage')}] (stage defaults to proposed — use `cards move` to advance)", aj)
|
|
1446
1510
|
if args.command == "label":
|
|
1447
1511
|
# READ the current set before replacing it. If the GET fails we must
|
|
@@ -1491,7 +1555,8 @@ def run_board(argv: list[str]) -> int:
|
|
|
1491
1555
|
try:
|
|
1492
1556
|
patch = _card_edit_payload(
|
|
1493
1557
|
self_name, title_text, body_text, due_at=args.due,
|
|
1494
|
-
project_id=project_id, priority=args.priority
|
|
1558
|
+
project_id=project_id, priority=args.priority,
|
|
1559
|
+
opt_out=getattr(args, "no_redact", False))
|
|
1495
1560
|
except ValueError as exc:
|
|
1496
1561
|
print(f"swarph board cards edit: {exc}", file=sys.stderr)
|
|
1497
1562
|
return 2
|
|
@@ -1508,7 +1573,8 @@ def run_board(argv: list[str]) -> int:
|
|
|
1508
1573
|
f"an unrecoverable one", file=sys.stderr)
|
|
1509
1574
|
return 1
|
|
1510
1575
|
try:
|
|
1511
|
-
pre = _write_card_preimage(self_name, gw, args.id, cur, patch
|
|
1576
|
+
pre = _write_card_preimage(self_name, gw, args.id, cur, patch,
|
|
1577
|
+
opt_out=getattr(args, "no_redact", False))
|
|
1512
1578
|
except OSError as exc:
|
|
1513
1579
|
print(f"swarph board cards edit: cannot write the pre-image log "
|
|
1514
1580
|
f"({exc}) — refusing to write, for the same reason: the "
|
|
@@ -1541,7 +1607,7 @@ def run_board(argv: list[str]) -> int:
|
|
|
1541
1607
|
# the row in one gateway call, or neither.
|
|
1542
1608
|
if args.holder is not None and args.holder_flag is not None:
|
|
1543
1609
|
print("swarph board cards ask: holder given twice (positional and "
|
|
1544
|
-
|
|
1610
|
+
"--holder) — pass one", file=sys.stderr)
|
|
1545
1611
|
return 2
|
|
1546
1612
|
holder = args.holder_flag or args.holder
|
|
1547
1613
|
if holder is None and args.step is None:
|
|
@@ -1562,7 +1628,8 @@ def run_board(argv: list[str]) -> int:
|
|
|
1562
1628
|
done=args.done, accept=args.accept,
|
|
1563
1629
|
accept_json=accept_json, kind=args.kind,
|
|
1564
1630
|
timeout_hours=args.timeout_hours,
|
|
1565
|
-
task=args.task, task_needs=args.task_needs
|
|
1631
|
+
task=args.task, task_needs=args.task_needs,
|
|
1632
|
+
opt_out=getattr(args, "no_redact", False))
|
|
1566
1633
|
except ValueError as exc:
|
|
1567
1634
|
print(f"swarph board cards ask: {exc}", file=sys.stderr)
|
|
1568
1635
|
return 2
|
|
@@ -1570,7 +1637,8 @@ def run_board(argv: list[str]) -> int:
|
|
|
1570
1637
|
return _out(st, d, _ask_line, args.json)
|
|
1571
1638
|
if args.command == "confirm-flow":
|
|
1572
1639
|
try:
|
|
1573
|
-
body = _confirm_flow_payload(self_name, args.holder, args.what
|
|
1640
|
+
body = _confirm_flow_payload(self_name, args.holder, args.what,
|
|
1641
|
+
opt_out=getattr(args, "no_redact", False))
|
|
1574
1642
|
except ValueError as e:
|
|
1575
1643
|
print(f"swarph board cards confirm-flow: {e}", file=sys.stderr)
|
|
1576
1644
|
return 2
|
|
@@ -1614,7 +1682,8 @@ def run_board(argv: list[str]) -> int:
|
|
|
1614
1682
|
return 1
|
|
1615
1683
|
st, d = _post_json(
|
|
1616
1684
|
f"{gw}/messages",
|
|
1617
|
-
_card_say_payload(self_name, to_node, args.kind, content, thread_uuid
|
|
1685
|
+
_card_say_payload(self_name, to_node, args.kind, content, thread_uuid,
|
|
1686
|
+
opt_out=getattr(args, "no_redact", False)),
|
|
1618
1687
|
token,
|
|
1619
1688
|
)
|
|
1620
1689
|
# A 403 here carries the gateway's explanation that attaching PUBLISHES
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""Card #1277 — cost per accepted outcome, from recorded usage only.
|
|
2
|
+
|
|
3
|
+
A row whose usage is unknown is counted and excluded from the token
|
|
4
|
+
totals. It is never treated as zero.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
_ALWAYS = ("input_tokens", "output_tokens", "cache_read_tokens")
|
|
9
|
+
_JOBS = ("execute", "grade", "advise", "rework", "other")
|
|
10
|
+
_GRADE = {"validate", "plan-review", "second-seat", "spec-review"}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def job_of(row) -> str | None:
|
|
14
|
+
if row.get("rework") or row.get("step") == "rework":
|
|
15
|
+
return "rework"
|
|
16
|
+
step = row.get("step")
|
|
17
|
+
if step is None or step == "":
|
|
18
|
+
return "other"
|
|
19
|
+
if step == "build":
|
|
20
|
+
return "execute"
|
|
21
|
+
if step in _GRADE:
|
|
22
|
+
return "grade"
|
|
23
|
+
if step in {"advise", "advisor", "pre-read"} or "advise" in step:
|
|
24
|
+
return "advise"
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _as_int(value):
|
|
29
|
+
if isinstance(value, bool) or not isinstance(value, int):
|
|
30
|
+
return None
|
|
31
|
+
return value
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def token_total(usage):
|
|
35
|
+
"""Sum the fields that were read. Unknown is not zero.
|
|
36
|
+
|
|
37
|
+
Thinking is a breakdown of output_tokens and is not added again.
|
|
38
|
+
A cache split that was read is the cache total. A flat
|
|
39
|
+
cache_creation with no split is the total instead. Having neither
|
|
40
|
+
makes the row unknown."""
|
|
41
|
+
if not isinstance(usage, dict):
|
|
42
|
+
return None
|
|
43
|
+
total = 0
|
|
44
|
+
for name in _ALWAYS:
|
|
45
|
+
value = _as_int(usage.get(name, "unknown"))
|
|
46
|
+
if value is None:
|
|
47
|
+
return None
|
|
48
|
+
total += value
|
|
49
|
+
one_h = _as_int(usage.get("cache_creation_1h_tokens", "unknown"))
|
|
50
|
+
five = _as_int(usage.get("cache_creation_5m_tokens", "unknown"))
|
|
51
|
+
unsplit = _as_int(usage.get("cache_creation_unsplit_tokens", "unknown"))
|
|
52
|
+
if one_h is not None and five is not None:
|
|
53
|
+
return total + one_h + five
|
|
54
|
+
if unsplit is not None and one_h is None and five is None:
|
|
55
|
+
return total + unsplit
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def row_cost(usage, rates):
|
|
60
|
+
"""USD from llm_cost.compute_cost, or None when a price row or a
|
|
61
|
+
reading is missing. Unknown tokens are not passed in as zero."""
|
|
62
|
+
if token_total(usage) is None or not isinstance(usage, dict):
|
|
63
|
+
return None
|
|
64
|
+
model = usage.get("model")
|
|
65
|
+
price = (rates or {}).get(model) if isinstance(rates, dict) else None
|
|
66
|
+
if price is None:
|
|
67
|
+
return None
|
|
68
|
+
from swarph_shared.llm_cost import TokenUsage, compute_cost
|
|
69
|
+
one_h = _as_int(usage.get("cache_creation_1h_tokens", "unknown"))
|
|
70
|
+
five = _as_int(usage.get("cache_creation_5m_tokens", "unknown"))
|
|
71
|
+
unsplit = _as_int(usage.get("cache_creation_unsplit_tokens", "unknown"))
|
|
72
|
+
if one_h is not None and five is not None:
|
|
73
|
+
parsed = TokenUsage(
|
|
74
|
+
input_tokens=usage["input_tokens"],
|
|
75
|
+
output_tokens=usage["output_tokens"],
|
|
76
|
+
cache_read_tokens=usage["cache_read_tokens"],
|
|
77
|
+
cache_creation_1h_tokens=one_h,
|
|
78
|
+
cache_creation_5m_tokens=five,
|
|
79
|
+
)
|
|
80
|
+
elif unsplit is not None:
|
|
81
|
+
parsed = TokenUsage(
|
|
82
|
+
input_tokens=usage["input_tokens"],
|
|
83
|
+
output_tokens=usage["output_tokens"],
|
|
84
|
+
cache_read_tokens=usage["cache_read_tokens"],
|
|
85
|
+
cache_creation_unsplit_tokens=unsplit,
|
|
86
|
+
)
|
|
87
|
+
else:
|
|
88
|
+
return None
|
|
89
|
+
return compute_cost(parsed, price)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _window_label(window) -> str:
|
|
93
|
+
window = window or {}
|
|
94
|
+
card = window.get("card")
|
|
95
|
+
since = window.get("since") or "-"
|
|
96
|
+
until = window.get("until") or "-"
|
|
97
|
+
where = f"card #{card}" if card else "all cards"
|
|
98
|
+
return f"{where} since {since} until {until}"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def format_cost(report: dict, rates=None) -> str:
|
|
102
|
+
closes = report.get("closes") or []
|
|
103
|
+
later = report.get("later_fix") or {}
|
|
104
|
+
by_card: dict = {}
|
|
105
|
+
for row in closes:
|
|
106
|
+
by_card.setdefault(row.get("card_id"), []).append(row)
|
|
107
|
+
if rates is None:
|
|
108
|
+
rates = report.get("rates")
|
|
109
|
+
lines = [f"window: {_window_label(report.get('window'))}"]
|
|
110
|
+
unknown_rows = 0
|
|
111
|
+
usd_parts = []
|
|
112
|
+
usd_blocked = False
|
|
113
|
+
underestimated = False
|
|
114
|
+
done_known = []
|
|
115
|
+
perfect_known = []
|
|
116
|
+
done = 0
|
|
117
|
+
perfect = 0
|
|
118
|
+
for card_id, rows in by_card.items():
|
|
119
|
+
stage = rows[0].get("stage") or "-"
|
|
120
|
+
fixes = later.get(str(card_id)) or later.get(card_id) or []
|
|
121
|
+
fails = sum(1 for row in rows if row.get("outcome") == "fail")
|
|
122
|
+
reworks = sum(1 for row in rows if row.get("rework") or row.get("step") == "rework")
|
|
123
|
+
fix_label = (" later-fix=" + ",".join(f"#{n}" for n in fixes)) if fixes else ""
|
|
124
|
+
lines.append(f"card #{card_id} stage={stage}{fix_label}")
|
|
125
|
+
buckets = {job: {"tokens": 0, "known": 0, "unknown": 0} for job in _JOBS}
|
|
126
|
+
card_known = 0
|
|
127
|
+
card_unknown = 0
|
|
128
|
+
for row in rows:
|
|
129
|
+
total = token_total(row.get("usage"))
|
|
130
|
+
job = job_of(row)
|
|
131
|
+
if total is None:
|
|
132
|
+
unknown_rows += 1
|
|
133
|
+
card_unknown += 1
|
|
134
|
+
if job in buckets:
|
|
135
|
+
buckets[job]["unknown"] += 1
|
|
136
|
+
continue
|
|
137
|
+
card_known += total
|
|
138
|
+
if job in buckets:
|
|
139
|
+
buckets[job]["tokens"] += total
|
|
140
|
+
buckets[job]["known"] += 1
|
|
141
|
+
for job in _JOBS:
|
|
142
|
+
bucket = buckets[job]
|
|
143
|
+
lines.append(
|
|
144
|
+
f" {job}: {bucket['tokens']} tokens over {bucket['known']} "
|
|
145
|
+
f"known rows (unknown {bucket['unknown']})")
|
|
146
|
+
lines.append(f" rows: {len(rows)} FAIL: {fails} reworks: {reworks}")
|
|
147
|
+
if stage == "done":
|
|
148
|
+
for row in rows:
|
|
149
|
+
priced = row_cost(row.get("usage"), rates)
|
|
150
|
+
if priced is None:
|
|
151
|
+
usd_blocked = True
|
|
152
|
+
else:
|
|
153
|
+
usd_parts.append(priced.cost_usd)
|
|
154
|
+
underestimated = underestimated or priced.underestimated
|
|
155
|
+
is_done = stage == "done"
|
|
156
|
+
is_perfect = is_done and fails == 0 and reworks == 0 and not fixes
|
|
157
|
+
if is_done:
|
|
158
|
+
done += 1
|
|
159
|
+
if card_unknown == 0:
|
|
160
|
+
done_known.append(card_known)
|
|
161
|
+
if is_perfect:
|
|
162
|
+
perfect += 1
|
|
163
|
+
if card_unknown == 0:
|
|
164
|
+
perfect_known.append(card_known)
|
|
165
|
+
lines.append(f"unknown rows: {unknown_rows}")
|
|
166
|
+
known_sum = sum(done_known)
|
|
167
|
+
if done and len(done_known) == done:
|
|
168
|
+
lines.append(
|
|
169
|
+
f"tokens per card done: {known_sum}/{done} "
|
|
170
|
+
f"(known tokens, unknown rows excluded)")
|
|
171
|
+
lines.append(
|
|
172
|
+
f"cost per accepted outcome: {known_sum}/{done} "
|
|
173
|
+
f"tokens per done card (unknown rows: {unknown_rows})")
|
|
174
|
+
else:
|
|
175
|
+
lines.append(
|
|
176
|
+
"tokens per card done: unknown "
|
|
177
|
+
f"({len(done_known)} of {done} done cards fully read)")
|
|
178
|
+
lines.append(
|
|
179
|
+
"cost per accepted outcome: unknown "
|
|
180
|
+
f"({len(done_known)} of {done} done cards fully read, "
|
|
181
|
+
f"unknown rows: {unknown_rows})")
|
|
182
|
+
lines.append(f"perfect-run rate: {perfect}/{done}")
|
|
183
|
+
if perfect and len(perfect_known) == perfect:
|
|
184
|
+
lines.append(
|
|
185
|
+
f"cost per perfect run: {sum(perfect_known)}/{perfect} "
|
|
186
|
+
f"tokens per perfect card (unknown rows: {unknown_rows})")
|
|
187
|
+
else:
|
|
188
|
+
lines.append(f"cost per perfect run: no perfect runs ({perfect})")
|
|
189
|
+
if usd_blocked or not usd_parts:
|
|
190
|
+
lines.append("usd: unknown")
|
|
191
|
+
else:
|
|
192
|
+
total_usd = sum(usd_parts)
|
|
193
|
+
shown = int(total_usd) if total_usd == int(total_usd) else total_usd
|
|
194
|
+
note = " (unsplit cache priced at the 5m rate)" if underestimated else ""
|
|
195
|
+
lines.append(f"usd: {shown}{note}")
|
|
196
|
+
lines.append(
|
|
197
|
+
"sub-agent spend: included in each close "
|
|
198
|
+
"(that session's subagents, each response once)")
|
|
199
|
+
return "\n".join(lines)
|