agentwire-dev 1.78.0__tar.gz → 1.79.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.78.0 → agentwire_dev-1.79.0}/PKG-INFO +1 -1
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/core.py +34 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/doctor_cli.py +68 -6
- agentwire_dev-1.79.0/agentwire/hooks/session-start-handler.sh +23 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/hooks_cli.py +62 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety_cli.py +5 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety_commands.py +6 -4
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety_migrate.py +63 -8
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/sessions/conversation-identity.md +37 -0
- agentwire_dev-1.79.0/tests/unit/test_conversation_change.py +176 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_hooks_install.py +2 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_safety_deployment.py +3 -2
- agentwire_dev-1.79.0/tests/unit/test_safety_migrate.py +169 -0
- agentwire_dev-1.78.0/tests/unit/test_safety_migrate.py +0 -79
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/.gitignore +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/AGENTS.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/LICENSE +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/README.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/RELEASING.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/SECURITY.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/__main__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/auth_expired.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/background_tasks.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/beta.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/channels_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/chrome_tabs.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/claude_settings.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/cohort.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/config.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/council/minutes.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/env_loader.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/history_migrate.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/hooks/outcome_logger.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/inbox.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_chrome.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_core.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_council.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_msg.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_session.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/mcp_worktree.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/msg_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/notify_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/pane_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/playback_lane.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/prompt_router.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/restart_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/role_prompts.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/contributor.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/reviewer-worktree.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/reviewer.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/shared-checkout.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/worker-worktree.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/desktop.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/audit.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/lint.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/provenance.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/residuals.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rule_baselines.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rules/agentwire-control-plane.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rules/agentwire-control-plane.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rules/agentwire-core.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rules/agentwire-core.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rules/agentwire-mcp-tools.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rules/agentwire-mcp-tools.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rules/agentwire-outbound.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rules/agentwire-outbound.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rules/agentwire.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety/suggest.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety_ext.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety_notify.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/safety_packs_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scheduler/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scheduler/dispatch.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scheduler/models.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scheduler/report.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scheduler/schedule.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scheduler/zombie.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/security.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/sent_ledger.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/server.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/session_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/session_ready.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/session_state.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/css/desktop.css +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/card-terminal.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/dead-key-residue.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/desktop.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/hotkeys.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/lineage.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/session-hud-controller.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/session-hud-notices.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/session-hud-spawn.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/session-hud.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/spawn-ghost.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/taskbar-persist.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/terminal-pane.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/topology-render.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/utils/rich-text.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/voice/audio-unlock.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/js/workspace-window.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/static/topology-harness.html +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/system_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tabs_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tasks_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/council/minutes.html.j2 +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/statusline.sh +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/wait_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/worktree_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/corpus/cases/bypass.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/corpus/cases/control_plane.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/corpus/cases/path_spelling.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/corpus/cases/relative_paths.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/corpus/golden/effective_rules.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/corpus/golden/harvested.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/corpus/golden/rule_ids.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/corpus/golden/snapshot.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/corpus/schema.json +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/design/session-card-fields.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/design/session-card-recommendation.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/logo.png +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/auth-expired.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/internals/session-topology.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/sessions/fan-out-cohorts.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/sessions/heal-line-count-cliff.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/sessions/helper-sessions.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/sessions/messaging.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/pyproject.toml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/corpus_runner.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/audio_unlock_harness.mjs +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/pane_30_shell.txt +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/pane_80_agent.txt +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/pane_80_done.txt +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/pane_80_interrupted.txt +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/pane_80_monitor.txt +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/pane_80_quoted_footer.txt +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/pane_80_second_notice.txt +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/pane_80_shell.txt +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/pane_80_shell_and_monitor.txt +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/transcript_bash_done.jsonl +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/transcript_bash_pending.jsonl +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/transcript_monitor_done.jsonl +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/background_tasks/transcript_monitor_events.jsonl +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/dc_msg_body_quoting_carriers.txt +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/hotkeys_harness.mjs +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/session_hud_detent_harness.mjs +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/taskbar_persist_harness.mjs +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/fixtures/topology_expand_harness.mjs +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/home_guard.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/integration/test_send_verified_tmux.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/integration/test_tmux_name_rewrite.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/integration/test_worktree_cmd.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_agentwire_rules_layer.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_audio_unlock_js.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_audit_attribution.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_audit_outcomes.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_auth_expired.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_auth_expired_dispatch.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_background_tasks.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_background_tasks_review.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_beta_flag.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_block_rows_carry_an_id.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_brace_expansion_zero_access.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_breakglass.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_buddy_removal_keeps.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_chrome_tabs.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_claude_settings.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_cli_stderr_clean.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_cohort.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_control_plane_protection.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_corpus.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_council_minutes.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_damage_control_delete_recursive.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_damage_control_pin.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_dangling_worktrees.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_dc_install.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_dc_policy_packs.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_dc_profile_isolation.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_doctor_orphaned_history.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_doctor_scheduler_staleness.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_doctor_secrets_perms.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_doctor_task_migration.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_ensure_shared_dir.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_ensure_verified_prompt.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_env_loader.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_extension_points.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_golden_snapshot.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_guarded_launch_command.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_helper_session.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_heredoc_marker_liveness.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_history_migrate.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_history_migrate_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_history_resume_name.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_hook_fail_closed.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_hook_fail_closed_matrix.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_hook_link_guard.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_hook_python_floor.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_hook_subprocess.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_hotkeys_js.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_inbox.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_launch_line_reentry.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_launch_via_env.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_live_target_1261.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_mcp_nonblocking.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_mcp_tool_policy.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_msg_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_notify_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_owner_only_writes.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_path_case_folding.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_path_spelling.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_payload_position.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_pending_message_visibility.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_playback_lane.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_policy_ladder.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_portal_pair_url.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_posture_default.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_powershell_matcher.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_projects_registry.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_prompt_router.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_prompt_router_dedup.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_prompt_router_resume.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_prose_operands.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_rebuild_uv_lock.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_relative_path_operands.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_remote_session_record.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_report_back_path_1259.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_restart_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_rich_text_js.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_rm_recoverable.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_role_prompt_retention.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_role_prompt_sweep_wiring.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_rule_files_load.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_rule_ids_pinned.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_rules_json_in_sync.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_safe_cwd.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_safety_ext.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_safety_groups.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_safety_install.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_safety_notify.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_safety_packs.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_say_lane.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_scan_budget.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_scheduler_liveness.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_scheduler_zombie.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_sed_script_is_data.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_sent_ledger.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_services_command.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_session_created_by_env.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_session_hud_detent_js.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_session_metadata_ssot.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_session_metadata_write.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_session_ready.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_session_state.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_shim_selfheal.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_task_max_duration.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_taskbar_persist_js.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_tasks_cli.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_tmux_session_cwd.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_topology_expand_js.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_unattended_allow.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_unattended_scoped_allow.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_voice_assistant_removed.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_voice_off_and_shim_bind.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_watchdog_stages.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_worktree.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_worktree_branch_cleanup.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_worktree_dot_project.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_worktree_git_truth.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_worktree_layout.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_worktree_registry.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tests/unit/test_zero_access_member_access.py +0 -0
- {agentwire_dev-1.78.0 → agentwire_dev-1.79.0}/tools/nonce_stt_probe.py +0 -0
|
@@ -1550,6 +1550,40 @@ def record_session_launch(
|
|
|
1550
1550
|
return metadata
|
|
1551
1551
|
|
|
1552
1552
|
|
|
1553
|
+
def record_conversation_change(session_name: str, conversation_id: str) -> bool:
|
|
1554
|
+
"""Make *conversation_id* the session's CURRENT conversation (#1271).
|
|
1555
|
+
|
|
1556
|
+
:func:`record_session_launch` writes the chain once, at launch. Claude
|
|
1557
|
+
mints a new id inside a running session on ``/clear`` and switches ids on
|
|
1558
|
+
``/resume``, and nothing at launch can know — so the SessionStart hook
|
|
1559
|
+
reports each change here, and ``restart``'s newest-first chain walk works
|
|
1560
|
+
unchanged.
|
|
1561
|
+
|
|
1562
|
+
The id ends up LAST in the chain: a fresh id is appended, and an id already
|
|
1563
|
+
recorded (a ``/resume`` back to an earlier conversation) is moved to the
|
|
1564
|
+
tail, because the walk reads the tail as "what the session is in now".
|
|
1565
|
+
Already-last is a no-op that writes nothing, so the hook is idempotent and
|
|
1566
|
+
the launch's own record (which fires the same id) costs nothing.
|
|
1567
|
+
|
|
1568
|
+
Returns whether the record changed. A session with no launch record is left
|
|
1569
|
+
alone (False) — this must never conjure a partial record that
|
|
1570
|
+
``recorded_sessions`` and ``doctor`` would then take for a launched
|
|
1571
|
+
session. Raises ``OSError`` if the write doesn't land (see
|
|
1572
|
+
:func:`store_session_metadata`); the hook decides what to do about that.
|
|
1573
|
+
"""
|
|
1574
|
+
metadata = load_session_metadata(session_name)
|
|
1575
|
+
if not metadata.get("cwd_at_launch"):
|
|
1576
|
+
return False
|
|
1577
|
+
|
|
1578
|
+
chain = list(metadata.get("conversation_ids") or [])
|
|
1579
|
+
if chain and chain[-1] == conversation_id:
|
|
1580
|
+
return False
|
|
1581
|
+
|
|
1582
|
+
metadata["conversation_ids"] = [c for c in chain if c != conversation_id] + [conversation_id]
|
|
1583
|
+
store_session_metadata(session_name, metadata)
|
|
1584
|
+
return True
|
|
1585
|
+
|
|
1586
|
+
|
|
1553
1587
|
def notify_portal_session_created(session_name: str, parent: str | None, role: str | None) -> None:
|
|
1554
1588
|
"""Tell the portal a session was just created, with topology context (#747).
|
|
1555
1589
|
|
|
@@ -497,6 +497,8 @@ def _render_damage_control_section(fix: bool = False) -> int:
|
|
|
497
497
|
print(f" [{mark}] {finding['message']}")
|
|
498
498
|
if finding["level"] == "bad":
|
|
499
499
|
issues += 1
|
|
500
|
+
if finding["code"] == "stale-ruleset":
|
|
501
|
+
print(" Fix: agentwire safety install --refresh (prints the diff and acknowledges it)")
|
|
500
502
|
if not package_status["ok"]:
|
|
501
503
|
print(" Fix: agentwire hooks install (or: agentwire doctor --fix)")
|
|
502
504
|
print(" Blocked outright? From a normal terminal (not through Claude Code):")
|
|
@@ -534,11 +536,9 @@ def _render_damage_control_section(fix: bool = False) -> int:
|
|
|
534
536
|
|
|
535
537
|
# Rules and tooldefs ship inside the package; what lives on the machine is the host's
|
|
536
538
|
# own overlay. A file there REPLACES the bundled one of the same name, so name each.
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
print(f" [..] Your {section} overlay replaces bundled files: {', '.join(named)}")
|
|
541
|
-
print(" Fix: agentwire safety migrate (removes pristine copies, keeps your edits)")
|
|
539
|
+
overlay_plan = safety_migrate.classify()
|
|
540
|
+
for line in safety_migrate.overlay_report_lines(overlay_plan):
|
|
541
|
+
print(line)
|
|
542
542
|
|
|
543
543
|
# Rule groups and packs (#1141): informational only, never scored — a
|
|
544
544
|
# disabled pack is a choice, not drift.
|
|
@@ -580,7 +580,7 @@ def _render_damage_control_section(fix: bool = False) -> int:
|
|
|
580
580
|
print(f" [!!] DUPLICATE rule ids in the loaded rule set: {', '.join(duplicates)}")
|
|
581
581
|
print(" `disabled_rules` / `unattended_allow` naming one of these names")
|
|
582
582
|
print(" BOTH rules. Usually a half-applied rule sync.")
|
|
583
|
-
print(" Fix:
|
|
583
|
+
print(f" Fix: {safety_migrate.duplicate_ids_fix(overlay_plan)}")
|
|
584
584
|
issues += 1
|
|
585
585
|
else:
|
|
586
586
|
print(" [ok] Rule ids unique across the loaded rule set")
|
|
@@ -936,6 +936,56 @@ def scan_orphaned_history(sessions: list[str] | None = None) -> list[dict]:
|
|
|
936
936
|
return findings
|
|
937
937
|
|
|
938
938
|
|
|
939
|
+
def scan_unrecorded_transcripts(sessions: list[str] | None = None) -> list[dict]:
|
|
940
|
+
"""Live sessions whose project dir holds transcripts newer than the recorded head (#1271).
|
|
941
|
+
|
|
942
|
+
The SessionStart hook keeps ``conversation_ids`` current across ``/clear``
|
|
943
|
+
and ``/resume``; a session that took one BEFORE the hook was installed has
|
|
944
|
+
a chain that stops at its launch id, and ``restart`` would resume that
|
|
945
|
+
stale conversation. The evidence is on disk: transcripts in the session's
|
|
946
|
+
history dir, absent from the chain, written after the head's own.
|
|
947
|
+
|
|
948
|
+
STATED, never scored, because it cannot be certain: the history dir is
|
|
949
|
+
keyed by cwd, so a second session sharing the directory writes transcripts
|
|
950
|
+
that look identical. The finding lists the candidates and says so. Live
|
|
951
|
+
sessions only — the ones you might actually restart.
|
|
952
|
+
"""
|
|
953
|
+
from .core import load_session_metadata, recorded_sessions
|
|
954
|
+
from .history import claude_projects_dir, history_key_candidates
|
|
955
|
+
|
|
956
|
+
findings: list[dict] = []
|
|
957
|
+
for name in sessions if sessions is not None else recorded_sessions():
|
|
958
|
+
metadata = load_session_metadata(name)
|
|
959
|
+
ids = list(metadata.get("conversation_ids") or [])
|
|
960
|
+
cwd = metadata.get("cwd_at_launch")
|
|
961
|
+
if not ids or not cwd or not tmux_session_exists(name):
|
|
962
|
+
continue
|
|
963
|
+
|
|
964
|
+
for key in history_key_candidates(cwd):
|
|
965
|
+
project = claude_projects_dir() / key
|
|
966
|
+
try:
|
|
967
|
+
head = project / f"{ids[-1]}.jsonl"
|
|
968
|
+
baseline = head.stat().st_mtime if head.exists() else None
|
|
969
|
+
if baseline is None:
|
|
970
|
+
continue # no head transcript to be newer than
|
|
971
|
+
newer = sorted(
|
|
972
|
+
(f for f in project.glob("*.jsonl")
|
|
973
|
+
if f.stem not in ids and f.stat().st_mtime > baseline),
|
|
974
|
+
key=lambda f: f.stat().st_mtime,
|
|
975
|
+
)
|
|
976
|
+
except OSError:
|
|
977
|
+
continue
|
|
978
|
+
if newer:
|
|
979
|
+
findings.append({
|
|
980
|
+
"session": name,
|
|
981
|
+
"head": ids[-1],
|
|
982
|
+
"newer": [f.stem for f in newer],
|
|
983
|
+
"project_dir": str(project),
|
|
984
|
+
})
|
|
985
|
+
break
|
|
986
|
+
return findings
|
|
987
|
+
|
|
988
|
+
|
|
939
989
|
def _render_orphaned_history_section() -> int:
|
|
940
990
|
"""Doctor section: conversations a restart could not bring back (#871).
|
|
941
991
|
|
|
@@ -975,6 +1025,18 @@ def _render_orphaned_history_section() -> int:
|
|
|
975
1025
|
print(" Not a fault. Restarting these keeps the role and starts a fresh "
|
|
976
1026
|
"conversation.")
|
|
977
1027
|
|
|
1028
|
+
unrecorded = scan_unrecorded_transcripts()
|
|
1029
|
+
if unrecorded:
|
|
1030
|
+
print(f" [..] {len(unrecorded)} live session(s) with transcripts newer than the "
|
|
1031
|
+
"recorded conversation:")
|
|
1032
|
+
for f in unrecorded:
|
|
1033
|
+
print(f" - {f['session']}: recorded head {f['head'][:8]}, newer "
|
|
1034
|
+
f"{', '.join(c[:8] for c in f['newer'])}")
|
|
1035
|
+
print(" Likely a /clear or /resume taken before the session-start hook was "
|
|
1036
|
+
"installed (`agentwire hooks install`): `agentwire restart` would resume the "
|
|
1037
|
+
"recorded head, not the newer conversation. Not scored — another session in "
|
|
1038
|
+
"the same directory writes transcripts that look the same.")
|
|
1039
|
+
|
|
978
1040
|
return len(orphaned)
|
|
979
1041
|
|
|
980
1042
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Claude Code SessionStart hook (source: startup|resume|clear|compact).
|
|
3
|
+
#
|
|
4
|
+
# Claude mints a new conversation id on /clear and switches ids on /resume;
|
|
5
|
+
# nothing at launch can know. This reports the id to the owning agentwire
|
|
6
|
+
# session's record so `agentwire restart` resumes the CURRENT conversation
|
|
7
|
+
# (#1271). The logic lives in `agentwire hooks session-start` (CLI is SSOT);
|
|
8
|
+
# this wrapper only hands over the payload.
|
|
9
|
+
#
|
|
10
|
+
# Never blocks the session start and never fails it: the work runs detached
|
|
11
|
+
# and the script exits 0 unconditionally.
|
|
12
|
+
|
|
13
|
+
DEBUG_LOG="/tmp/claude-hook-debug.log"
|
|
14
|
+
AGENTWIRE="${AGENTWIRE_BIN:-$(which agentwire 2>/dev/null || echo "$HOME/.local/bin/agentwire")}"
|
|
15
|
+
|
|
16
|
+
input=$(cat)
|
|
17
|
+
[[ -n "$TMUX_PANE" ]] || exit 0
|
|
18
|
+
|
|
19
|
+
(
|
|
20
|
+
printf '%s' "$input" | "$AGENTWIRE" hooks session-start 2>&1 \
|
|
21
|
+
| sed "s|^|[$(date -Iseconds)] session-start: |" >> "$DEBUG_LOG"
|
|
22
|
+
) </dev/null >/dev/null 2>&1 &
|
|
23
|
+
exit 0
|
|
@@ -382,6 +382,13 @@ def _managed_hook_files() -> list[ManagedHook]:
|
|
|
382
382
|
("PostToolUse", "PostToolUseFailure", "PermissionDenied"),
|
|
383
383
|
"Outcome logger", True, "required for damage-control audit outcomes",
|
|
384
384
|
),
|
|
385
|
+
# Reports Claude's in-session conversation changes (/clear, /resume,
|
|
386
|
+
# compact) into the launch record so `restart` resumes the CURRENT one.
|
|
387
|
+
ManagedHook(
|
|
388
|
+
"session-start-handler.sh", claude_hooks_dir(), ("SessionStart",),
|
|
389
|
+
"Session-start hook", True,
|
|
390
|
+
"required for `agentwire restart` to resume after /clear or /resume",
|
|
391
|
+
),
|
|
385
392
|
ManagedHook(
|
|
386
393
|
"queue-processor.sh", Path.home() / ".agentwire", (),
|
|
387
394
|
"Queue processor", True, "required for notification queuing",
|
|
@@ -740,6 +747,54 @@ def cmd_hooks_status(args) -> int:
|
|
|
740
747
|
return 0
|
|
741
748
|
|
|
742
749
|
|
|
750
|
+
def record_session_start(payload: dict) -> str:
|
|
751
|
+
"""Apply one SessionStart payload to the owning session's record (#1271).
|
|
752
|
+
|
|
753
|
+
Returns a one-line outcome for the hook log. The owning session is resolved
|
|
754
|
+
from the PANE, and only pane 0 counts: a worker pane (index > 0) is not a
|
|
755
|
+
session and its conversation must never overwrite its owner's chain — the
|
|
756
|
+
same rule ``spawn`` and prompt routing apply. Raises on a failed write;
|
|
757
|
+
:func:`cmd_hooks_session_start` is the one place that turns that into exit 0.
|
|
758
|
+
"""
|
|
759
|
+
from . import pane_manager
|
|
760
|
+
from .core import record_conversation_change
|
|
761
|
+
|
|
762
|
+
conversation_id = payload.get("session_id")
|
|
763
|
+
if not isinstance(conversation_id, str) or not conversation_id:
|
|
764
|
+
return "skipped: payload has no session_id"
|
|
765
|
+
|
|
766
|
+
session = pane_manager.get_current_session()
|
|
767
|
+
pane_index = pane_manager.get_current_pane_index()
|
|
768
|
+
if not session or pane_index is None:
|
|
769
|
+
return "skipped: not in a tmux pane"
|
|
770
|
+
if pane_index > 0:
|
|
771
|
+
return f"skipped: worker pane {session}.{pane_index}"
|
|
772
|
+
|
|
773
|
+
source = payload.get("source", "?")
|
|
774
|
+
if record_conversation_change(session, conversation_id):
|
|
775
|
+
return f"recorded {conversation_id} for {session} (source={source})"
|
|
776
|
+
return f"unchanged: {session} already at {conversation_id} or has no launch record"
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
def cmd_hooks_session_start(args) -> int:
|
|
780
|
+
"""Claude Code SessionStart hook body: payload on stdin, ALWAYS exits 0.
|
|
781
|
+
|
|
782
|
+
A hook that can fail a session start is worse than a stale chain, so every
|
|
783
|
+
error — unreadable payload, tmux gone, store unwritable — is logged to
|
|
784
|
+
stderr (the hook script routes that to the debug log) and swallowed.
|
|
785
|
+
"""
|
|
786
|
+
import sys
|
|
787
|
+
|
|
788
|
+
try:
|
|
789
|
+
payload = json.loads(sys.stdin.read() or "{}")
|
|
790
|
+
if not isinstance(payload, dict):
|
|
791
|
+
raise ValueError("payload is not a JSON object")
|
|
792
|
+
print(record_session_start(payload), file=sys.stderr)
|
|
793
|
+
except Exception as e:
|
|
794
|
+
print(f"session-start hook error: {type(e).__name__}: {e}", file=sys.stderr)
|
|
795
|
+
return 0
|
|
796
|
+
|
|
797
|
+
|
|
743
798
|
def register_hooks_parser(subparsers) -> None:
|
|
744
799
|
hooks_parser = subparsers.add_parser(
|
|
745
800
|
"hooks", help="Manage agentwire hook files (permission, idle handler, queue processor)"
|
|
@@ -775,3 +830,10 @@ def register_hooks_parser(subparsers) -> None:
|
|
|
775
830
|
"status", help="Check hook installation status"
|
|
776
831
|
)
|
|
777
832
|
hooks_status.set_defaults(func=cmd_hooks_status)
|
|
833
|
+
|
|
834
|
+
# hooks session-start (invoked by the SessionStart hook, not by humans)
|
|
835
|
+
hooks_session_start = hooks_subparsers.add_parser(
|
|
836
|
+
"session-start",
|
|
837
|
+
help="SessionStart hook body: record the new conversation id (reads the payload on stdin; always exits 0)",
|
|
838
|
+
)
|
|
839
|
+
hooks_session_start.set_defaults(func=cmd_hooks_session_start)
|
|
@@ -54,6 +54,7 @@ def cmd_safety_install(args) -> int:
|
|
|
54
54
|
assume_yes=getattr(args, "yes", False),
|
|
55
55
|
force=getattr(args, "force", False),
|
|
56
56
|
allow_foreign=getattr(args, "allow_foreign_source", False),
|
|
57
|
+
refresh=getattr(args, "refresh", False),
|
|
57
58
|
)
|
|
58
59
|
|
|
59
60
|
|
|
@@ -163,6 +164,10 @@ def register_safety_parser(subparsers) -> None:
|
|
|
163
164
|
"--force", action="store_true",
|
|
164
165
|
help="Override the downgrade refusal (this package is older than the recorded install)",
|
|
165
166
|
)
|
|
167
|
+
safety_install.add_argument(
|
|
168
|
+
"--refresh", action="store_true",
|
|
169
|
+
help="Print and acknowledge the ruleset diff since the last install (loosening is marked !!)",
|
|
170
|
+
)
|
|
166
171
|
safety_install.add_argument(
|
|
167
172
|
"--allow-foreign-source", action="store_true",
|
|
168
173
|
help="Let a checkout that is NOT the installed tool write these "
|
|
@@ -606,16 +606,18 @@ def safety_install_cmd(
|
|
|
606
606
|
assume_yes: bool = False,
|
|
607
607
|
force: bool = False,
|
|
608
608
|
allow_foreign: bool = False,
|
|
609
|
+
refresh: bool = False,
|
|
609
610
|
) -> int:
|
|
610
611
|
"""CLI command: ``agentwire safety install``: the package's ``init`` under AgentWire's profile.
|
|
611
612
|
|
|
612
|
-
Without ``--yes`` it asks once first
|
|
613
|
-
|
|
613
|
+
Without ``--yes`` it asks once first (``--refresh`` only prints and acknowledges the ruleset
|
|
614
|
+
diff, so it does not ask). Returns non-zero on any refusal, so a script can never read a
|
|
615
|
+
refusal as success (the whole of #936's operator picture).
|
|
614
616
|
"""
|
|
615
|
-
if not assume_yes:
|
|
617
|
+
if not assume_yes and not refresh:
|
|
616
618
|
print("This registers the damage-control hooks (damage-control-dev) in Claude Code's user settings:")
|
|
617
619
|
print(f" {sys.executable} -I -m damage_control.hook <bash|edit|write|read|mcp>")
|
|
618
620
|
if input("Proceed with installation? [y/N] ").strip().lower() != "y":
|
|
619
621
|
print("Installation cancelled.")
|
|
620
622
|
return 0
|
|
621
|
-
return safety_ext.install(force=force, allow_foreign=allow_foreign).code
|
|
623
|
+
return safety_ext.install(force=force, allow_foreign=allow_foreign, refresh=refresh).code
|
|
@@ -6,7 +6,9 @@ REPLACES the bundled file of the same name (a stale copy is not protection, it i
|
|
|
6
6
|
a script registration runs code that no longer ships. This command classifies what is on the
|
|
7
7
|
machine with ``rule_baselines.json`` (the sha256 of every version we ever shipped):
|
|
8
8
|
|
|
9
|
-
* an overlay file matching a shipped hash
|
|
9
|
+
* an overlay file matching a shipped hash whose name the bundle still ships holds nothing the
|
|
10
|
+
bundle lacks, so it is deleted;
|
|
11
|
+
* a shipped-hash file the bundle no longer ships (``gws.yaml``, #1143) stays: it may be the only copy;
|
|
10
12
|
* any other overlay file is a human's edit, so it stays (and is named; it still overrides by name);
|
|
11
13
|
* pack decisions that the old always-on files implied are recorded (``packs:`` in the policy);
|
|
12
14
|
* registrations of the old scripts, and the scripts, are removed once the package hooks are
|
|
@@ -27,7 +29,12 @@ from typing import Any, Callable, Dict, List, Optional
|
|
|
27
29
|
from damage_control import harness_config as hc
|
|
28
30
|
from damage_control import install as dc_install
|
|
29
31
|
from damage_control import packs
|
|
30
|
-
from damage_control.engine import
|
|
32
|
+
from damage_control.engine import (
|
|
33
|
+
bundled_rule_sources,
|
|
34
|
+
bundled_tooldefs_dir,
|
|
35
|
+
config_override_dir,
|
|
36
|
+
policy_file_path,
|
|
37
|
+
)
|
|
31
38
|
|
|
32
39
|
from . import safety_ext
|
|
33
40
|
|
|
@@ -62,29 +69,74 @@ def _sha256(path: Path) -> Optional[str]:
|
|
|
62
69
|
|
|
63
70
|
|
|
64
71
|
def _dirs() -> Dict[str, Path]:
|
|
72
|
+
safety_ext.activate() # judge by AgentWire's profile: without it config_override_dir() is ~/.damage-control (#1268)
|
|
65
73
|
base = config_override_dir()
|
|
66
74
|
return {"rules": base / "damage-control", "tooldefs": base / "tooldefs"}
|
|
67
75
|
|
|
68
76
|
|
|
69
77
|
def _legacy_dir() -> Path:
|
|
78
|
+
safety_ext.activate()
|
|
70
79
|
return config_override_dir() / "hooks" / "damage-control"
|
|
71
80
|
|
|
72
81
|
|
|
82
|
+
def bundled_names() -> Dict[str, set]:
|
|
83
|
+
"""File names the CURRENT bundle provides: the engine's plus AgentWire's rules layer (#1269)."""
|
|
84
|
+
rule_sources = [*bundled_rule_sources(), safety_ext.RULES_DIR]
|
|
85
|
+
return {
|
|
86
|
+
"rules": {p.name for d in rule_sources for p in d.glob("*.yaml")},
|
|
87
|
+
"tooldefs": {p.name for p in bundled_tooldefs_dir().glob("*.yaml")},
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
73
91
|
def classify() -> Dict[str, Dict[str, List[str]]]:
|
|
74
|
-
"""``{section: {"pristine"
|
|
92
|
+
"""``{section: {"pristine", "edited", "unbundled"}}`` for the shipped-named files on the machine.
|
|
93
|
+
|
|
94
|
+
``pristine`` is redundant: it matches a version we shipped AND the bundle still provides that
|
|
95
|
+
name. ``unbundled`` matches a shipped version but the bundle no longer ships the name (baselines
|
|
96
|
+
keep retired history), so the copy may be the only protection there is and is never retired
|
|
97
|
+
(#1269). ``edited`` is a human's change.
|
|
98
|
+
"""
|
|
75
99
|
out: Dict[str, Dict[str, List[str]]] = {}
|
|
76
100
|
baselines = load_baselines()
|
|
101
|
+
bundled = bundled_names()
|
|
77
102
|
for section, live in _dirs().items():
|
|
78
|
-
|
|
79
|
-
edited: List[str] = []
|
|
103
|
+
groups: Dict[str, List[str]] = {"pristine": [], "edited": [], "unbundled": []}
|
|
80
104
|
for name, hashes in sorted(baselines[section].items()):
|
|
81
105
|
target = live / name
|
|
82
|
-
if target.is_file():
|
|
83
|
-
|
|
84
|
-
|
|
106
|
+
if not target.is_file():
|
|
107
|
+
continue
|
|
108
|
+
if _sha256(target) not in hashes:
|
|
109
|
+
groups["edited"].append(name)
|
|
110
|
+
elif name in bundled[section]:
|
|
111
|
+
groups["pristine"].append(name)
|
|
112
|
+
else:
|
|
113
|
+
groups["unbundled"].append(name)
|
|
114
|
+
out[section] = groups
|
|
85
115
|
return out
|
|
86
116
|
|
|
87
117
|
|
|
118
|
+
def overlay_report_lines(plan: Dict[str, Dict[str, List[str]]]) -> List[str]:
|
|
119
|
+
"""Doctor's overlay lines. Only a pristine copy has a Fix (migrate retires it); edited and
|
|
120
|
+
unbundled files are information, because migrate deliberately keeps them (#1270)."""
|
|
121
|
+
lines: List[str] = []
|
|
122
|
+
for section, groups in plan.items():
|
|
123
|
+
if groups["pristine"]:
|
|
124
|
+
lines.append(f" [..] Redundant {section} copies of bundled files: {', '.join(groups['pristine'])}")
|
|
125
|
+
lines.append(" Fix: agentwire safety migrate (removes the pristine copies)")
|
|
126
|
+
kept = groups["edited"] + groups["unbundled"]
|
|
127
|
+
if kept:
|
|
128
|
+
lines.append(f" [..] Your {section} overlay replaces or adds to the bundle: {', '.join(kept)}")
|
|
129
|
+
return lines
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def duplicate_ids_fix(plan: Dict[str, Dict[str, List[str]]]) -> str:
|
|
133
|
+
"""Legacy overlay copies shadow the bundle and are what duplicate rule ids come from on a
|
|
134
|
+
pre-package install; ``install`` does not touch them, ``migrate`` does (#1270)."""
|
|
135
|
+
if any(groups["pristine"] for groups in plan.values()):
|
|
136
|
+
return "agentwire safety migrate (retires the old overlay copies that duplicate the bundle)"
|
|
137
|
+
return "agentwire safety install --yes"
|
|
138
|
+
|
|
139
|
+
|
|
88
140
|
def legacy_files() -> List[Path]:
|
|
89
141
|
return [p for name in LEGACY_HOOK_FILES if (p := _legacy_dir() / name).exists()]
|
|
90
142
|
|
|
@@ -170,6 +222,7 @@ def migrate(
|
|
|
170
222
|
log: Callable[[str], None] = print,
|
|
171
223
|
) -> int:
|
|
172
224
|
"""Classify, install the package hooks, then retire what only the old install needed. Returns an exit code."""
|
|
225
|
+
safety_ext.activate()
|
|
173
226
|
plan = classify()
|
|
174
227
|
legacy = legacy_files()
|
|
175
228
|
for section, groups in plan.items():
|
|
@@ -177,6 +230,8 @@ def migrate(
|
|
|
177
230
|
log(f"{'would remove' if dry_run else 'remove'} {section[:-1]} copy {name} (the package ships it)")
|
|
178
231
|
for name in groups["edited"]:
|
|
179
232
|
log(f"keep {section[:-1]} {name}: edited, so it replaces the bundled file of that name")
|
|
233
|
+
for name in groups["unbundled"]:
|
|
234
|
+
log(f"keep {section[:-1]} {name}: the package no longer ships it, so this copy is the only one")
|
|
180
235
|
for path in legacy:
|
|
181
236
|
log(f"{'would remove' if dry_run else 'remove'} legacy hook script {path.name}")
|
|
182
237
|
if dry_run:
|
|
@@ -266,6 +266,43 @@ against the installed Claude Code, the same way #878 established tmux's
|
|
|
266
266
|
mapping. Encoding only `/` (#892) produced a key no directory ever had for any
|
|
267
267
|
path with a dot, underscore or space.
|
|
268
268
|
|
|
269
|
+
## The chain follows the conversation, not just the launch (#1271)
|
|
270
|
+
|
|
271
|
+
`record_session_launch` writes the chain **once**. Claude mints a new id inside
|
|
272
|
+
a running session on `/clear` and switches ids on `/resume`, so a chain that
|
|
273
|
+
only knew launches resumed a week-old conversation after six `/clear`s — the
|
|
274
|
+
record named the id the session *started* with, not the one it was *in*. A
|
|
275
|
+
single-launch test cannot see this; the bug only exists after a second step.
|
|
276
|
+
|
|
277
|
+
A Claude Code `SessionStart` hook (`source`: `startup|resume|clear|compact`,
|
|
278
|
+
carrying the new `session_id`) reports each change:
|
|
279
|
+
|
|
280
|
+
- `hooks/session-start-handler.sh` is registered by `agentwire hooks install`
|
|
281
|
+
like the other managed hooks (drift checks in `hooks status` / `doctor`
|
|
282
|
+
included). It runs the work detached and exits 0 unconditionally — a hook
|
|
283
|
+
must never fail or slow a session start.
|
|
284
|
+
- The body is `agentwire hooks session-start` (CLI is SSOT). It resolves the
|
|
285
|
+
owning session from `$TMUX_PANE` via `pane_manager`, **skips worker panes
|
|
286
|
+
(index > 0)** — a pane is not a session and must not write its owner's
|
|
287
|
+
chain, same rule as `spawn` — and calls `core.record_conversation_change`,
|
|
288
|
+
which uses the same atomic `store_session_metadata` write.
|
|
289
|
+
- `record_conversation_change` puts the id **last** in the chain (an id already
|
|
290
|
+
present — `/resume` back to an earlier conversation — moves to the tail,
|
|
291
|
+
because the tail is what restart reads as "current"). Already-last is a no-op,
|
|
292
|
+
so it is idempotent and the launch's own id costs nothing. A session with no
|
|
293
|
+
launch record is left alone: the hook never conjures a partial record.
|
|
294
|
+
- Errors are logged to `/tmp/claude-hook-debug.log`, never raised.
|
|
295
|
+
|
|
296
|
+
`restart`'s newest-first walk is unchanged: a `/clear`ed conversation that
|
|
297
|
+
never took a turn has no transcript yet (written lazily), so the walk falls
|
|
298
|
+
back to the previous id that does.
|
|
299
|
+
|
|
300
|
+
**Sessions that took a `/clear` before the hook was installed** have a chain
|
|
301
|
+
frozen at launch. `doctor` states (never scores) live sessions whose history
|
|
302
|
+
dir holds transcripts newer than the recorded head and absent from the chain.
|
|
303
|
+
It cannot be certain — another session in the same directory writes transcripts
|
|
304
|
+
that look identical — hence a note, not a fault.
|
|
305
|
+
|
|
269
306
|
## Restarting in place
|
|
270
307
|
|
|
271
308
|
`agentwire restart -s <session>` is the verb the record exists for: `/exit`,
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""#1271: ``conversation_ids`` follows Claude's in-session id changes.
|
|
2
|
+
|
|
3
|
+
A single-launch test cannot see this bug: the chain is written at launch, so a
|
|
4
|
+
session that never ``/clear``s always restarts correctly. Every test here takes
|
|
5
|
+
a SECOND step after the launch.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import io
|
|
9
|
+
import json
|
|
10
|
+
import types
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from agentwire import doctor_cli, hooks_cli, restart_cli
|
|
15
|
+
from agentwire.history import encode_project_path
|
|
16
|
+
|
|
17
|
+
TURN = '{"type":"user","message":{"role":"user","content":"hi"}}\n'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@pytest.fixture
|
|
21
|
+
def store(tmp_path, monkeypatch):
|
|
22
|
+
monkeypatch.setattr("agentwire.core.CONFIG_DIR", tmp_path / "agentwire")
|
|
23
|
+
monkeypatch.setattr("agentwire.history.claude_projects_dir", lambda: tmp_path / "projects")
|
|
24
|
+
cwd = tmp_path / "worktree"
|
|
25
|
+
cwd.mkdir()
|
|
26
|
+
(tmp_path / "projects").mkdir()
|
|
27
|
+
return types.SimpleNamespace(root=tmp_path, cwd=cwd, projects=tmp_path / "projects")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.fixture
|
|
31
|
+
def pane(monkeypatch):
|
|
32
|
+
"""Where the hook believes it runs: (session, pane_index)."""
|
|
33
|
+
where = types.SimpleNamespace(session="sess", index=0)
|
|
34
|
+
monkeypatch.setattr("agentwire.pane_manager.get_current_session", lambda: where.session)
|
|
35
|
+
monkeypatch.setattr("agentwire.pane_manager.get_current_pane_index", lambda: where.index)
|
|
36
|
+
return where
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def transcript(store, cid):
|
|
40
|
+
d = store.projects / encode_project_path(str(store.cwd))
|
|
41
|
+
d.mkdir(parents=True, exist_ok=True)
|
|
42
|
+
(d / f"{cid}.jsonl").write_text(TURN)
|
|
43
|
+
return d / f"{cid}.jsonl"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def launch(store, session="sess"):
|
|
47
|
+
from agentwire.core import build_agent_command, record_session_launch
|
|
48
|
+
|
|
49
|
+
agent = build_agent_command("bypass")
|
|
50
|
+
record_session_launch(session, agent, store.cwd)
|
|
51
|
+
return agent.conversation_id
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def session_start(cid, source="clear"):
|
|
55
|
+
return hooks_cli.record_session_start({"session_id": cid, "source": source})
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def chain(session="sess"):
|
|
59
|
+
from agentwire.core import load_session_metadata
|
|
60
|
+
|
|
61
|
+
return load_session_metadata(session)["conversation_ids"]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_restart_resumes_the_post_clear_conversation(store, pane, monkeypatch):
|
|
65
|
+
launched = launch(store)
|
|
66
|
+
transcript(store, launched)
|
|
67
|
+
session_start("after-clear-1")
|
|
68
|
+
transcript(store, "after-clear-1")
|
|
69
|
+
session_start("after-clear-2")
|
|
70
|
+
transcript(store, "after-clear-2")
|
|
71
|
+
|
|
72
|
+
assert chain() == [launched, "after-clear-1", "after-clear-2"]
|
|
73
|
+
|
|
74
|
+
captured = []
|
|
75
|
+
monkeypatch.setattr(restart_cli, "tmux_session_exists", lambda n: False)
|
|
76
|
+
monkeypatch.setattr(restart_cli, "_notify_portal_sessions_changed", lambda: None)
|
|
77
|
+
monkeypatch.setattr(restart_cli.pane_manager, "get_current_session", lambda: None)
|
|
78
|
+
monkeypatch.setattr(
|
|
79
|
+
restart_cli, "_launch_tmux_session",
|
|
80
|
+
lambda name, path, env, cmd: captured.append(cmd),
|
|
81
|
+
)
|
|
82
|
+
args = types.SimpleNamespace(session="sess", json=False, no_wait=True)
|
|
83
|
+
assert restart_cli.cmd_restart(args) == 0
|
|
84
|
+
assert '--resume "after-clear-2" --fork-session' in captured[0]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_a_cleared_but_unprompted_conversation_falls_back_to_the_last_real_one(store, pane):
|
|
88
|
+
launched = launch(store)
|
|
89
|
+
transcript(store, launched)
|
|
90
|
+
session_start("cleared-never-prompted") # no transcript: written lazily
|
|
91
|
+
|
|
92
|
+
resume_id, _ = restart_cli.resolve_resume_target(chain(), str(store.cwd))
|
|
93
|
+
assert resume_id == launched
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_the_hook_is_idempotent_and_resume_moves_an_old_id_to_the_tail(store, pane):
|
|
97
|
+
from agentwire.core import record_conversation_change
|
|
98
|
+
|
|
99
|
+
launched = launch(store)
|
|
100
|
+
assert record_conversation_change("sess", launched) is False # the launch's own id
|
|
101
|
+
session_start("b")
|
|
102
|
+
assert session_start("b").startswith("unchanged")
|
|
103
|
+
assert chain() == [launched, "b"]
|
|
104
|
+
|
|
105
|
+
# /resume back to the launch conversation: it is now the CURRENT one.
|
|
106
|
+
session_start(launched, source="resume")
|
|
107
|
+
assert chain() == ["b", launched]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_the_hook_never_writes_outside_its_own_session_record(store, pane):
|
|
111
|
+
launch(store)
|
|
112
|
+
before = chain()
|
|
113
|
+
|
|
114
|
+
pane.index = 1 # a worker pane is not a session
|
|
115
|
+
assert session_start("worker-conv").startswith("skipped: worker pane")
|
|
116
|
+
|
|
117
|
+
pane.index, pane.session = 0, "no-such-session" # no launch record: nothing to extend
|
|
118
|
+
assert session_start("x").startswith("unchanged")
|
|
119
|
+
from agentwire.core import load_session_metadata, session_metadata_path
|
|
120
|
+
|
|
121
|
+
assert not session_metadata_path("no-such-session").exists()
|
|
122
|
+
assert load_session_metadata("no-such-session") == {}
|
|
123
|
+
assert chain() == before
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_the_hook_command_exits_zero_on_every_bad_input(store, pane, monkeypatch, capsys):
|
|
127
|
+
launch(store)
|
|
128
|
+
bad = ["", "{{{", "[1]", '{"no":"id"}', '{"session_id": 5}']
|
|
129
|
+
codes = []
|
|
130
|
+
for raw in bad:
|
|
131
|
+
monkeypatch.setattr("sys.stdin", io.StringIO(raw))
|
|
132
|
+
codes.append(hooks_cli.cmd_hooks_session_start(types.SimpleNamespace()))
|
|
133
|
+
|
|
134
|
+
def boom(*_):
|
|
135
|
+
raise OSError("read-only store")
|
|
136
|
+
|
|
137
|
+
monkeypatch.setattr("agentwire.core.store_session_metadata", boom)
|
|
138
|
+
monkeypatch.setattr("sys.stdin", io.StringIO(json.dumps({"session_id": "new"})))
|
|
139
|
+
codes.append(hooks_cli.cmd_hooks_session_start(types.SimpleNamespace()))
|
|
140
|
+
|
|
141
|
+
assert codes == [0] * len(codes)
|
|
142
|
+
assert "read-only store" in capsys.readouterr().err # logged, not swallowed silently
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class TestDoctorUnrecordedTranscripts:
|
|
146
|
+
@pytest.fixture(autouse=True)
|
|
147
|
+
def live(self, monkeypatch):
|
|
148
|
+
monkeypatch.setattr(doctor_cli, "tmux_session_exists", lambda n: True)
|
|
149
|
+
|
|
150
|
+
def test_newer_unrecorded_transcript_is_stated(self, store):
|
|
151
|
+
import os
|
|
152
|
+
|
|
153
|
+
launched = launch(store)
|
|
154
|
+
head = transcript(store, launched)
|
|
155
|
+
cleared = transcript(store, "cleared")
|
|
156
|
+
os.utime(head, (1000, 1000))
|
|
157
|
+
os.utime(cleared, (2000, 2000))
|
|
158
|
+
|
|
159
|
+
[f] = doctor_cli.scan_unrecorded_transcripts(["sess"])
|
|
160
|
+
assert (f["head"], f["newer"]) == (launched, ["cleared"])
|
|
161
|
+
|
|
162
|
+
def test_a_recorded_or_older_transcript_is_silent(self, store, pane):
|
|
163
|
+
import os
|
|
164
|
+
|
|
165
|
+
launched = launch(store)
|
|
166
|
+
head = transcript(store, launched)
|
|
167
|
+
older = transcript(store, "older")
|
|
168
|
+
os.utime(older, (500, 500))
|
|
169
|
+
os.utime(head, (1000, 1000))
|
|
170
|
+
assert doctor_cli.scan_unrecorded_transcripts(["sess"]) == []
|
|
171
|
+
|
|
172
|
+
newer = transcript(store, "cleared")
|
|
173
|
+
os.utime(newer, (2000, 2000))
|
|
174
|
+
session_start("cleared") # the hook caught it
|
|
175
|
+
os.utime(newer, (2000, 2000))
|
|
176
|
+
assert doctor_cli.scan_unrecorded_transcripts(["sess"]) == []
|
|
@@ -109,6 +109,8 @@ class TestInstallHooks:
|
|
|
109
109
|
for e in events["PermissionRequest"] for h in e["hooks"])
|
|
110
110
|
assert any(h["command"].endswith("idle-handler.sh")
|
|
111
111
|
for e in events["Notification"] for h in e["hooks"])
|
|
112
|
+
assert any(h["command"].endswith("session-start-handler.sh")
|
|
113
|
+
for e in events["SessionStart"] for h in e["hooks"])
|
|
112
114
|
|
|
113
115
|
|
|
114
116
|
def test_stale_installed_copy_refreshed(self, env):
|