agentwire-dev 1.66.0__tar.gz → 1.68.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.66.0 → agentwire_dev-1.68.0}/.github/workflows/security.yml +73 -1
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/PKG-INFO +2 -2
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/__main__.py +3 -2
- agentwire_dev-1.68.0/agentwire/auth_expired.py +447 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/completion.py +76 -5
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/core.py +592 -64
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/doctor_cli.py +701 -30
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/ensure_cli.py +157 -8
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/history.py +220 -12
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/history_cli.py +155 -1
- agentwire_dev-1.68.0/agentwire/history_migrate.py +463 -0
- agentwire_dev-1.68.0/agentwire/hooks/damage-control/bash-tool-damage-control.py +3009 -0
- agentwire_dev-1.68.0/agentwire/hooks/damage-control/edit-tool-damage-control.py +2910 -0
- agentwire_dev-1.68.0/agentwire/hooks/damage-control/mcp-tool-damage-control.py +3045 -0
- agentwire_dev-1.68.0/agentwire/hooks/damage-control/read-tool-damage-control.py +2925 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +7 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/aws.yaml +13 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +27 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/containers.yaml +10 -3
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/core.yaml +19 -7
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/databases.yaml +27 -55
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/firebase.yaml +5 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/gcp.yaml +9 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/gws.yaml +7 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +10 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/outbound.yaml +7 -0
- agentwire_dev-1.68.0/agentwire/hooks/damage-control/rules/payloads.yaml +118 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/publish.yaml +6 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/remote.yaml +30 -0
- agentwire_dev-1.68.0/agentwire/hooks/damage-control/write-tool-damage-control.py +2909 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks_cli.py +60 -7
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/inbox.py +80 -11
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/limits_cli.py +18 -1
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/machine_cli.py +8 -8
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_task.py +5 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/onboarding.py +8 -1
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/pane_cli.py +24 -9
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/prompt_router.py +382 -61
- agentwire_dev-1.68.0/agentwire/restart_cli.py +276 -0
- agentwire_dev-1.68.0/agentwire/role_prompts.py +301 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/scheduler.py +34 -20
- agentwire_dev-1.68.0/agentwire/safety/_core.py +2821 -0
- agentwire_dev-1.68.0/agentwire/safety/lint.py +252 -0
- agentwire_dev-1.68.0/agentwire/safety/provenance.py +205 -0
- agentwire_dev-1.68.0/agentwire/safety/rule_baselines.json +116 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/safety_cli.py +18 -2
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/safety_commands.py +395 -54
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/__init__.py +1 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/dispatch.py +59 -2
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/models.py +3 -1
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/report.py +83 -1
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/zombie.py +1 -1
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler_cli.py +62 -6
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/security.py +8 -22
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/session_cli.py +64 -23
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/system_cli.py +25 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tasks.py +58 -5
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tasks_cli.py +55 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/tmux.conf +12 -3
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/worktree.py +22 -6
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/INDEX.md +3 -0
- agentwire_dev-1.68.0/docs/wiki/auth-expired.md +210 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/damage-control.md +424 -10
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/scheduling/scheduled-workloads.md +145 -1
- agentwire_dev-1.68.0/docs/wiki/security/pip-audit.md +158 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/security/secrets.md +36 -0
- agentwire_dev-1.68.0/docs/wiki/sessions/conversation-identity.md +532 -0
- agentwire_dev-1.68.0/docs/wiki/sessions/heal-line-count-cliff.md +166 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/messaging.md +37 -10
- agentwire_dev-1.68.0/docs/wiki/sessions/prompt-routing.md +290 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/pyproject.toml +9 -1
- agentwire_dev-1.68.0/tests/conftest.py +371 -0
- agentwire_dev-1.68.0/tests/home_guard.py +133 -0
- agentwire_dev-1.68.0/tests/integration/test_tmux_name_rewrite.py +174 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/integration/test_worktree_cmd.py +122 -12
- agentwire_dev-1.68.0/tests/unit/test_auth_expired.py +417 -0
- agentwire_dev-1.68.0/tests/unit/test_auth_expired_dispatch.py +310 -0
- agentwire_dev-1.68.0/tests/unit/test_build_agent_command.py +380 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_cli_commands.py +7 -9
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_control_plane_protection.py +8 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_damage_control_bypass.py +10 -0
- agentwire_dev-1.68.0/tests/unit/test_damage_control_hooks.py +1867 -0
- agentwire_dev-1.68.0/tests/unit/test_damage_control_payload_anchoring.py +1354 -0
- agentwire_dev-1.68.0/tests/unit/test_doctor_orphaned_history.py +168 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_doctor_scheduler_staleness.py +58 -15
- agentwire_dev-1.68.0/tests/unit/test_doctor_secrets_perms.py +128 -0
- agentwire_dev-1.68.0/tests/unit/test_ensure_verified_prompt.py +155 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_guarded_launch_command.py +12 -2
- agentwire_dev-1.68.0/tests/unit/test_history.py +179 -0
- agentwire_dev-1.68.0/tests/unit/test_history_migrate.py +476 -0
- agentwire_dev-1.68.0/tests/unit/test_history_migrate_cli.py +134 -0
- agentwire_dev-1.68.0/tests/unit/test_history_resume_name.py +126 -0
- agentwire_dev-1.68.0/tests/unit/test_home_isolation.py +364 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_hooks_install.py +10 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_inbox.py +101 -4
- agentwire_dev-1.68.0/tests/unit/test_launch_line_reentry.py +355 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_locking.py +4 -4
- agentwire_dev-1.68.0/tests/unit/test_owner_only_writes.py +102 -0
- agentwire_dev-1.68.0/tests/unit/test_pending_message_visibility.py +149 -0
- agentwire_dev-1.68.0/tests/unit/test_pip_audit_report.py +580 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_prompt_router.py +30 -7
- agentwire_dev-1.68.0/tests/unit/test_prompt_router_resume.py +701 -0
- agentwire_dev-1.68.0/tests/unit/test_remote_session_record.py +97 -0
- agentwire_dev-1.68.0/tests/unit/test_restart_cli.py +373 -0
- agentwire_dev-1.68.0/tests/unit/test_role_prompt_retention.py +286 -0
- agentwire_dev-1.68.0/tests/unit/test_role_prompt_sweep_wiring.py +198 -0
- agentwire_dev-1.68.0/tests/unit/test_safety_deployment.py +842 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_safety_heal.py +9 -0
- agentwire_dev-1.68.0/tests/unit/test_scheduler_liveness.py +351 -0
- agentwire_dev-1.68.0/tests/unit/test_session_metadata_ssot.py +190 -0
- agentwire_dev-1.68.0/tests/unit/test_session_metadata_write.py +157 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_skill_install.py +12 -2
- agentwire_dev-1.68.0/tests/unit/test_task_max_duration.py +171 -0
- agentwire_dev-1.68.0/tests/unit/test_tmux_session_cwd.py +126 -0
- agentwire_dev-1.68.0/tests/unit/test_unattended_scoped_allow.py +732 -0
- agentwire_dev-1.68.0/tests/unit/test_worktree_dot_project.py +146 -0
- agentwire_dev-1.66.0/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -1605
- agentwire_dev-1.66.0/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -1515
- agentwire_dev-1.66.0/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -1642
- agentwire_dev-1.66.0/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -1530
- agentwire_dev-1.66.0/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -1514
- agentwire_dev-1.66.0/agentwire/safety/_core.py +0 -1429
- agentwire_dev-1.66.0/docs/wiki/security/pip-audit.md +0 -60
- agentwire_dev-1.66.0/docs/wiki/sessions/prompt-routing.md +0 -156
- agentwire_dev-1.66.0/tests/conftest.py +0 -149
- agentwire_dev-1.66.0/tests/unit/test_build_agent_command.py +0 -163
- agentwire_dev-1.66.0/tests/unit/test_damage_control_hooks.py +0 -806
- agentwire_dev-1.66.0/tests/unit/test_history.py +0 -34
- agentwire_dev-1.66.0/tests/unit/test_worktree_dot_project.py +0 -84
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.gitignore +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/AGENTS.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/LICENSE +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/README.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/RELEASING.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/SECURITY.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/chrome_tabs.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/cohort.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/config.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/minutes.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_chrome.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_core.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_council.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_msg.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_session.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_worktree.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/msg_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/notify_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/contributor.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/reviewer-worktree.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/reviewer.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/shared-checkout.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/worker-worktree.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/desktop.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/schedule.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/server.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/session_ready.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/css/desktop.css +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/card-terminal.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/desktop.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/lineage.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-hud-controller.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-hud-notices.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-hud-spawn.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-hud.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/spawn-ghost.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/terminal-pane.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/topology-render.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/utils/rich-text.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/workspace-window.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/topology-harness.html +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tabs_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/council/minutes.html.j2 +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/statusline.sh +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/wait_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/worktree_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/design/session-card-fields.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/design/session-card-recommendation.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/logo.png +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/session-topology.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/fan-out-cohorts.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/helper-sessions.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/integration/test_send_verified_tmux.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_chrome_tabs.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_cohort.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_core_created_by_rooting.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_council_minutes.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_dangling_worktrees.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_doctor_task_migration.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_ensure_shared_dir.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_helper_session.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_launch_via_env.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_msg_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_notify_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_pip_environment.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_posture_default.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_projects_registry.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_rich_text_js.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_scheduler_zombie.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_session_created_by_env.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_session_ready.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_shim_selfheal.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tasks_cli.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_window_cycling_binding.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_worktree.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_worktree_branch_cleanup.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_worktree_git_truth.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_worktree_layout.py +0 -0
- {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_worktree_registry.py +0 -0
|
@@ -66,6 +66,16 @@ jobs:
|
|
|
66
66
|
# deps are bumped explicitly in pyproject; transitive fixes land via lock
|
|
67
67
|
# bumps. See docs/wiki/security/pip-audit.md for the residual-CVE rationale.
|
|
68
68
|
continue-on-error: true
|
|
69
|
+
# The weekly cron opens/updates the tracking issue, which the DEFAULT token
|
|
70
|
+
# does not necessarily allow — a repo set to read-only default permissions
|
|
71
|
+
# would fail the `gh issue` call. Declared explicitly so the durable half of
|
|
72
|
+
# the visibility fix can't silently no-op. (No `pull-requests: write`: this
|
|
73
|
+
# deliberately does not comment on PRs — a fork PR gets a read-only token,
|
|
74
|
+
# so that flow would silently fail for exactly the external contributors it
|
|
75
|
+
# would exist to serve.)
|
|
76
|
+
permissions:
|
|
77
|
+
contents: read
|
|
78
|
+
issues: write
|
|
69
79
|
steps:
|
|
70
80
|
- uses: actions/checkout@v4
|
|
71
81
|
- name: Install uv
|
|
@@ -85,14 +95,42 @@ jobs:
|
|
|
85
95
|
# HTTP request-handling CVEs are not on a reachable path. Documented +
|
|
86
96
|
# ignored here so the advisory signal stays meaningful; revisit when mcp /
|
|
87
97
|
# chatterbox-tts relax the ceiling. See docs/wiki/security/pip-audit.md.
|
|
98
|
+
# PYSEC-2026-3483 is the deprecated WebSocket SERVER transport
|
|
99
|
+
# (mcp.server.websocket) missing Host/Origin validation. agentwire runs
|
|
100
|
+
# its MCP server on stdio (mcp_server.py: mcp.run(transport="stdio")) and
|
|
101
|
+
# never imports that module, so it is not on a reachable path. Its fix
|
|
102
|
+
# needs mcp>=1.28.1, which pulls pydantic 2.13 and cascades the tts
|
|
103
|
+
# extra's whole chain (torch 2.6 -> 2.13 plus the CUDA stack, 32 packages)
|
|
104
|
+
# — a bad trade against an unreachable advisory. 1.27.2 clears the other
|
|
105
|
+
# two mcp advisories at a one-package diff. Revisit when the torch bump is
|
|
106
|
+
# wanted on its own merits. See docs/wiki/security/pip-audit.md.
|
|
88
107
|
- name: Audit runtime dependencies
|
|
108
|
+
id: audit
|
|
109
|
+
continue-on-error: true
|
|
89
110
|
run: >
|
|
90
111
|
uvx pip-audit==2.10.1 -r requirements.txt
|
|
112
|
+
--format json --output audit-runtime.json
|
|
91
113
|
--ignore-vuln PYSEC-2026-161
|
|
92
114
|
--ignore-vuln CVE-2026-48818
|
|
93
115
|
--ignore-vuln CVE-2026-48817
|
|
94
116
|
--ignore-vuln CVE-2026-54283
|
|
95
117
|
--ignore-vuln CVE-2026-54282
|
|
118
|
+
--ignore-vuln PYSEC-2026-3483
|
|
119
|
+
# The job stays advisory (continue-on-error above), but its RESULT is no
|
|
120
|
+
# longer invisible: this prints ::warning:: annotations, which GitHub
|
|
121
|
+
# renders on the run and PR checks views without anyone opening the job
|
|
122
|
+
# log, and writes a table to the step summary. `if: always()` so a
|
|
123
|
+
# crashed audit reports "UNKNOWN, which is not clean" rather than nothing
|
|
124
|
+
# — the exact shape of #900, where a red audit rendered as green.
|
|
125
|
+
# --min-packages is a coverage floor, not a version assertion: zero
|
|
126
|
+
# advisories over zero packages is not a clean bill of health. The
|
|
127
|
+
# runtime export is ~124 packages, so anything under 50 means the export
|
|
128
|
+
# produced nothing to audit and the run is reported UNKNOWN, not clean.
|
|
129
|
+
- name: Report advisories (never blocks)
|
|
130
|
+
if: always()
|
|
131
|
+
run: >
|
|
132
|
+
uv run --no-project python scripts/pip_audit_report.py
|
|
133
|
+
audit-runtime.json --scope runtime --min-packages 50
|
|
96
134
|
# Full audit including optional extras (tts/stt: torch, onnxruntime,
|
|
97
135
|
# gradio, ...). Weekly only and never ignore-filtered — surfaces the full
|
|
98
136
|
# backlog for review without blocking or spamming every PR.
|
|
@@ -101,4 +139,38 @@ jobs:
|
|
|
101
139
|
run: uv export --no-emit-project --all-extras --format requirements-txt -o requirements-all.txt
|
|
102
140
|
- name: Full audit (weekly cron, optional extras)
|
|
103
141
|
if: github.event_name == 'schedule'
|
|
104
|
-
|
|
142
|
+
continue-on-error: true
|
|
143
|
+
run: >
|
|
144
|
+
uvx pip-audit==2.10.1 -r requirements-all.txt
|
|
145
|
+
--format json --output audit-all.json
|
|
146
|
+
- name: Report full audit + open/update the tracking issue
|
|
147
|
+
if: always() && github.event_name == 'schedule'
|
|
148
|
+
env:
|
|
149
|
+
GH_TOKEN: ${{ github.token }}
|
|
150
|
+
AUDIT_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
151
|
+
run: |
|
|
152
|
+
uv run --no-project python scripts/pip_audit_report.py audit-all.json \
|
|
153
|
+
--scope "all extras" --min-packages 100 --issue-body issue-body.md
|
|
154
|
+
# ONE issue, reused. Annotations and summaries belong to a run nobody
|
|
155
|
+
# revisits; an issue is what actually stops advisories accumulating
|
|
156
|
+
# unseen — which is how #900 reached eight.
|
|
157
|
+
title='pip-audit: unresolved advisories in the dependency lock'
|
|
158
|
+
# --state all, NOT --state open: an open-only search cannot see the
|
|
159
|
+
# issue this workflow closed last week, so a recurrence would file a
|
|
160
|
+
# SECOND issue and the "one issue, reused" promise would quietly
|
|
161
|
+
# become "one per close/recur cycle".
|
|
162
|
+
existing=$(gh issue list --state all --search "$title in:title" \
|
|
163
|
+
--json number,state --jq '.[0] | "\(.number) \(.state)"' || true)
|
|
164
|
+
number=${existing%% *}
|
|
165
|
+
state=${existing##* }
|
|
166
|
+
if grep -q ': clean' issue-body.md; then
|
|
167
|
+
if [ -n "$number" ] && [ "$state" = "OPEN" ]; then
|
|
168
|
+
gh issue comment "$number" --body-file issue-body.md
|
|
169
|
+
gh issue close "$number" --comment "pip-audit is clean; closing. This issue is reopened automatically if findings return."
|
|
170
|
+
fi
|
|
171
|
+
elif [ -z "$number" ]; then
|
|
172
|
+
gh issue create --title "$title" --label "area:security" --body-file issue-body.md
|
|
173
|
+
else
|
|
174
|
+
[ "$state" = "CLOSED" ] && gh issue reopen "$number"
|
|
175
|
+
gh issue comment "$number" --body-file issue-body.md
|
|
176
|
+
fi
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentwire-dev
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.68.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
|
|
@@ -231,7 +231,7 @@ Requires-Dist: fastapi>=0.104.0
|
|
|
231
231
|
Requires-Dist: jinja2>=3.1.0
|
|
232
232
|
Requires-Dist: kokoro-onnx>=0.4.9; python_version < '3.14'
|
|
233
233
|
Requires-Dist: markdown>=3.5
|
|
234
|
-
Requires-Dist: mcp
|
|
234
|
+
Requires-Dist: mcp<2,>=1.2.0
|
|
235
235
|
Requires-Dist: pydantic>=2.0.0
|
|
236
236
|
Requires-Dist: python-dotenv>=1.2.2
|
|
237
237
|
Requires-Dist: python-multipart>=0.0.6
|
|
@@ -37,7 +37,6 @@ from .core import ( # noqa: E402,F401 # E402: must follow load_dotenv(); F401:
|
|
|
37
37
|
_parse_session_target,
|
|
38
38
|
_portal_auth_headers,
|
|
39
39
|
_post_desktop_notification,
|
|
40
|
-
_record_session_creator,
|
|
41
40
|
_resolve_posture_from_args,
|
|
42
41
|
_run_remote,
|
|
43
42
|
_set_session_name_env,
|
|
@@ -58,6 +57,7 @@ from .core import ( # noqa: E402,F401 # E402: must follow load_dotenv(); F401:
|
|
|
58
57
|
load_config,
|
|
59
58
|
load_session_metadata,
|
|
60
59
|
parse_env_args,
|
|
60
|
+
record_session_launch,
|
|
61
61
|
store_session_metadata,
|
|
62
62
|
tmux_session_exists,
|
|
63
63
|
tmux_session_has_agent,
|
|
@@ -190,7 +190,7 @@ Command Categories:
|
|
|
190
190
|
from . import doctor_cli, history_cli, machine_cli, safety_cli
|
|
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
|
-
from . import tabs_cli, wait_cli, worktree_cli
|
|
193
|
+
from . import restart_cli, tabs_cli, wait_cli, worktree_cli
|
|
194
194
|
from .council import cli as council_cli
|
|
195
195
|
|
|
196
196
|
_REGISTRARS = [ # noqa: N806 # registry constant; Phase 1 of #495 appends here
|
|
@@ -201,6 +201,7 @@ Command Categories:
|
|
|
201
201
|
pane_cli.register_pane_parser,
|
|
202
202
|
send_cli.register_send_parser,
|
|
203
203
|
session_cli.register_session_parser,
|
|
204
|
+
restart_cli.register_restart_parser,
|
|
204
205
|
portal_cli.register_portal_parser,
|
|
205
206
|
tts_cli.register_tts_parser,
|
|
206
207
|
channels_cli.register_channels_parser,
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
"""Detect an expired Claude login and stop dispatching into it (#906).
|
|
2
|
+
|
|
3
|
+
The failure this exists for, measured on 2026-08-04 (#867): a scheduled
|
|
4
|
+
dispatch did everything right — session created, agent launched, a 20,433-byte
|
|
5
|
+
prompt submitted at ``08:00:20.785Z`` — and the turn was rejected 15 ms later:
|
|
6
|
+
|
|
7
|
+
.. code-block:: json
|
|
8
|
+
|
|
9
|
+
{"model": "<synthetic>",
|
|
10
|
+
"content": [{"type": "text", "text": "Login expired · Please run /login"}],
|
|
11
|
+
"usage": {"input_tokens": 0, "output_tokens": 0},
|
|
12
|
+
"error": "authentication_failed", "isApiErrorMessage": true}
|
|
13
|
+
|
|
14
|
+
Zero tokens, no model call, ``turn_duration: 16ms``, transcript ends. Nothing
|
|
15
|
+
noticed. ``memory-manager`` then sat until its ceiling and reported
|
|
16
|
+
``incomplete — Timeout waiting for task completion``, which describes the
|
|
17
|
+
symptom and actively misleads about the cause; ``ai-morning-briefing`` hit the
|
|
18
|
+
same outage four hours later and burned the scheduler's full 14400s. Six hours
|
|
19
|
+
of dispatch time, and three investigation passes chasing a guardrail, a
|
|
20
|
+
dispatcher, a timeout and a paste race.
|
|
21
|
+
|
|
22
|
+
**The transcript is the detector, and the pane deliberately is not.** Claude
|
|
23
|
+
Code renders the phrase inline as an ordinary assistant message, so it also
|
|
24
|
+
appears in any pane that merely *quotes* or reviews the incident — the pane
|
|
25
|
+
investigating #867 had "Login expired · Please run /login" on screen all day.
|
|
26
|
+
A pane-text rule would buy that false-positive class, and a false positive
|
|
27
|
+
here **halts scheduling**, which is strictly worse than the hang it replaces.
|
|
28
|
+
The transcript's ``error`` field is a structured fact about a turn that
|
|
29
|
+
actually happened, so that is what is keyed on. This is the opposite trade
|
|
30
|
+
from :mod:`usage_limit`, and for a concrete reason: the usage-limit signal is
|
|
31
|
+
a *live select-menu* that can be proven live (nothing renders after it), and
|
|
32
|
+
this one cannot.
|
|
33
|
+
|
|
34
|
+
Recovery is a property of the same signal, not a separate mechanism: only the
|
|
35
|
+
**last** assistant turn in a transcript decides, so a session that auth-failed
|
|
36
|
+
and then took a real turn reads as healthy with nothing to reset.
|
|
37
|
+
|
|
38
|
+
The machine-wide part matters as much as the detection. An expired login is
|
|
39
|
+
not per-task — every subsequent dispatch hits it — so one detection records a
|
|
40
|
+
single outage state, emails the owner ONCE (throttled, following the
|
|
41
|
+
dead-letter and #905 no-parent escalation precedents rather than inventing a
|
|
42
|
+
third channel), and later dispatches fail fast instead of each burning its own
|
|
43
|
+
timeout. The state carries :data:`OUTAGE_TTL` so it cannot wedge the scheduler
|
|
44
|
+
indefinitely: after it, one dispatch is let through as a probe, which now
|
|
45
|
+
fails in seconds rather than hours.
|
|
46
|
+
|
|
47
|
+
On a pre-flight credential check (#906 item 3): there is no cheap, reliable
|
|
48
|
+
local signal to gate on. Claude Code keeps credentials in the macOS Keychain,
|
|
49
|
+
where reading them needs ``security find-generic-password -w`` — an
|
|
50
|
+
interactive authorization prompt, which unattended is a worse hang than the
|
|
51
|
+
bug. Where a plaintext ``~/.claude/.credentials.json`` does exist, its
|
|
52
|
+
``expiresAt`` is the *access* token's, which lapses routinely and is refreshed
|
|
53
|
+
silently; gating dispatch on it would false-alarm constantly. The outage state
|
|
54
|
+
below IS the cheap pre-flight — a single local file read, no network — it just
|
|
55
|
+
costs one detection to arm.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
from __future__ import annotations
|
|
59
|
+
|
|
60
|
+
import json
|
|
61
|
+
import os
|
|
62
|
+
import socket
|
|
63
|
+
from datetime import datetime, timedelta, timezone
|
|
64
|
+
from pathlib import Path
|
|
65
|
+
|
|
66
|
+
# The transcript's structured error value for an expired/refused login. Keyed
|
|
67
|
+
# on exactly this — never widened to "any api error", because a rate-limit or
|
|
68
|
+
# an overloaded upstream is transient and retryable, while this one provably
|
|
69
|
+
# cannot succeed until a human runs `/login`.
|
|
70
|
+
AUTH_ERROR = "authentication_failed"
|
|
71
|
+
|
|
72
|
+
# What Claude Code renders for it. Used only to quote the operator a
|
|
73
|
+
# recognizable line in the email/summary — never as a detection signal (see
|
|
74
|
+
# the module docstring).
|
|
75
|
+
RENDERED = "Login expired · Please run /login"
|
|
76
|
+
|
|
77
|
+
# How far back into a transcript to read. A hung run's file is a few KB; a
|
|
78
|
+
# long interactive one is megabytes, and only its tail can be the last turn.
|
|
79
|
+
TAIL_BYTES = 256 * 1024
|
|
80
|
+
|
|
81
|
+
# How long a recorded outage keeps gating dispatch before one probe is allowed
|
|
82
|
+
# through. Bounded on purpose: a stale flag that never cleared would halt every
|
|
83
|
+
# scheduled task on the machine, which is a worse failure than the hang. Each
|
|
84
|
+
# fresh detection refreshes it, so a real outage keeps gating; a resolved one
|
|
85
|
+
# costs at most one fast failure to notice.
|
|
86
|
+
OUTAGE_TTL = timedelta(minutes=30)
|
|
87
|
+
|
|
88
|
+
# Owner-escalation throttle. Follows prompt_router's no-parent escalation
|
|
89
|
+
# (#905) and the dead-letter digest: an out-of-band email, sent on the first
|
|
90
|
+
# sighting and then at most once an hour while the outage persists. Unthrottled
|
|
91
|
+
# this would be one email per dispatch per outage.
|
|
92
|
+
ESCALATE_TTL = timedelta(hours=1)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _config_dir() -> Path:
|
|
96
|
+
"""Read through the MODULE, not a from-import (#902).
|
|
97
|
+
|
|
98
|
+
``from .core import CONFIG_DIR`` binds the value at import time, so a test
|
|
99
|
+
(or anything else) that patches ``core.CONFIG_DIR`` is silently ignored and
|
|
100
|
+
the code writes to the real ``~/.agentwire``. That is the same trap
|
|
101
|
+
``core.role_prompts_dir()`` exists to avoid, and here it would mean a test
|
|
102
|
+
suite scribbling a real outage gate onto the operator's machine.
|
|
103
|
+
"""
|
|
104
|
+
from . import core
|
|
105
|
+
|
|
106
|
+
return Path(core.CONFIG_DIR)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def state_path() -> Path:
|
|
110
|
+
"""The ONE outage record. Machine-wide, not per-session or per-task."""
|
|
111
|
+
return _config_dir() / "auth-expired" / "state.json"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def events_path() -> Path:
|
|
115
|
+
return _config_dir() / "auth-expired-events.jsonl"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _now() -> datetime:
|
|
119
|
+
return datetime.now(timezone.utc)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def log_event(event: str, **fields) -> None:
|
|
123
|
+
"""Append an event. Best-effort — telemetry must never break a dispatch."""
|
|
124
|
+
try:
|
|
125
|
+
path = events_path()
|
|
126
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
127
|
+
with open(path, "a") as f:
|
|
128
|
+
f.write(json.dumps({"ts": _now().isoformat(), "event": event, **fields}) + "\n")
|
|
129
|
+
except OSError:
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# ---------------------------------------------------------------------------
|
|
134
|
+
# Detection — the transcript
|
|
135
|
+
# ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _tail_lines(path: Path, limit: int = TAIL_BYTES) -> list[str]:
|
|
139
|
+
"""The last complete lines of *path*, bounded by *limit* bytes.
|
|
140
|
+
|
|
141
|
+
The first line of a mid-file read is almost always a fragment, so it is
|
|
142
|
+
dropped rather than fed to ``json.loads`` — a partial row must read as
|
|
143
|
+
"nothing to see", never as a parse error that aborts the scan.
|
|
144
|
+
"""
|
|
145
|
+
try:
|
|
146
|
+
size = path.stat().st_size
|
|
147
|
+
with open(path, "rb") as f:
|
|
148
|
+
if size > limit:
|
|
149
|
+
f.seek(size - limit)
|
|
150
|
+
chunk = f.read()
|
|
151
|
+
chunk = chunk.split(b"\n", 1)[1] if b"\n" in chunk else b""
|
|
152
|
+
else:
|
|
153
|
+
chunk = f.read()
|
|
154
|
+
except OSError:
|
|
155
|
+
return []
|
|
156
|
+
return [ln for ln in chunk.decode("utf-8", "replace").split("\n") if ln.strip()]
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def last_assistant_turn(path: Path) -> dict | None:
|
|
160
|
+
"""The last ``assistant`` row in *path*, or None.
|
|
161
|
+
|
|
162
|
+
"Last" is the whole point. A transcript that auth-failed at 08:00 and took
|
|
163
|
+
a real turn at 09:00 has recovered, and reporting it as expired would gate
|
|
164
|
+
the scheduler on a resolved outage. Reading only the final assistant row
|
|
165
|
+
makes recovery fall out of detection instead of needing a reset.
|
|
166
|
+
"""
|
|
167
|
+
found = None
|
|
168
|
+
for line in _tail_lines(path):
|
|
169
|
+
try:
|
|
170
|
+
row = json.loads(line)
|
|
171
|
+
except (json.JSONDecodeError, ValueError):
|
|
172
|
+
continue
|
|
173
|
+
if isinstance(row, dict) and row.get("type") == "assistant":
|
|
174
|
+
found = row
|
|
175
|
+
return found
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def row_is_auth_failure(row: dict | None) -> bool:
|
|
179
|
+
"""Does *row* carry the expired-login rejection?
|
|
180
|
+
|
|
181
|
+
Keyed on the structured ``error`` field, not on the rendered text, so a
|
|
182
|
+
reworded message keeps working and an assistant turn that merely *says*
|
|
183
|
+
the phrase (an agent reporting on this very incident) never matches.
|
|
184
|
+
|
|
185
|
+
Rewording is proven, not assumed: the two real outages on disk render
|
|
186
|
+
DIFFERENTLY — "Login expired · Please run /login" (2026-08-04, Claude Code
|
|
187
|
+
2.1.221) and "Not logged in · Please run /login" (2026-07-07, 2.1.201) —
|
|
188
|
+
and share this one field. Both are fixtured.
|
|
189
|
+
|
|
190
|
+
The residual risk is RESTRUCTURING, not rewording: if a future version
|
|
191
|
+
nests the error (say under ``message.error`` or an ``error.type``), this
|
|
192
|
+
returns False and the detector goes quiet rather than loud. Nothing here
|
|
193
|
+
can catch that on its own — the check to run when a Claude Code upgrade
|
|
194
|
+
lands is that ``error`` is still a top-level string on an api-error row.
|
|
195
|
+
"""
|
|
196
|
+
if not isinstance(row, dict):
|
|
197
|
+
return False
|
|
198
|
+
return row.get("error") == AUTH_ERROR
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def transcript_auth_failure(path: Path) -> bool:
|
|
202
|
+
"""True iff *path*'s most recent assistant turn was refused for auth."""
|
|
203
|
+
return row_is_auth_failure(last_assistant_turn(path))
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
# ---------------------------------------------------------------------------
|
|
207
|
+
# Detection — locating the transcripts to read
|
|
208
|
+
# ---------------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def recorded_transcripts(session: str) -> list[Path]:
|
|
212
|
+
"""Transcripts named by the session's own launch record (#871).
|
|
213
|
+
|
|
214
|
+
The strong path: agentwire MINTS the conversation id and records it with
|
|
215
|
+
the launch cwd, so this addresses the exact file rather than guessing.
|
|
216
|
+
Returns [] when the record predates #871 (or the session was never
|
|
217
|
+
recorded) — the caller falls back to :func:`touched_transcripts`, which is
|
|
218
|
+
still evidence rather than a guess.
|
|
219
|
+
"""
|
|
220
|
+
from .core import load_session_metadata
|
|
221
|
+
from .history import PROJECTS_DIR, encode_project_path
|
|
222
|
+
|
|
223
|
+
try:
|
|
224
|
+
meta = load_session_metadata(session)
|
|
225
|
+
except Exception:
|
|
226
|
+
return []
|
|
227
|
+
cwd = meta.get("cwd_at_launch")
|
|
228
|
+
ids = meta.get("conversation_ids") or []
|
|
229
|
+
if not cwd or not ids:
|
|
230
|
+
return []
|
|
231
|
+
base = Path(PROJECTS_DIR) / encode_project_path(str(cwd))
|
|
232
|
+
return [p for p in (base / f"{cid}.jsonl" for cid in ids) if p.exists()]
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def touched_transcripts(project_path, since: float) -> list[Path]:
|
|
236
|
+
"""Transcripts in *project_path*'s history dir written since *since*.
|
|
237
|
+
|
|
238
|
+
The fallback for a session whose launch record predates #871 — which is
|
|
239
|
+
exactly ``memory-manager``'s shape on 2026-08-04, so a detector that only
|
|
240
|
+
handled the recorded path could not have seen the incident it was written
|
|
241
|
+
for.
|
|
242
|
+
|
|
243
|
+
Deliberately NOT "the newest ``.jsonl`` in the directory", the guess
|
|
244
|
+
CLAUDE.md warns against: this is scoped to one project dir AND to files
|
|
245
|
+
written during the window the caller is asking about, so a hit is a
|
|
246
|
+
transcript this run actually produced.
|
|
247
|
+
"""
|
|
248
|
+
from .history import PROJECTS_DIR, encode_project_path
|
|
249
|
+
|
|
250
|
+
base = Path(PROJECTS_DIR) / encode_project_path(str(project_path))
|
|
251
|
+
try:
|
|
252
|
+
entries = list(base.glob("*.jsonl"))
|
|
253
|
+
except OSError:
|
|
254
|
+
return []
|
|
255
|
+
out = []
|
|
256
|
+
for p in entries:
|
|
257
|
+
try:
|
|
258
|
+
if p.stat().st_mtime >= since:
|
|
259
|
+
out.append(p)
|
|
260
|
+
except OSError:
|
|
261
|
+
continue
|
|
262
|
+
return sorted(out)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def detect(session: str, project_path=None, since: float | None = None) -> dict | None:
|
|
266
|
+
"""Is *session*'s last turn an expired-login rejection?
|
|
267
|
+
|
|
268
|
+
Returns a detail dict (never a bare bool — the caller has to be able to
|
|
269
|
+
say WHICH transcript proved it) or None. Recorded transcripts first; the
|
|
270
|
+
touched-since fallback only when the record can't name one.
|
|
271
|
+
"""
|
|
272
|
+
for path in recorded_transcripts(session):
|
|
273
|
+
if transcript_auth_failure(path):
|
|
274
|
+
return {"session": session, "transcript": str(path), "source": "recorded"}
|
|
275
|
+
if project_path is not None and since is not None:
|
|
276
|
+
for path in touched_transcripts(project_path, since):
|
|
277
|
+
if transcript_auth_failure(path):
|
|
278
|
+
return {"session": session, "transcript": str(path), "source": "touched"}
|
|
279
|
+
return None
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
# ---------------------------------------------------------------------------
|
|
283
|
+
# Machine-wide outage state
|
|
284
|
+
# ---------------------------------------------------------------------------
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def read_state() -> dict | None:
|
|
288
|
+
try:
|
|
289
|
+
return json.loads(state_path().read_text())
|
|
290
|
+
except (OSError, json.JSONDecodeError):
|
|
291
|
+
return None
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def write_state(state: dict) -> None:
|
|
295
|
+
"""Atomic — a torn write must not leave an unparseable gate behind."""
|
|
296
|
+
path = state_path()
|
|
297
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
298
|
+
tmp = path.with_suffix(".tmp")
|
|
299
|
+
tmp.write_text(json.dumps(state, indent=2))
|
|
300
|
+
os.replace(tmp, path)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def clear_state() -> bool:
|
|
304
|
+
"""Drop the outage record. True iff one was there.
|
|
305
|
+
|
|
306
|
+
Called from ``completion.wait_for_completion_signal``'s success path: a
|
|
307
|
+
written task summary is proof a turn ran, which is proof the login works.
|
|
308
|
+
That is what makes the operator-facing "reopens on the first successful
|
|
309
|
+
turn" a fact rather than a description of behavior nothing implements —
|
|
310
|
+
the mismatch #906 itself is about, at a smaller scale. ``OUTAGE_TTL``
|
|
311
|
+
remains the backstop for a fleet that isn't completing anything.
|
|
312
|
+
"""
|
|
313
|
+
try:
|
|
314
|
+
state_path().unlink()
|
|
315
|
+
log_event("outage_cleared")
|
|
316
|
+
return True
|
|
317
|
+
except OSError:
|
|
318
|
+
return False
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def outage_active(now: datetime | None = None) -> dict | None:
|
|
322
|
+
"""The current outage, or None if there isn't a fresh one.
|
|
323
|
+
|
|
324
|
+
Freshness is the safety property: a recorded outage gates dispatch only
|
|
325
|
+
while it has been seen within :data:`OUTAGE_TTL`. Past that the gate opens
|
|
326
|
+
and the next dispatch acts as the probe — which, with detection in place,
|
|
327
|
+
fails in seconds instead of hours. A flag that gated forever would take the
|
|
328
|
+
whole scheduler down on a stale file.
|
|
329
|
+
"""
|
|
330
|
+
state = read_state()
|
|
331
|
+
if not state:
|
|
332
|
+
return None
|
|
333
|
+
try:
|
|
334
|
+
seen = datetime.fromisoformat(state["last_seen"])
|
|
335
|
+
except (KeyError, TypeError, ValueError):
|
|
336
|
+
return None
|
|
337
|
+
if (now or _now()) - seen > OUTAGE_TTL:
|
|
338
|
+
return None
|
|
339
|
+
return state
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def record_outage(detail: dict, source: str = "ensure") -> dict:
|
|
343
|
+
"""Record (or refresh) the machine-wide outage and escalate once.
|
|
344
|
+
|
|
345
|
+
``detected_at`` is carried forward across refreshes so the operator can see
|
|
346
|
+
how long the outage has run; refreshing it each sighting would make a
|
|
347
|
+
four-hour outage read as seconds old — the same defect #905 fixed on
|
|
348
|
+
``detected_at`` in the prompt sweep.
|
|
349
|
+
"""
|
|
350
|
+
prior = read_state() or {}
|
|
351
|
+
now = _now()
|
|
352
|
+
sessions = list(prior.get("sessions") or [])
|
|
353
|
+
if detail.get("session") and detail["session"] not in sessions:
|
|
354
|
+
sessions.append(detail["session"])
|
|
355
|
+
state = {
|
|
356
|
+
"detected_at": prior.get("detected_at") or now.isoformat(),
|
|
357
|
+
"last_seen": now.isoformat(),
|
|
358
|
+
"sessions": sessions,
|
|
359
|
+
"transcript": detail.get("transcript"),
|
|
360
|
+
"source": source,
|
|
361
|
+
"host": socket.gethostname(),
|
|
362
|
+
"escalated_at": prior.get("escalated_at"),
|
|
363
|
+
}
|
|
364
|
+
state["escalated_at"] = _escalate(state, prior)
|
|
365
|
+
write_state(state)
|
|
366
|
+
log_event("outage_detected", session=detail.get("session"),
|
|
367
|
+
transcript=detail.get("transcript"), source=source)
|
|
368
|
+
return state
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _escalate(state: dict, prior: dict) -> str | None:
|
|
372
|
+
"""Email the owner once per :data:`ESCALATE_TTL` while the outage persists.
|
|
373
|
+
|
|
374
|
+
Best-effort in the strong sense: a missing key or a provider failure must
|
|
375
|
+
never turn "we detected the outage and failed the task fast" into an
|
|
376
|
+
exception that fails it slowly instead. The outage state is written either
|
|
377
|
+
way, so the gate works with or without the email.
|
|
378
|
+
|
|
379
|
+
Consequence worth naming: only a SUCCESSFUL send stamps ``escalated_at``,
|
|
380
|
+
so a persistently broken sender is retried once per detection rather than
|
|
381
|
+
once per :data:`ESCALATE_TTL`. That is the intended trade — a send that
|
|
382
|
+
silently counted as delivered would lose the escalation entirely, and
|
|
383
|
+
losing it is strictly worse than retrying it. The retry is cheap (the
|
|
384
|
+
email path is already best-effort and off the critical path) and it stops
|
|
385
|
+
the moment one send lands.
|
|
386
|
+
"""
|
|
387
|
+
previous = prior.get("escalated_at")
|
|
388
|
+
if previous:
|
|
389
|
+
try:
|
|
390
|
+
if _now() - datetime.fromisoformat(previous) < ESCALATE_TTL:
|
|
391
|
+
return previous
|
|
392
|
+
except (TypeError, ValueError):
|
|
393
|
+
pass
|
|
394
|
+
try:
|
|
395
|
+
from .channels.email import send_email
|
|
396
|
+
|
|
397
|
+
sessions = ", ".join(state.get("sessions") or []) or "(none recorded)"
|
|
398
|
+
body = "\n".join([
|
|
399
|
+
f"Claude Code on `{state.get('host')}` is refusing every turn with "
|
|
400
|
+
f"**{RENDERED}** (`error: {AUTH_ERROR}`).",
|
|
401
|
+
"",
|
|
402
|
+
f"- **First seen:** {state.get('detected_at')}",
|
|
403
|
+
f"- **Sessions affected so far:** {sessions}",
|
|
404
|
+
f"- **Evidence:** {state.get('transcript')}",
|
|
405
|
+
"",
|
|
406
|
+
"Scheduled dispatches are being skipped rather than each burning its "
|
|
407
|
+
"own timeout. Run `/login` in any Claude Code session to clear it; "
|
|
408
|
+
"the gate re-probes automatically and reopens on the first "
|
|
409
|
+
"successful turn.",
|
|
410
|
+
])
|
|
411
|
+
result = send_email(
|
|
412
|
+
subject=f"[agentwire] Claude login expired on {state.get('host')} — dispatch gated",
|
|
413
|
+
body=body,
|
|
414
|
+
)
|
|
415
|
+
if getattr(result, "success", False):
|
|
416
|
+
log_event("escalated", sessions=state.get("sessions"))
|
|
417
|
+
return _now().isoformat()
|
|
418
|
+
log_event("escalate_failed", error=getattr(result, "error", None))
|
|
419
|
+
except Exception as exc: # never break the caller
|
|
420
|
+
log_event("escalate_failed", error=str(exc))
|
|
421
|
+
return previous
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def check_and_flag(
|
|
425
|
+
session: str, project_path=None, since: float | None = None, source: str = "ensure"
|
|
426
|
+
) -> dict | None:
|
|
427
|
+
"""The fast-path probe for polling loops. Mirrors ``usage_limit.check_and_park``.
|
|
428
|
+
|
|
429
|
+
Cheap when nothing is wrong (one or two bounded tail reads), records the
|
|
430
|
+
machine-wide outage and escalates when it is. Returns the detail dict so
|
|
431
|
+
the caller can name the transcript in its own failure message.
|
|
432
|
+
"""
|
|
433
|
+
detail = detect(session, project_path=project_path, since=since)
|
|
434
|
+
if detail is None:
|
|
435
|
+
return None
|
|
436
|
+
record_outage(detail, source=source)
|
|
437
|
+
return detail
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def summary_line(detail: dict | None = None) -> str:
|
|
441
|
+
"""The operator-facing reason string. Names the cause, not the symptom."""
|
|
442
|
+
where = f" (evidence: {detail['transcript']})" if detail and detail.get("transcript") else ""
|
|
443
|
+
return (
|
|
444
|
+
f"Claude login expired — the agent's turn was refused with "
|
|
445
|
+
f"'{RENDERED}' (error: {AUTH_ERROR}); no completion signal can arrive "
|
|
446
|
+
f"until `/login` is run{where}"
|
|
447
|
+
)
|