agentwire-dev 1.68.0__tar.gz → 1.70.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.github/workflows/pytest.yml +13 -4
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/PKG-INFO +2 -2
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/__main__.py +5 -1
- agentwire_dev-1.70.0/agentwire/activity_cli.py +86 -0
- agentwire_dev-1.70.0/agentwire/alerts_cli.py +153 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/auth_expired.py +46 -0
- agentwire_dev-1.70.0/agentwire/beta.py +193 -0
- agentwire_dev-1.70.0/agentwire/buddy_cli.py +456 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/channels_cli.py +36 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/cohort.py +46 -8
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/config.py +134 -7
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/core.py +160 -19
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/doctor_cli.py +190 -43
- agentwire_dev-1.70.0/agentwire/fleet_activity.py +563 -0
- agentwire_dev-1.70.0/agentwire/fleet_alerts.py +380 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/audit_logger.py +105 -3
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +1188 -98
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +1174 -101
- agentwire_dev-1.70.0/agentwire/hooks/damage-control/mcp-tool-damage-control.py +4241 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +1166 -96
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +12 -7
- agentwire_dev-1.70.0/agentwire/hooks/damage-control/rules/mcp-tools.yaml +84 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/payloads.yaml +16 -0
- agentwire_dev-1.70.0/agentwire/hooks/damage-control/rules/remote.yaml +49 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +1166 -96
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks_cli.py +7 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/inbox.py +249 -44
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/limits_cli.py +19 -5
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_channels.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_chrome.py +2 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_core.py +66 -78
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_council.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_handoff.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_history.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_listen.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_lock.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_machine.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_msg.py +9 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_notify.py +16 -8
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_pane.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_projects.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_scheduler.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_scratchpad.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_server.py +2 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_services.py +5 -3
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_session.py +6 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_status.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_task.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_tunnels.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_voice.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_worktree.py +1 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/msg_cli.py +40 -7
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/notify_cli.py +68 -5
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/pane_cli.py +26 -3
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/prompt_router.py +78 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/__init__.py +11 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/agentwire.md +5 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/orchestrator.md +12 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/worker-worktree.md +12 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/worker.md +12 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/desktop.py +5 -0
- agentwire_dev-1.68.0/agentwire/hooks/damage-control/mcp-tool-damage-control.py → agentwire_dev-1.70.0/agentwire/safety/_core.py +1147 -309
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/safety/lint.py +8 -2
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/safety/rule_baselines.json +9 -2
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/safety_cli.py +18 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/safety_commands.py +140 -30
- agentwire_dev-1.70.0/agentwire/safety_notify.py +389 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scheduler/report.py +27 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/server.py +16 -8
- agentwire_dev-1.70.0/agentwire/services.py +696 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/session_cli.py +106 -12
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/css/desktop.css +14 -0
- agentwire_dev-1.70.0/agentwire/static/js/dead-key-residue.js +63 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/desktop.js +12 -19
- agentwire_dev-1.70.0/agentwire/static/js/hotkeys.js +38 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/scratchpad.js +4 -14
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/service-classification.js +1 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/session-hud-controller.js +6 -4
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/session-hud.js +4 -14
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/sidebar.js +4 -15
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/terminal-pane.js +14 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/topology-render.js +24 -2
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/system_cli.py +8 -3
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tooldefs/git.yaml +14 -2
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/usage_limit.py +49 -1
- agentwire_dev-1.70.0/agentwire/voice_layer/__init__.py +29 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/client.py +2204 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/confirm.py +2545 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/delivery.py +262 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/identity.py +307 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/instructions.py +346 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/outbox.py +188 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/realtime.py +263 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/relay.py +192 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/server.py +521 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/surface.py +370 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/tools.py +1080 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/transcript.py +441 -0
- agentwire_dev-1.70.0/agentwire/voice_layer/write_tools.py +399 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/wait_cli.py +12 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/INDEX.md +1 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/internals/damage-control.md +99 -31
- agentwire_dev-1.70.0/docs/wiki/services.md +140 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/sessions/fan-out-cohorts.md +10 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/sessions/messaging.md +228 -5
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/sessions/worktree-sessions.md +10 -1
- agentwire_dev-1.70.0/docs/wiki/voice-layer.md +2801 -0
- agentwire_dev-1.70.0/scratch-remove-docker-daemons.sh +12 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/conftest.py +42 -0
- agentwire_dev-1.70.0/tests/fixtures/hotkeys_harness.mjs +123 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/integration/test_send_verified_tmux.py +4 -3
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/integration/test_tmux_name_rewrite.py +18 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/integration/test_worktree_cmd.py +3 -0
- agentwire_dev-1.70.0/tests/page_slice.py +40 -0
- agentwire_dev-1.70.0/tests/unit/test_audit_attribution.py +266 -0
- agentwire_dev-1.70.0/tests/unit/test_beta_flag.py +684 -0
- agentwire_dev-1.70.0/tests/unit/test_buddy_restart.py +370 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_cli_smoke.py +15 -12
- agentwire_dev-1.70.0/tests/unit/test_cli_stderr_clean.py +232 -0
- agentwire_dev-1.70.0/tests/unit/test_client_wires.py +302 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_cohort.py +72 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_damage_control_hooks.py +85 -63
- agentwire_dev-1.70.0/tests/unit/test_damage_control_inert_view.py +136 -0
- agentwire_dev-1.70.0/tests/unit/test_damage_control_operation_pinning.py +297 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_damage_control_payload_anchoring.py +260 -183
- agentwire_dev-1.70.0/tests/unit/test_fleet_activity.py +750 -0
- agentwire_dev-1.70.0/tests/unit/test_fleet_alerts.py +804 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_hooks_install.py +14 -0
- agentwire_dev-1.70.0/tests/unit/test_hotkeys_js.py +37 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_inbox.py +91 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_limits_tick_isolation.py +24 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_mcp_server.py +63 -13
- agentwire_dev-1.70.0/tests/unit/test_mcp_tool_policy.py +230 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_mcp_tools_args.py +26 -9
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_msg_cli.py +58 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_notify_cli.py +36 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_pip_audit_report.py +0 -23
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_portal_api.py +24 -5
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_prompt_router.py +0 -21
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_restart_cli.py +0 -5
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_safety_commands.py +23 -3
- agentwire_dev-1.70.0/tests/unit/test_safety_coverage_wave.py +466 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_safety_deployment.py +6 -3
- agentwire_dev-1.70.0/tests/unit/test_safety_notify.py +459 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_services.py +60 -1
- agentwire_dev-1.70.0/tests/unit/test_services_command.py +919 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_session_metadata_ssot.py +5 -0
- agentwire_dev-1.70.0/tests/unit/test_tmux_template.py +26 -0
- agentwire_dev-1.70.0/tests/unit/test_unattended_allow.py +388 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_unattended_scoped_allow.py +181 -2
- agentwire_dev-1.70.0/tests/unit/test_voice_announcer.py +2829 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_body_delivery.py +337 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_bridge_host.py +343 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_confirm.py +3894 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_epoch.py +396 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_fleet_alerts.py +156 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_kind.py +347 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_layer.py +829 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_outbox.py +460 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_persona.py +364 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_picker.py +553 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_relay_full_text.py +472 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_surface.py +1178 -0
- agentwire_dev-1.70.0/tests/unit/test_voice_ux_1048.py +561 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_window_cycling_binding.py +4 -1
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_worktree_dot_project.py +14 -14
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_worktree_git_truth.py +147 -0
- agentwire_dev-1.70.0/tools/nonce_stt_probe.py +125 -0
- agentwire_dev-1.70.0/tools/voice_dc_probe.py +254 -0
- agentwire_dev-1.70.0/tools/voice_heal_probe.py +317 -0
- agentwire_dev-1.68.0/agentwire/hooks/damage-control/rules/remote.yaml +0 -81
- agentwire_dev-1.68.0/agentwire/safety/_core.py +0 -2821
- agentwire_dev-1.68.0/agentwire/services.py +0 -325
- agentwire_dev-1.68.0/agentwire/static/js/dead-key-suppressor.js +0 -53
- agentwire_dev-1.68.0/docs/wiki/services.md +0 -74
- agentwire_dev-1.68.0/tests/unit/test_tmux_template.py +0 -73
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/.gitignore +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/AGENTS.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/LICENSE +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/README.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/RELEASING.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/SECURITY.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/chrome_tabs.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/council/minutes.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/history_migrate.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/restart_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/role_prompts.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/contributor.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/reviewer-worktree.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/reviewer.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/shared-checkout.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/safety/provenance.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scheduler/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scheduler/dispatch.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scheduler/models.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scheduler/schedule.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scheduler/zombie.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/security.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/session_ready.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/card-terminal.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/lineage.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/session-hud-notices.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/session-hud-spawn.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/spawn-ghost.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/utils/rich-text.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/js/workspace-window.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/static/topology-harness.html +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tabs_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tasks_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/council/minutes.html.j2 +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/statusline.sh +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/worktree_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/design/session-card-fields.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/design/session-card-recommendation.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/logo.png +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/auth-expired.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/internals/session-topology.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/sessions/conversation-identity.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/sessions/heal-line-count-cliff.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/sessions/helper-sessions.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/pyproject.toml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/home_guard.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_auth_expired.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_auth_expired_dispatch.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_chrome_tabs.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_control_plane_protection.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_core_created_by_rooting.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_council_minutes.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_dangling_worktrees.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_doctor_orphaned_history.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_doctor_scheduler_staleness.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_doctor_secrets_perms.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_doctor_task_migration.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_ensure_shared_dir.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_ensure_verified_prompt.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_guarded_launch_command.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_helper_session.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_history_migrate.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_history_migrate_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_history_resume_name.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_home_isolation.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_launch_line_reentry.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_launch_via_env.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_owner_only_writes.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_pending_message_visibility.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_pip_environment.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_posture_default.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_projects_registry.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_prompt_router_resume.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_remote_session_record.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_rich_text_js.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_role_prompt_retention.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_role_prompt_sweep_wiring.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_safety_heal.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_scheduler_liveness.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_scheduler_zombie.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_session_created_by_env.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_session_metadata_write.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_session_ready.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_shim_selfheal.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_task_max_duration.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_tasks_cli.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_tmux_session_cwd.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_worktree.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_worktree_branch_cleanup.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_worktree_layout.py +0 -0
- {agentwire_dev-1.68.0 → agentwire_dev-1.70.0}/tests/unit/test_worktree_registry.py +0 -0
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# is on PATH. Per the council guardrail we do NOT chase coverage % or block PRs
|
|
11
11
|
# on flaky/tmux-dependent tests.
|
|
12
12
|
#
|
|
13
|
-
#
|
|
13
|
+
# On pushes to main, coverage is measured and surfaced (term-missing in the log + a table in the
|
|
14
14
|
# run's job summary + an uploaded coverage.xml artifact) but is REPORT-ONLY:
|
|
15
15
|
# there is deliberately no --cov-fail-under, so a low percentage never reds the
|
|
16
16
|
# build. The point is visibility — letting the maintainer spot untested
|
|
@@ -37,13 +37,22 @@ jobs:
|
|
|
37
37
|
- name: Sync dependencies
|
|
38
38
|
run: uv sync --extra dev
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
# Pull requests run the FAST set: no coverage tracing (it multiplies
|
|
41
|
+
# runtime on a hosted runner) and no `slow` tests (real git/tmux
|
|
42
|
+
# processes per test). A PR gate that takes 45 minutes gets bypassed.
|
|
43
|
+
- name: Run test suite (fast set)
|
|
44
|
+
if: github.event_name == 'pull_request'
|
|
45
|
+
run: uv run --no-sync pytest -q -m "not requires_tmux and not slow"
|
|
46
|
+
|
|
47
|
+
# Pushes to main run everything hermetic, with the report-only coverage.
|
|
48
|
+
- name: Run test suite (full) + coverage
|
|
49
|
+
if: github.event_name != 'pull_request'
|
|
41
50
|
run: >
|
|
42
51
|
uv run --no-sync pytest -q -m "not requires_tmux"
|
|
43
52
|
--cov=agentwire --cov-report=term-missing --cov-report=xml
|
|
44
53
|
|
|
45
54
|
- name: Publish coverage summary (report-only)
|
|
46
|
-
if: always()
|
|
55
|
+
if: github.event_name != 'pull_request' && always()
|
|
47
56
|
run: |
|
|
48
57
|
{
|
|
49
58
|
echo '## Coverage (report-only — no threshold gate)'
|
|
@@ -54,7 +63,7 @@ jobs:
|
|
|
54
63
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
55
64
|
|
|
56
65
|
- name: Upload coverage.xml artifact
|
|
57
|
-
if: always()
|
|
66
|
+
if: github.event_name != 'pull_request' && always()
|
|
58
67
|
uses: actions/upload-artifact@v4
|
|
59
68
|
with:
|
|
60
69
|
name: coverage-xml
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: agentwire-dev
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.70.0
|
|
4
4
|
Summary: Multi-session voice web interface for AI coding agents
|
|
5
5
|
Project-URL: Homepage, https://agentwire.dev
|
|
6
6
|
Project-URL: Repository, https://github.com/dotdevdotdev/agentwire-dev
|
|
@@ -183,7 +183,7 @@ Command Categories:
|
|
|
183
183
|
# - diff: structured git diff for the mobile Review window
|
|
184
184
|
# - prompts: prompt routing (rides the limits watchdog)
|
|
185
185
|
# - msg: polite agent-to-agent inbox (rides the watchdog)
|
|
186
|
-
from . import diff_cli, limits_cli, msg_cli, pane_cli, prompts_cli, send_cli # noqa: I001 # session_cli kept on its own line below to minimize Phase 1 #495 merge conflicts
|
|
186
|
+
from . import activity_cli, alerts_cli, diff_cli, limits_cli, msg_cli, pane_cli, prompts_cli, send_cli # noqa: I001 # session_cli kept on its own line below to minimize Phase 1 #495 merge conflicts
|
|
187
187
|
from . import session_cli
|
|
188
188
|
from . import channels_cli, config_cli, portal_cli, tts_cli
|
|
189
189
|
from . import scheduler_cli, ensure_cli, tasks_cli
|
|
@@ -191,12 +191,15 @@ Command Categories:
|
|
|
191
191
|
from . import handoff_cli, hooks_cli, mcp_cli, roles_cli, tunnels_cli
|
|
192
192
|
from . import notify_cli, palette_cli, push_cli, repo_cli, system_cli, wiki_cli
|
|
193
193
|
from . import restart_cli, tabs_cli, wait_cli, worktree_cli
|
|
194
|
+
from . import buddy_cli # BETA: gated on beta.voice_layer (default off)
|
|
194
195
|
from .council import cli as council_cli
|
|
195
196
|
|
|
196
197
|
_REGISTRARS = [ # noqa: N806 # registry constant; Phase 1 of #495 appends here
|
|
197
198
|
diff_cli.register_diff_parser,
|
|
198
199
|
prompts_cli.register_prompts_parser,
|
|
199
200
|
msg_cli.register_msg_parser,
|
|
201
|
+
alerts_cli.register_alerts_parser,
|
|
202
|
+
activity_cli.register_activity_parser,
|
|
200
203
|
limits_cli.register_limits_parser,
|
|
201
204
|
pane_cli.register_pane_parser,
|
|
202
205
|
send_cli.register_send_parser,
|
|
@@ -228,6 +231,7 @@ Command Categories:
|
|
|
228
231
|
tabs_cli.register_tabs_parser,
|
|
229
232
|
wait_cli.register_wait_parser,
|
|
230
233
|
worktree_cli.register_helper_parser,
|
|
234
|
+
buddy_cli.register_buddy_parser,
|
|
231
235
|
]
|
|
232
236
|
for _reg in _REGISTRARS:
|
|
233
237
|
_reg(subparsers)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""``agentwire activity`` — what the fleet has been doing (#1016).
|
|
2
|
+
|
|
3
|
+
The read side of :mod:`~agentwire.fleet_activity`. It exists as a CLI verb for
|
|
4
|
+
two reasons, and the second is the load-bearing one:
|
|
5
|
+
|
|
6
|
+
1. "CLI is the single source of truth" — a store readable only from inside the
|
|
7
|
+
process tree that writes it is exactly the shape that rule exists to prevent.
|
|
8
|
+
2. The voice layer dispatches **only** through the CLI (see
|
|
9
|
+
``voice_layer/tools.py``), so without this verb the buddy could not read the
|
|
10
|
+
ledger that was built for it.
|
|
11
|
+
|
|
12
|
+
Read-only, by construction: nothing here writes. Producers record from inside
|
|
13
|
+
the surfaces that generate the events (idle, say, toast, scheduled run), never
|
|
14
|
+
from a verb an agent could be talked into calling.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import json
|
|
20
|
+
from datetime import timedelta
|
|
21
|
+
|
|
22
|
+
from . import fleet_activity
|
|
23
|
+
|
|
24
|
+
#: Widest window the verb will look back over. The ledger is capped at
|
|
25
|
+
#: ``MAX_ENTRIES`` anyway, so this bounds the ANSWER rather than the read: a
|
|
26
|
+
#: request for a week of awareness is a request for history, and
|
|
27
|
+
#: ``agentwire scheduler history`` / the event logs are where history lives.
|
|
28
|
+
MAX_HOURS = 72
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def cmd_activity_list(args) -> int:
|
|
32
|
+
json_mode = getattr(args, "json", False)
|
|
33
|
+
hours = max(1, min(MAX_HOURS, int(getattr(args, "hours", 12) or 12)))
|
|
34
|
+
entries = fleet_activity.recent(
|
|
35
|
+
limit=max(1, int(getattr(args, "limit", 50) or 50)),
|
|
36
|
+
event=getattr(args, "event", "") or "",
|
|
37
|
+
session=getattr(args, "session", "") or "",
|
|
38
|
+
window=timedelta(hours=hours),
|
|
39
|
+
)
|
|
40
|
+
if json_mode:
|
|
41
|
+
print(json.dumps({
|
|
42
|
+
"success": True,
|
|
43
|
+
"count": len(entries),
|
|
44
|
+
"window_hours": hours,
|
|
45
|
+
"ledger": str(fleet_activity.ledger_path()),
|
|
46
|
+
"activity": entries,
|
|
47
|
+
}, indent=2))
|
|
48
|
+
return 0
|
|
49
|
+
if not entries:
|
|
50
|
+
print(f"No fleet activity recorded in the last {hours}h.")
|
|
51
|
+
return 0
|
|
52
|
+
for entry in entries:
|
|
53
|
+
# The announced flag is shown, not hidden: "recorded" and "said out
|
|
54
|
+
# loud" are different facts, and an operator debugging a chatty or a
|
|
55
|
+
# silent buddy needs to see which one an entry was.
|
|
56
|
+
mark = "*" if entry.get("announced") else " "
|
|
57
|
+
print(f"{mark} {entry.get('ts', '')} {entry.get('event', ''):<16} "
|
|
58
|
+
f"{entry.get('text', '')}")
|
|
59
|
+
print()
|
|
60
|
+
print("* = also queued to fleet-alert subscribers (spoken by the voice buddy at a gap)")
|
|
61
|
+
return 0
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def register_activity_parser(subparsers) -> None:
|
|
65
|
+
parser = subparsers.add_parser(
|
|
66
|
+
"activity",
|
|
67
|
+
help="What the fleet has been doing (idle, tasks, toasts, speech)",
|
|
68
|
+
description=(
|
|
69
|
+
"The fleet's activity ledger: sessions going idle, scheduled tasks "
|
|
70
|
+
"finishing, toasts shown to the owner, and everything spoken aloud "
|
|
71
|
+
"through fleet TTS. This is AWARENESS — a record something can read "
|
|
72
|
+
"when asked. Only a short, ruled subset is also queued to "
|
|
73
|
+
"fleet-alert subscribers (see `agentwire alerts`); the rest waits "
|
|
74
|
+
"here to be looked up."
|
|
75
|
+
),
|
|
76
|
+
)
|
|
77
|
+
sub = parser.add_subparsers(dest="activity_command", required=True)
|
|
78
|
+
|
|
79
|
+
p = sub.add_parser("list", help="Recent activity, newest first")
|
|
80
|
+
p.add_argument("--limit", type=int, default=50, help="Max entries (default: 50)")
|
|
81
|
+
p.add_argument("--hours", type=int, default=12,
|
|
82
|
+
help=f"How far back to look (1-{MAX_HOURS}, default: 12)")
|
|
83
|
+
p.add_argument("--event", choices=fleet_activity.EVENTS, help="Only this event type")
|
|
84
|
+
p.add_argument("-s", "--session", help="Only this session (exact name)")
|
|
85
|
+
p.add_argument("--json", action="store_true", help="Output JSON")
|
|
86
|
+
p.set_defaults(func=cmd_activity_list)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""``agentwire alerts`` — who hears the machine's own detectors (#982).
|
|
2
|
+
|
|
3
|
+
Fleet detectors (expired login, usage-limit park, dead-lettered report-backs, a
|
|
4
|
+
root pane blocked with nowhere to route) have always been able to email the
|
|
5
|
+
OWNER. ``fleet_alerts`` lets them address a SESSION as typed mail instead, and
|
|
6
|
+
this is the surface that turns that on: without a CLI verb the subscription API
|
|
7
|
+
would be reachable only from inside the tree that calls it, which is precisely
|
|
8
|
+
the shape "CLI is the single source of truth" exists to prevent.
|
|
9
|
+
|
|
10
|
+
Subscription is a renewable **lease**, so ``list`` reports the expiry rather
|
|
11
|
+
than a boolean: a subscriber that stopped renewing has silently stopped
|
|
12
|
+
hearing anything, and that is a state an operator has to be able to see.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
|
|
19
|
+
from . import fleet_alerts
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _emit(payload: dict, json_mode: bool, lines: "list[str] | None" = None) -> int:
|
|
23
|
+
if json_mode:
|
|
24
|
+
print(json.dumps(payload, indent=2))
|
|
25
|
+
else:
|
|
26
|
+
for line in lines or []:
|
|
27
|
+
print(line)
|
|
28
|
+
return 0 if payload.get("success", True) else 1
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def cmd_alerts_subscribe(args) -> int:
|
|
32
|
+
json_mode = getattr(args, "json", False)
|
|
33
|
+
try:
|
|
34
|
+
lease = fleet_alerts.subscribe(args.session)
|
|
35
|
+
except Exception as exc:
|
|
36
|
+
return _emit(
|
|
37
|
+
{"success": False, "error": str(exc)}, json_mode, [f"error: {exc}"]
|
|
38
|
+
)
|
|
39
|
+
return _emit(
|
|
40
|
+
{"success": True, "session": args.session, "lease": lease},
|
|
41
|
+
json_mode,
|
|
42
|
+
[
|
|
43
|
+
f"'{args.session}' now receives fleet alerts.",
|
|
44
|
+
f" lease expires: {lease['expires_at']}",
|
|
45
|
+
" Renew before then — an expired lease goes quiet, it does not warn.",
|
|
46
|
+
],
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def cmd_alerts_unsubscribe(args) -> int:
|
|
51
|
+
json_mode = getattr(args, "json", False)
|
|
52
|
+
dropped = fleet_alerts.unsubscribe(args.session)
|
|
53
|
+
if not dropped:
|
|
54
|
+
return _emit(
|
|
55
|
+
{"success": False, "error": f"'{args.session}' was not subscribed"},
|
|
56
|
+
json_mode,
|
|
57
|
+
[f"'{args.session}' was not subscribed."],
|
|
58
|
+
)
|
|
59
|
+
return _emit(
|
|
60
|
+
{"success": True, "session": args.session},
|
|
61
|
+
json_mode,
|
|
62
|
+
[f"'{args.session}' no longer receives fleet alerts."],
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def cmd_alerts_list(args) -> int:
|
|
67
|
+
"""Who is subscribed — and whether this answer can be trusted.
|
|
68
|
+
|
|
69
|
+
``list`` reads the same candidate index the emit path does, so a lost index
|
|
70
|
+
makes both of them say "nobody". That would be the worst property this
|
|
71
|
+
command could have: the one surface built to make a silent stop VISIBLE
|
|
72
|
+
would agree with the silent stop. So the index's presence is reported
|
|
73
|
+
alongside the answer, and its absence is not rendered as a confident zero.
|
|
74
|
+
"""
|
|
75
|
+
json_mode = getattr(args, "json", False)
|
|
76
|
+
names = fleet_alerts.subscribers()
|
|
77
|
+
index_present = fleet_alerts.subscribers_index_path().exists()
|
|
78
|
+
rows = [{"session": n, "lease": fleet_alerts.subscription(n)} for n in names]
|
|
79
|
+
if names:
|
|
80
|
+
lines = [
|
|
81
|
+
"Sessions receiving fleet alerts:",
|
|
82
|
+
*(f" {r['session']} (lease expires {(r['lease'] or {}).get('expires_at')})"
|
|
83
|
+
for r in rows),
|
|
84
|
+
]
|
|
85
|
+
elif index_present:
|
|
86
|
+
lines = ["No session is subscribed to fleet alerts."]
|
|
87
|
+
else:
|
|
88
|
+
lines = [
|
|
89
|
+
"No subscriber index — so this is NOT a confident 'nobody subscribed'.",
|
|
90
|
+
"Either nobody ever subscribed, or the index was lost; from here those "
|
|
91
|
+
"look identical, and while it is missing every alert reaches nobody.",
|
|
92
|
+
"Settle it (cheap, and it rebuilds the index either way):",
|
|
93
|
+
" agentwire alerts reindex",
|
|
94
|
+
]
|
|
95
|
+
return _emit(
|
|
96
|
+
{
|
|
97
|
+
"success": True,
|
|
98
|
+
"subscribers": names,
|
|
99
|
+
"leases": rows,
|
|
100
|
+
"index_present": index_present,
|
|
101
|
+
},
|
|
102
|
+
json_mode,
|
|
103
|
+
lines,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def cmd_alerts_reindex(args) -> int:
|
|
108
|
+
"""Rebuild the candidate index from the session records.
|
|
109
|
+
|
|
110
|
+
The alert path never walks the record store — that cost sits on the
|
|
111
|
+
synchronous permission-hook path — so a lost index means fewer alerts until
|
|
112
|
+
somebody rebuilds it. This is that somebody.
|
|
113
|
+
"""
|
|
114
|
+
json_mode = getattr(args, "json", False)
|
|
115
|
+
names = fleet_alerts.reindex()
|
|
116
|
+
return _emit(
|
|
117
|
+
{"success": True, "subscribers": names},
|
|
118
|
+
json_mode,
|
|
119
|
+
[f"Reindexed: {len(names)} live subscriber(s)." , *(f" {n}" for n in names)],
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def register_alerts_parser(subparsers) -> None:
|
|
124
|
+
parser = subparsers.add_parser(
|
|
125
|
+
"alerts",
|
|
126
|
+
help="Who hears the machine's own detectors (fleet alerts)",
|
|
127
|
+
description=(
|
|
128
|
+
"Fleet detectors — expired login, usage-limit park, dead-lettered "
|
|
129
|
+
"report-backs, a root pane blocked with nowhere to route — email the "
|
|
130
|
+
"owner. They can also address a SESSION as typed mail: an escalation "
|
|
131
|
+
"for the two conditions only a human can clear, a note or a request "
|
|
132
|
+
"for the rest. A session subscribes here, on a renewable lease."
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
sub = parser.add_subparsers(dest="alerts_command", required=True)
|
|
136
|
+
|
|
137
|
+
p = sub.add_parser("subscribe", help="Lease fleet alerts for a session")
|
|
138
|
+
p.add_argument("session", help="Session name (must have a session record)")
|
|
139
|
+
p.add_argument("--json", action="store_true", help="JSON output")
|
|
140
|
+
p.set_defaults(func=cmd_alerts_subscribe)
|
|
141
|
+
|
|
142
|
+
p = sub.add_parser("unsubscribe", help="Drop a session's fleet-alert lease")
|
|
143
|
+
p.add_argument("session")
|
|
144
|
+
p.add_argument("--json", action="store_true", help="JSON output")
|
|
145
|
+
p.set_defaults(func=cmd_alerts_unsubscribe)
|
|
146
|
+
|
|
147
|
+
p = sub.add_parser("list", help="Sessions with a live lease, and its expiry")
|
|
148
|
+
p.add_argument("--json", action="store_true", help="JSON output")
|
|
149
|
+
p.set_defaults(func=cmd_alerts_list)
|
|
150
|
+
|
|
151
|
+
p = sub.add_parser("reindex", help="Rebuild the subscriber index from records")
|
|
152
|
+
p.add_argument("--json", action="store_true", help="JSON output")
|
|
153
|
+
p.set_defaults(func=cmd_alerts_reindex)
|
|
@@ -360,8 +360,10 @@ def record_outage(detail: dict, source: str = "ensure") -> dict:
|
|
|
360
360
|
"source": source,
|
|
361
361
|
"host": socket.gethostname(),
|
|
362
362
|
"escalated_at": prior.get("escalated_at"),
|
|
363
|
+
"alerted_at": prior.get("alerted_at"),
|
|
363
364
|
}
|
|
364
365
|
state["escalated_at"] = _escalate(state, prior)
|
|
366
|
+
state["alerted_at"] = _alert_fleet(state, prior)
|
|
365
367
|
write_state(state)
|
|
366
368
|
log_event("outage_detected", session=detail.get("session"),
|
|
367
369
|
transcript=detail.get("transcript"), source=source)
|
|
@@ -421,6 +423,50 @@ def _escalate(state: dict, prior: dict) -> str | None:
|
|
|
421
423
|
return previous
|
|
422
424
|
|
|
423
425
|
|
|
426
|
+
def _alert_fleet(state: dict, prior: dict) -> "str | None":
|
|
427
|
+
"""Tell subscribed sessions, on the same clock the owner email rides (#982).
|
|
428
|
+
|
|
429
|
+
Escalation kind, and this is the clearest case for it in the fleet: the
|
|
430
|
+
outage is machine-wide, every subsequent turn is refused, and nothing but a
|
|
431
|
+
human running ``/login`` can clear it. It is bounded to once per
|
|
432
|
+
:data:`ESCALATE_TTL` per outage — machine-wide, not per session and not per
|
|
433
|
+
dispatch — which is what makes an interrupt affordable here.
|
|
434
|
+
|
|
435
|
+
Stamped separately from ``escalated_at`` while sharing that field's state
|
|
436
|
+
record and its TTL. Not a parallel throttle store — the same file, the same
|
|
437
|
+
window — but a separate stamp, because the two channels fail differently:
|
|
438
|
+
the email deliberately retries per detection when the provider is down
|
|
439
|
+
(only a successful send stamps), and an alert inheriting that retry would
|
|
440
|
+
turn a broken Resend key into one interrupt per dispatch. Enqueueing is a
|
|
441
|
+
local write, so this stamp lands whenever the alert actually did.
|
|
442
|
+
"""
|
|
443
|
+
previous = prior.get("alerted_at")
|
|
444
|
+
if previous:
|
|
445
|
+
try:
|
|
446
|
+
if _now() - datetime.fromisoformat(previous) < ESCALATE_TTL:
|
|
447
|
+
return previous
|
|
448
|
+
except (TypeError, ValueError):
|
|
449
|
+
pass
|
|
450
|
+
try:
|
|
451
|
+
from . import fleet_alerts
|
|
452
|
+
|
|
453
|
+
sessions = ", ".join(state.get("sessions") or []) or "(none recorded)"
|
|
454
|
+
reached = fleet_alerts.emit_for(
|
|
455
|
+
"auth_expired",
|
|
456
|
+
f"Claude login expired on {state.get('host')} — every turn is being "
|
|
457
|
+
f"refused ({RENDERED}). Sessions hit so far: {sessions}. Scheduled "
|
|
458
|
+
f"dispatch is gated until someone runs /login; nothing recovers on "
|
|
459
|
+
f"its own. First seen {state.get('detected_at')}.",
|
|
460
|
+
)
|
|
461
|
+
except Exception as exc: # alerting is best-effort; never break the gate
|
|
462
|
+
log_event("alert_failed", error=str(exc))
|
|
463
|
+
return previous
|
|
464
|
+
if not reached:
|
|
465
|
+
return previous
|
|
466
|
+
log_event("alerted", sessions=state.get("sessions"), to=reached)
|
|
467
|
+
return _now().isoformat()
|
|
468
|
+
|
|
469
|
+
|
|
424
470
|
def check_and_flag(
|
|
425
471
|
session: str, project_path=None, since: float | None = None, source: str = "ensure"
|
|
426
472
|
) -> dict | None:
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""``agentwire.beta`` — the one implementation of the beta gate.
|
|
2
|
+
|
|
3
|
+
A beta feature ships on ``main`` and stays off until a user asks for it. The
|
|
4
|
+
flag VALUES live in :mod:`agentwire.config` (``BetaConfig``); the MECHANICS of
|
|
5
|
+
hiding gated text live here, because the same mechanism now serves two
|
|
6
|
+
model-facing surfaces and a third would otherwise grow its own copy:
|
|
7
|
+
|
|
8
|
+
- **role prompts** (markdown) — resolved in ``roles.parse_role_file``;
|
|
9
|
+
- **MCP tool descriptions** (docstrings) — resolved by :func:`gated_doc`.
|
|
10
|
+
|
|
11
|
+
Both are text a model reads and a user pays tokens for, which is the property
|
|
12
|
+
that decides what belongs behind a gate. The MCP schema was missed on the first
|
|
13
|
+
pass: ``msg_send``'s description grew ~316 characters of voice-buddy prose that
|
|
14
|
+
loaded into every agent session in every install, ungated, while the commit
|
|
15
|
+
message asserted the role prompts were the only such surface. The lesson is in
|
|
16
|
+
this module's existence — one gate, one place, and a byte-identity proof per
|
|
17
|
+
surface rather than per file.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import re
|
|
23
|
+
|
|
24
|
+
#: A gated region:
|
|
25
|
+
#:
|
|
26
|
+
#: <!-- beta:voice_layer -->
|
|
27
|
+
#: ...text that only ships when beta.voice_layer is on...
|
|
28
|
+
#: <!-- /beta:voice_layer -->
|
|
29
|
+
#:
|
|
30
|
+
#: Leading whitespace is allowed on both markers (a docstring cannot put them in
|
|
31
|
+
#: column 0) and the close tag may end the string with no trailing newline. Both
|
|
32
|
+
#: shapes previously failed OPEN — the region simply did not match, and its text
|
|
33
|
+
#: shipped ungated, which is the one failure direction a gate may not have.
|
|
34
|
+
#:
|
|
35
|
+
#: The backreference means open and close must name the SAME flag, so a mistyped
|
|
36
|
+
#: close tag matches nothing. That case still fails open — it cannot be resolved
|
|
37
|
+
#: without guessing where the region ends — and is caught instead by the audit
|
|
38
|
+
#: in ``tests/unit/test_beta_flag.py``, which asserts no marker-shaped text
|
|
39
|
+
#: survives :func:`apply_beta_blocks` in any shipped role file.
|
|
40
|
+
BETA_BLOCK_RE = re.compile(
|
|
41
|
+
r"^[ \t]*<!-- beta:([a-z0-9_]+) -->[ \t]*\n(.*?)^[ \t]*<!-- /beta:\1 -->[ \t]*(?:\n|\Z)",
|
|
42
|
+
re.MULTILINE | re.DOTALL,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
#: Anything marker-SHAPED, paired or not. The audit's instrument: what
|
|
46
|
+
#: :data:`BETA_BLOCK_RE` leaves behind is exactly the set of broken markers.
|
|
47
|
+
LOOSE_MARKER_RE = re.compile(r"<!--\s*/?\s*beta:[^>]*-->")
|
|
48
|
+
|
|
49
|
+
#: A stray marker on its own line, removed at render time only — see
|
|
50
|
+
#: :func:`render` for why that is deliberately NOT done in
|
|
51
|
+
#: :func:`apply_beta_blocks`.
|
|
52
|
+
_STRAY_MARKER_LINE_RE = re.compile(
|
|
53
|
+
r"^[ \t]*<!--\s*/?\s*beta:[^>]*-->[ \t]*(?:\n|\Z)", re.MULTILINE
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
_CACHE: "set[str] | None" = None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def flag_names() -> frozenset[str]:
|
|
60
|
+
"""The flags a marker may legally name. Owned by :mod:`agentwire.config`."""
|
|
61
|
+
from .config import BETA_FLAG_NAMES
|
|
62
|
+
|
|
63
|
+
return BETA_FLAG_NAMES
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def enabled_flags() -> set[str]:
|
|
67
|
+
"""Which beta features are on, cached for the life of the process.
|
|
68
|
+
|
|
69
|
+
Cached because the gate sits on a hot path: ``parse_role_file`` runs once
|
|
70
|
+
per role per session launch, and an uncached read cost a full
|
|
71
|
+
``load_config`` — with its stderr INFO line — each time, taking ``roles
|
|
72
|
+
list`` from 11ms to 242ms and printing 24 log lines, for a feature almost
|
|
73
|
+
nobody has enabled.
|
|
74
|
+
|
|
75
|
+
The consequence is stated rather than hidden: a long-lived process
|
|
76
|
+
observes the flag state it started with, so turning a beta feature on takes
|
|
77
|
+
the restart that ``config.yaml`` changes already take. An import-time
|
|
78
|
+
surface like an MCP tool description is process-lifetime by construction
|
|
79
|
+
anyway. :func:`reset_cache` exists for tests.
|
|
80
|
+
|
|
81
|
+
**The precondition that makes the ON direction safe, written down because
|
|
82
|
+
it is not visible from here.** A cached ``{"voice_layer"}`` outlives a
|
|
83
|
+
config that has since said off — verified: gated prose keeps rendering
|
|
84
|
+
until :func:`reset_cache`. That is unreachable today only because every
|
|
85
|
+
in-process caller of ``load_roles``/``parse_role_file`` is a short-lived
|
|
86
|
+
CLI module, and the surfaces that look long-lived are not: ``role show``
|
|
87
|
+
and ``roles list`` shell out through ``run_agentwire_cmd``, so each render
|
|
88
|
+
happens in a fresh process that re-reads the flag.
|
|
89
|
+
|
|
90
|
+
**A long-lived in-process caller would violate that**, and would do it
|
|
91
|
+
silently — the gate would keep a feature ON for a user who turned it off,
|
|
92
|
+
with no error anywhere. If you add one (a portal route rendering role text
|
|
93
|
+
in-process, a daemon calling ``parse_role_file``), either call
|
|
94
|
+
:func:`reset_cache` at the top of each request or give that caller an
|
|
95
|
+
explicit ``enabled`` set. Do not discover this precondition by tripping it.
|
|
96
|
+
"""
|
|
97
|
+
global _CACHE
|
|
98
|
+
if _CACHE is None:
|
|
99
|
+
from .config import enabled_beta_flags
|
|
100
|
+
|
|
101
|
+
_CACHE = enabled_beta_flags()
|
|
102
|
+
return _CACHE
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def reset_cache() -> None:
|
|
106
|
+
"""Drop the cached flag set (tests; a process that rewrote its own config)."""
|
|
107
|
+
global _CACHE
|
|
108
|
+
_CACHE = None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def apply_beta_blocks(text: str, enabled: set[str]) -> str:
|
|
112
|
+
"""Resolve every PAIRED gated region in *text*.
|
|
113
|
+
|
|
114
|
+
Enabled flag → the body ships, with the marker lines removed (they are
|
|
115
|
+
scaffolding, and shipping them would cost the tokens the gate exists to
|
|
116
|
+
save). Disabled — or a flag name nothing knows about — → the whole region
|
|
117
|
+
goes, markers included.
|
|
118
|
+
|
|
119
|
+
**An unknown flag fails CLOSED**, and that direction is chosen rather than
|
|
120
|
+
inherited: text no gate can turn off is precisely the failure this module
|
|
121
|
+
exists to prevent. What makes it safe rather than silent is the paired
|
|
122
|
+
audit — a test fails on any marker naming a flag ``config.BETA_FLAG_NAMES``
|
|
123
|
+
does not know, so a typo is caught before it can delete a section forever.
|
|
124
|
+
|
|
125
|
+
Deliberately does NOT remove unpaired markers: this function's output is
|
|
126
|
+
what the audit measures, and swallowing broken markers here would make that
|
|
127
|
+
audit unable to fail. :func:`render` does that, at the edge.
|
|
128
|
+
"""
|
|
129
|
+
known = flag_names()
|
|
130
|
+
|
|
131
|
+
def _resolve(match: "re.Match") -> str:
|
|
132
|
+
flag, body = match.group(1), match.group(2)
|
|
133
|
+
return body if (flag in known and flag in enabled) else ""
|
|
134
|
+
|
|
135
|
+
return BETA_BLOCK_RE.sub(_resolve, text)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def render(text: str, enabled: "set[str] | None" = None) -> str:
|
|
139
|
+
"""Resolve gated regions for text about to reach a model.
|
|
140
|
+
|
|
141
|
+
:func:`apply_beta_blocks`, then strip any marker line left over. That second
|
|
142
|
+
step fixes only the smaller half of a broken marker: the region it was meant
|
|
143
|
+
to wrap is still ungated (the audit is what catches that), but the
|
|
144
|
+
scaffolding itself never reaches the model as prose.
|
|
145
|
+
"""
|
|
146
|
+
# Text with no marker cannot change, so it must not pay for the flag
|
|
147
|
+
# lookup — that is 20 of the 24 shipped role files and 107 of the 108 MCP
|
|
148
|
+
# tool descriptions, several of which resolve at IMPORT time. Cheap
|
|
149
|
+
# substring scan, and it keys on the same literal the regexes do.
|
|
150
|
+
if enabled is None:
|
|
151
|
+
if "beta:" not in text:
|
|
152
|
+
return text
|
|
153
|
+
enabled = enabled_flags()
|
|
154
|
+
return _STRAY_MARKER_LINE_RE.sub("", apply_beta_blocks(text, enabled))
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def gated_doc(fn):
|
|
158
|
+
"""Resolve gated regions in a function's docstring, in place.
|
|
159
|
+
|
|
160
|
+
For MCP tools, apply it BELOW ``@mcp.tool()`` so FastMCP reads the resolved
|
|
161
|
+
text::
|
|
162
|
+
|
|
163
|
+
@mcp.tool()
|
|
164
|
+
@gated_doc
|
|
165
|
+
def msg_send(...):
|
|
166
|
+
\"\"\"...\"\"\"
|
|
167
|
+
|
|
168
|
+
Decorators apply bottom-up, so the docstring is already resolved by the time
|
|
169
|
+
the tool is registered — and FastMCP snapshots the docstring AT
|
|
170
|
+
registration, publishing it as the tool description, which is what makes
|
|
171
|
+
this the whole fix.
|
|
172
|
+
|
|
173
|
+
**Inverting the two silently un-gates the tool**, measured rather than
|
|
174
|
+
feared: with ``@gated_doc`` above ``@mcp.tool()`` the raw text publishes,
|
|
175
|
+
markers and all (2165 chars vs 1800). Nothing about the wrong order looks
|
|
176
|
+
wrong, so the property is pinned over the WHOLE registry —
|
|
177
|
+
``test_no_published_description_carries_a_marker`` fails on any published
|
|
178
|
+
description containing a marker, whatever put it there.
|
|
179
|
+
|
|
180
|
+
The resolution happens ONCE, at import, against whatever flag state the
|
|
181
|
+
process started with — so any later reader that wants to verify the
|
|
182
|
+
resolved text needs to know which flags it was resolved WITH, not which
|
|
183
|
+
flags are on now. ``__beta_enabled__`` records exactly that (and
|
|
184
|
+
``__beta_raw_doc__`` the pre-resolution text), which is what lets the
|
|
185
|
+
byte-identity tests hold on a machine with a beta flag enabled instead of
|
|
186
|
+
silently asserting the developer's personal config (#1023).
|
|
187
|
+
"""
|
|
188
|
+
if fn.__doc__ and "beta:" in fn.__doc__:
|
|
189
|
+
enabled = enabled_flags()
|
|
190
|
+
fn.__beta_raw_doc__ = fn.__doc__
|
|
191
|
+
fn.__beta_enabled__ = frozenset(enabled)
|
|
192
|
+
fn.__doc__ = render(fn.__doc__, enabled=enabled)
|
|
193
|
+
return fn
|