agentwire-dev 1.56.1__tar.gz → 1.57.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.56.1 → agentwire_dev-1.57.0}/PKG-INFO +1 -1
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/__main__.py +4 -2
- agentwire_dev-1.57.0/agentwire/chrome_tabs.py +124 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/config.py +7 -5
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/core.py +71 -16
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/diff_cli.py +1 -1
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/doctor_cli.py +23 -2
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/ensure_cli.py +11 -1
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +105 -13
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +105 -13
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +105 -13
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +105 -13
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +6 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +105 -13
- agentwire_dev-1.57.0/agentwire/mcp_chrome.py +90 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_server.py +1 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_session.py +38 -1
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_worktree.py +126 -25
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/project_config.py +28 -25
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/__init__.py +56 -26
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/agentwire.md +2 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/contributor.md +1 -1
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/correspondent.md +3 -3
- agentwire_dev-1.56.1/agentwire/roles/worktree-session.md → agentwire_dev-1.57.0/agentwire/roles/worker-worktree.md +11 -8
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/worker.md +4 -2
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/safety/_core.py +105 -13
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/scheduler/dispatch.py +6 -6
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/session_cli.py +488 -121
- agentwire_dev-1.57.0/agentwire/tabs_cli.py +89 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tasks.py +16 -6
- agentwire_dev-1.57.0/agentwire/tasks_cli.py +299 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/worktree.py +41 -10
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/worktree_registry.py +9 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/INDEX.md +3 -3
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/architecture.md +8 -4
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/briefing-mode.md +2 -2
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/glossary.md +2 -2
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/internals/damage-control.md +80 -5
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/internals/parallel-refactor.md +1 -1
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/quickstart.md +5 -1
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/research/briefing-mode-feasibility.md +2 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/scheduling/scheduled-workloads.md +13 -3
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/security/damage-control-hardening.md +12 -4
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/sessions/prompt-routing.md +10 -3
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/sessions/worktree-sessions.md +36 -2
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/integration/test_scheduler_board.py +4 -4
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/integration/test_worktree_cmd.py +330 -2
- agentwire_dev-1.57.0/tests/unit/test_chrome_tabs.py +110 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_cli_commands.py +111 -12
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_control_plane_protection.py +146 -18
- agentwire_dev-1.57.0/tests/unit/test_core_created_by_rooting.py +114 -0
- agentwire_dev-1.57.0/tests/unit/test_dangling_worktrees.py +142 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_mcp_tools_args.py +101 -2
- agentwire_dev-1.57.0/tests/unit/test_posture_default.py +71 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_project_config.py +40 -8
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_roles.py +69 -31
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_scheduler.py +2 -2
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_task_cli.py +2 -2
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_tasks.py +14 -6
- agentwire_dev-1.57.0/tests/unit/test_tasks_cli.py +171 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_worktree.py +61 -0
- agentwire_dev-1.57.0/tests/unit/test_worktree_branch_cleanup.py +165 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/.gitignore +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/AGENTS.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/LICENSE +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/README.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/RELEASING.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/SECURITY.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/channels_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/council/minutes.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/hooks_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/inbox.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_core.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_council.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_msg.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_voiceclone.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/msg_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/notify_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/pane_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/prompt_router.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/desktop.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/safety_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/safety_commands.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/scheduler/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/scheduler/models.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/scheduler/report.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/scheduler/schedule.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/security.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/server.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/session_ready.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/css/desktop.css +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/desktop.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/system_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templates/council/minutes.html.j2 +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/voiceclone.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/logo.png +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/sessions/messaging.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/pyproject.toml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/integration/test_send_verified_tmux.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_council_minutes.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_inbox.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_msg_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_notify_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_pip_environment.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_prompt_router.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_safety_heal.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_session_ready.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_window_cycling_binding.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_worktree_layout.py +0 -0
- {agentwire_dev-1.56.1 → agentwire_dev-1.57.0}/tests/unit/test_worktree_registry.py +0 -0
|
@@ -16,7 +16,6 @@ from . import ( # noqa: E402 # must follow load_dotenv() above
|
|
|
16
16
|
from .core import ( # noqa: E402,F401 # E402: must follow load_dotenv(); F401: re-exported moved helpers
|
|
17
17
|
_UNATTENDED_ENV_KEYS,
|
|
18
18
|
CONFIG_DIR,
|
|
19
|
-
KIND_DEFAULT_POSTURE,
|
|
20
19
|
AgentCommand,
|
|
21
20
|
_add_posture_harness_flags,
|
|
22
21
|
_build_tmux_env_flags,
|
|
@@ -188,10 +187,11 @@ Command Categories:
|
|
|
188
187
|
from . import diff_cli, limits_cli, msg_cli, pane_cli, prompts_cli, send_cli # noqa: I001 # session_cli kept on its own line below to minimize Phase 1 #495 merge conflicts
|
|
189
188
|
from . import session_cli
|
|
190
189
|
from . import channels_cli, config_cli, portal_cli, tts_cli
|
|
191
|
-
from . import scheduler_cli, ensure_cli
|
|
190
|
+
from . import scheduler_cli, ensure_cli, tasks_cli
|
|
192
191
|
from . import doctor_cli, history_cli, machine_cli, safety_cli
|
|
193
192
|
from . import handoff_cli, hooks_cli, mcp_cli, roles_cli, tunnels_cli
|
|
194
193
|
from . import notify_cli, palette_cli, push_cli, repo_cli, system_cli, wiki_cli
|
|
194
|
+
from . import tabs_cli
|
|
195
195
|
from .council import cli as council_cli
|
|
196
196
|
|
|
197
197
|
_REGISTRARS = [ # noqa: N806 # registry constant; Phase 1 of #495 appends here
|
|
@@ -207,6 +207,7 @@ Command Categories:
|
|
|
207
207
|
channels_cli.register_channels_parser,
|
|
208
208
|
scheduler_cli.register_scheduler_parser,
|
|
209
209
|
ensure_cli.register_ensure_parser,
|
|
210
|
+
tasks_cli.register_tasks_parser,
|
|
210
211
|
doctor_cli.register_doctor_parser,
|
|
211
212
|
safety_cli.register_safety_parser,
|
|
212
213
|
machine_cli.register_machine_parser,
|
|
@@ -224,6 +225,7 @@ Command Categories:
|
|
|
224
225
|
repo_cli.register_repo_parser,
|
|
225
226
|
config_cli.register_config_parser,
|
|
226
227
|
palette_cli.register_palette_parser,
|
|
228
|
+
tabs_cli.register_tabs_parser,
|
|
227
229
|
]
|
|
228
230
|
for _reg in _REGISTRARS:
|
|
229
231
|
_reg(subparsers)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Tracks claude-in-chrome tab ids opened by a session (#717).
|
|
2
|
+
|
|
3
|
+
Worktree sessions open claude-in-chrome tabs to e2e-verify their work before
|
|
4
|
+
opening a PR. Those tabs are never closed if the session finishes without
|
|
5
|
+
tidying up after itself, or dies mid-work — this module is pure bookkeeping
|
|
6
|
+
so a crashed session's orphaned tabs can still be identified during teardown.
|
|
7
|
+
|
|
8
|
+
agentwire has no way to call `tabs_close_mcp` itself: that MCP server runs
|
|
9
|
+
inside the CALLING agent's own client, not agentwire's process. So this only
|
|
10
|
+
tracks tab ids; the actual close always happens at the LLM/agent layer —
|
|
11
|
+
either the session closing its own tabs before finishing (the normal path),
|
|
12
|
+
or `worktree_remove` surfacing untracked-but-still-open tab ids to whichever
|
|
13
|
+
agent runs the teardown (the crash backstop).
|
|
14
|
+
|
|
15
|
+
Layout: one JSON file (``~/.agentwire/chrome-tabs.json``), keyed by session
|
|
16
|
+
name -> list of ``{tab_id, url, tracked_at}``. Plain JSON, hand-editable.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import contextlib
|
|
20
|
+
import datetime
|
|
21
|
+
import fcntl
|
|
22
|
+
import json
|
|
23
|
+
import os
|
|
24
|
+
import tempfile
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
REGISTRY_FILE = Path.home() / ".agentwire" / "chrome-tabs.json"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@contextlib.contextmanager
|
|
31
|
+
def _locked():
|
|
32
|
+
"""Serialize read-modify-write across processes via an flock sidecar."""
|
|
33
|
+
REGISTRY_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
34
|
+
lock_path = REGISTRY_FILE.with_suffix(REGISTRY_FILE.suffix + ".lock")
|
|
35
|
+
fd = os.open(str(lock_path), os.O_CREAT | os.O_RDWR, 0o644)
|
|
36
|
+
try:
|
|
37
|
+
fcntl.flock(fd, fcntl.LOCK_EX)
|
|
38
|
+
yield
|
|
39
|
+
finally:
|
|
40
|
+
fcntl.flock(fd, fcntl.LOCK_UN)
|
|
41
|
+
os.close(fd)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _load() -> dict:
|
|
45
|
+
if not REGISTRY_FILE.exists():
|
|
46
|
+
return {}
|
|
47
|
+
try:
|
|
48
|
+
data = json.loads(REGISTRY_FILE.read_text())
|
|
49
|
+
return data if isinstance(data, dict) else {}
|
|
50
|
+
except (json.JSONDecodeError, OSError):
|
|
51
|
+
return {}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _save(data: dict) -> None:
|
|
55
|
+
"""Atomically write the registry (temp file in same dir + os.replace)."""
|
|
56
|
+
REGISTRY_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
payload = json.dumps(data, indent=2) + "\n"
|
|
58
|
+
fd, tmp = tempfile.mkstemp(dir=str(REGISTRY_FILE.parent), prefix=REGISTRY_FILE.name + ".", suffix=".tmp")
|
|
59
|
+
try:
|
|
60
|
+
with os.fdopen(fd, "w") as f:
|
|
61
|
+
f.write(payload)
|
|
62
|
+
f.flush()
|
|
63
|
+
os.fsync(f.fileno())
|
|
64
|
+
os.replace(tmp, REGISTRY_FILE) # atomic on POSIX
|
|
65
|
+
except BaseException:
|
|
66
|
+
with contextlib.suppress(OSError):
|
|
67
|
+
os.unlink(tmp)
|
|
68
|
+
raise
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def track(session: str, tab_id: str, url: str | None = None) -> dict:
|
|
72
|
+
"""Record that ``session`` opened claude-in-chrome tab ``tab_id``.
|
|
73
|
+
|
|
74
|
+
Idempotent per (session, tab_id) — re-tracking the same tab just refreshes
|
|
75
|
+
its entry rather than duplicating it.
|
|
76
|
+
"""
|
|
77
|
+
entry = {
|
|
78
|
+
"tab_id": tab_id,
|
|
79
|
+
"url": url,
|
|
80
|
+
"tracked_at": datetime.datetime.now().astimezone().isoformat(timespec="seconds"),
|
|
81
|
+
}
|
|
82
|
+
with _locked():
|
|
83
|
+
data = _load()
|
|
84
|
+
tabs = [t for t in data.get(session, []) if t.get("tab_id") != tab_id]
|
|
85
|
+
tabs.append(entry)
|
|
86
|
+
data[session] = tabs
|
|
87
|
+
_save(data)
|
|
88
|
+
return entry
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def untrack(session: str, tab_id: str) -> bool:
|
|
92
|
+
"""Drop a tracked tab (the session closed it itself). Returns whether it was tracked."""
|
|
93
|
+
with _locked():
|
|
94
|
+
data = _load()
|
|
95
|
+
tabs = data.get(session, [])
|
|
96
|
+
remaining = [t for t in tabs if t.get("tab_id") != tab_id]
|
|
97
|
+
removed = len(remaining) != len(tabs)
|
|
98
|
+
if remaining:
|
|
99
|
+
data[session] = remaining
|
|
100
|
+
else:
|
|
101
|
+
data.pop(session, None)
|
|
102
|
+
if removed:
|
|
103
|
+
_save(data)
|
|
104
|
+
return removed
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def tabs_for(session: str) -> list[dict]:
|
|
108
|
+
"""All tracked tabs for a session (read-only)."""
|
|
109
|
+
return _load().get(session, [])
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def clear(session: str) -> list[dict]:
|
|
113
|
+
"""Drop + return every tracked tab for a session — the teardown backstop."""
|
|
114
|
+
with _locked():
|
|
115
|
+
data = _load()
|
|
116
|
+
tabs = data.pop(session, [])
|
|
117
|
+
if tabs:
|
|
118
|
+
_save(data)
|
|
119
|
+
return tabs
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def all_tabs() -> dict[str, list[dict]]:
|
|
123
|
+
"""Every session -> tracked-tabs mapping (read-only, for listing/debugging)."""
|
|
124
|
+
return _load()
|
|
@@ -101,9 +101,11 @@ class WorktreesConfig:
|
|
|
101
101
|
# Gitignored files that `git worktree add` won't carry over (it only
|
|
102
102
|
# checks out tracked files). These are copied from the main repo into
|
|
103
103
|
# each fresh worktree so agents have the secrets/config they need.
|
|
104
|
-
# .agentwire.yml
|
|
105
|
-
# load their task
|
|
106
|
-
|
|
104
|
+
# .agentwire.yml/.agentwire.tasks.yml are included because worktree-dispatched
|
|
105
|
+
# tasks can't load their session/task config without them when the project
|
|
106
|
+
# gitignores them (the latter is the protected, host-authored task-exec file —
|
|
107
|
+
# #720).
|
|
108
|
+
copy_files: list = field(default_factory=lambda: [".env", ".agentwire.yml", ".agentwire.tasks.yml"])
|
|
107
109
|
|
|
108
110
|
|
|
109
111
|
@dataclass
|
|
@@ -120,7 +122,7 @@ class ProjectsConfig:
|
|
|
120
122
|
|
|
121
123
|
@dataclass
|
|
122
124
|
class WorktreeConfig:
|
|
123
|
-
"""Standalone worktree
|
|
125
|
+
"""Standalone worktree session orchestration (`worktree:` config key).
|
|
124
126
|
|
|
125
127
|
Governs `agentwire worktree <name>` — the first-class primitive for
|
|
126
128
|
spawning an isolated branch+worktree+session for one unit of work.
|
|
@@ -621,7 +623,7 @@ def _dict_to_config(data: dict) -> Config:
|
|
|
621
623
|
enabled=worktrees_data.get("enabled", True),
|
|
622
624
|
suffix=worktrees_data.get("suffix", "-worktrees"),
|
|
623
625
|
auto_create_branch=worktrees_data.get("auto_create_branch", True),
|
|
624
|
-
copy_files=worktrees_data.get("copy_files", [".env", ".agentwire.yml"]),
|
|
626
|
+
copy_files=worktrees_data.get("copy_files", [".env", ".agentwire.yml", ".agentwire.tasks.yml"]),
|
|
625
627
|
)
|
|
626
628
|
projects = ProjectsConfig(
|
|
627
629
|
dir=projects_data.get("dir", "~/projects"),
|
|
@@ -28,7 +28,7 @@ from .project_config import (
|
|
|
28
28
|
normalize_session_type,
|
|
29
29
|
)
|
|
30
30
|
from .roles import RoleConfig, merge_roles
|
|
31
|
-
from .worktree import parse_session_name
|
|
31
|
+
from .worktree import git_common_dir, parse_session_name
|
|
32
32
|
|
|
33
33
|
# Default config directory
|
|
34
34
|
CONFIG_DIR = Path.home() / ".agentwire"
|
|
@@ -489,16 +489,30 @@ def wait_for_shell_prompt(target: str, timeout: float = 2.0) -> None:
|
|
|
489
489
|
time.sleep(0.05)
|
|
490
490
|
|
|
491
491
|
|
|
492
|
+
def _live_session_cwd(session: str) -> Path | None:
|
|
493
|
+
"""The session's current pane cwd, or None if it isn't a live tmux session.
|
|
494
|
+
|
|
495
|
+
Unlike ``_get_session_project_path``, this never falls back to guessing a
|
|
496
|
+
path from the session name — a guessed path is unsafe for an identity
|
|
497
|
+
comparison (#715's same-project check needs the real cwd or nothing).
|
|
498
|
+
"""
|
|
499
|
+
if not tmux_session_exists(session):
|
|
500
|
+
return None
|
|
501
|
+
result = subprocess.run(
|
|
502
|
+
["tmux", "display-message", "-t", session, "-p", "#{pane_current_path}"],
|
|
503
|
+
capture_output=True,
|
|
504
|
+
text=True,
|
|
505
|
+
)
|
|
506
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
507
|
+
return Path(result.stdout.strip())
|
|
508
|
+
return None
|
|
509
|
+
|
|
510
|
+
|
|
492
511
|
def _get_session_project_path(session: str) -> Path | None:
|
|
493
512
|
"""Get a session's project path from tmux cwd, falling back to session name parsing."""
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
capture_output=True,
|
|
498
|
-
text=True,
|
|
499
|
-
)
|
|
500
|
-
if result.returncode == 0 and result.stdout.strip():
|
|
501
|
-
return Path(result.stdout.strip())
|
|
513
|
+
live = _live_session_cwd(session)
|
|
514
|
+
if live is not None:
|
|
515
|
+
return live
|
|
502
516
|
|
|
503
517
|
# Fallback: derive from session name
|
|
504
518
|
config = load_config()
|
|
@@ -507,6 +521,41 @@ def _get_session_project_path(session: str) -> Path | None:
|
|
|
507
521
|
return projects_dir / project
|
|
508
522
|
|
|
509
523
|
|
|
524
|
+
def _same_project(path_a: Path, path_b: Path) -> bool:
|
|
525
|
+
"""True when two paths belong to the same git repo (shared .git dir
|
|
526
|
+
across linked worktrees) or, outside a repo, are the same resolved path."""
|
|
527
|
+
common_a = git_common_dir(path_a)
|
|
528
|
+
if common_a is None:
|
|
529
|
+
return path_a.resolve() == path_b.resolve()
|
|
530
|
+
common_b = git_common_dir(path_b)
|
|
531
|
+
if common_b is None:
|
|
532
|
+
return path_a.resolve() == path_b.resolve()
|
|
533
|
+
return common_a == common_b
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
def resolve_default_created_by(caller: str | None, target_path: Path) -> str | None:
|
|
537
|
+
"""The default ``created_by`` when none was explicitly given.
|
|
538
|
+
|
|
539
|
+
Inherit the caller only when the new session's project is the one the
|
|
540
|
+
caller is already running in — a cross-project spawn gets its own root
|
|
541
|
+
instead of flattening into the caller's subtree (#715). An explicit
|
|
542
|
+
--created-by always wins and never reaches this function.
|
|
543
|
+
|
|
544
|
+
Uses ``_live_session_cwd`` rather than ``_get_session_project_path`` —
|
|
545
|
+
the latter's session-name-guessing fallback isn't a safe basis for an
|
|
546
|
+
identity comparison (it doesn't understand the worktree naming scheme,
|
|
547
|
+
`{project}-{name}`, and would misjudge same/cross-project); if the
|
|
548
|
+
caller's real cwd can't be confirmed, treat it as unknown (no inheritance)
|
|
549
|
+
rather than risk a wrong guess.
|
|
550
|
+
"""
|
|
551
|
+
if not caller:
|
|
552
|
+
return None
|
|
553
|
+
caller_path = _live_session_cwd(caller)
|
|
554
|
+
if caller_path is None:
|
|
555
|
+
return None
|
|
556
|
+
return caller if _same_project(caller_path, target_path) else None
|
|
557
|
+
|
|
558
|
+
|
|
510
559
|
def tmux_session_has_agent(name: str) -> bool:
|
|
511
560
|
"""Check if a tmux session has an agent running (not just a bare shell).
|
|
512
561
|
|
|
@@ -1135,14 +1184,20 @@ def _post_desktop_notification(text: str, session: str | None = None, priority:
|
|
|
1135
1184
|
return False
|
|
1136
1185
|
|
|
1137
1186
|
|
|
1138
|
-
|
|
1139
|
-
"
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1187
|
+
def _default_posture(kind: str | None, worktree_topology: bool = False) -> str:
|
|
1188
|
+
"""Default posture for a spawn: bypass, unless it's a worker that is NOT
|
|
1189
|
+
isolated on its own worktree — a pane (agentwire spawn) or a worker on
|
|
1190
|
+
plain main topology, both sharing a live checkout someone else may be
|
|
1191
|
+
watching, stay restricted. Orchestrators (main or worktree topology) and
|
|
1192
|
+
worktree-topology workers get full autonomous access — nothing to step
|
|
1193
|
+
on but their own isolated branch.
|
|
1194
|
+
"""
|
|
1195
|
+
if kind == "worker" and not worktree_topology:
|
|
1196
|
+
return "restricted"
|
|
1197
|
+
return "bypass"
|
|
1143
1198
|
|
|
1144
1199
|
|
|
1145
|
-
def _resolve_session_type_from_args(args, kind: str) -> tuple[str | None, str | None]:
|
|
1200
|
+
def _resolve_session_type_from_args(args, kind: str, worktree_topology: bool = False) -> tuple[str | None, str | None]:
|
|
1146
1201
|
"""Resolve the internal fused session type from the shared flag core.
|
|
1147
1202
|
|
|
1148
1203
|
Posture × harness are the canonical axes; legacy --type (fused strings or
|
|
@@ -1158,7 +1213,7 @@ def _resolve_session_type_from_args(args, kind: str) -> tuple[str | None, str |
|
|
|
1158
1213
|
posture = getattr(args, 'posture', None)
|
|
1159
1214
|
harness = getattr(args, 'harness', None)
|
|
1160
1215
|
type_arg = getattr(args, 'type', None)
|
|
1161
|
-
default_posture =
|
|
1216
|
+
default_posture = _default_posture(kind, worktree_topology)
|
|
1162
1217
|
|
|
1163
1218
|
if posture or harness:
|
|
1164
1219
|
try:
|
|
@@ -29,7 +29,7 @@ Output shape (``--json``)::
|
|
|
29
29
|
|
|
30
30
|
Base resolution (no ``--base``): if the worktree has uncommitted changes the
|
|
31
31
|
diff is vs ``HEAD`` (what the agent just did, not yet committed); otherwise it
|
|
32
|
-
is vs ``origin/main`` (a worktree
|
|
32
|
+
is vs ``origin/main`` (a worktree session's committed branch work). The portal
|
|
33
33
|
relies on this so a phone review needs zero flags.
|
|
34
34
|
"""
|
|
35
35
|
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
``doctor`` walks the full install (Python/deps, hooks, skills, damage control,
|
|
4
4
|
source-checkout drift, services, config, SSH/tunnels, voice loop, secrets,
|
|
5
|
-
remote machines, dead-lettered messages
|
|
6
|
-
ones. ``network status`` is the read-only
|
|
5
|
+
remote machines, dead-lettered messages, dangling worktree sessions) and
|
|
6
|
+
optionally auto-fixes the local ones. ``network status`` is the read-only
|
|
7
|
+
network-health glance.
|
|
7
8
|
|
|
8
9
|
The hook/skill drift helpers (``get_hooks_source``, ``_managed_hook_files``,
|
|
9
10
|
``_managed_file_state``, ``skill_drift``, ``CLAUDE_SKILLS_DIR``) are owned by
|
|
@@ -869,6 +870,26 @@ def cmd_doctor(args) -> int:
|
|
|
869
870
|
except Exception as e:
|
|
870
871
|
print(f" [..] Could not check dead-lettered messages: {e}")
|
|
871
872
|
|
|
873
|
+
# 11. Check for dangling worktree sessions (live, open PR, no live parent
|
|
874
|
+
# to review/merge it — #716's concrete failure mode: a rootless-but-
|
|
875
|
+
# still-subordinate session that correctly refuses to self-merge).
|
|
876
|
+
print("\nChecking for dangling worktree sessions...")
|
|
877
|
+
try:
|
|
878
|
+
from . import worktree_registry
|
|
879
|
+
from .session_cli import scan_dangling_worktrees
|
|
880
|
+
|
|
881
|
+
dangling = scan_dangling_worktrees(worktree_registry.all_entries())
|
|
882
|
+
if not dangling:
|
|
883
|
+
print(" [ok] No dangling worktree sessions found")
|
|
884
|
+
else:
|
|
885
|
+
issues_found += 1
|
|
886
|
+
print(f" [!!] {len(dangling)} live worktree session(s) with an open PR and no live parent:")
|
|
887
|
+
for d in dangling:
|
|
888
|
+
print(f" - {d['session']} branch={d['branch']} {d.get('pr_url', '')} ({d['reason']})")
|
|
889
|
+
print(" Assign a parent (agentwire msg send / --created-by) or merge/close the PR yourself.")
|
|
890
|
+
except Exception as e:
|
|
891
|
+
print(f" [..] Could not check for dangling worktree sessions: {e}")
|
|
892
|
+
|
|
872
893
|
# Summary
|
|
873
894
|
print()
|
|
874
895
|
print("-" * 60)
|
|
@@ -492,6 +492,16 @@ def _run_ensure_task(args, session, task, ctx, shell, project_path, json_mode) -
|
|
|
492
492
|
self.roles = task_role if task_role else None
|
|
493
493
|
self.model = None
|
|
494
494
|
self.json = json_mode
|
|
495
|
+
# Force the pre-#715 unconditional-inherit behavior:
|
|
496
|
+
# ensure is the scheduler's dispatch primitive — the
|
|
497
|
+
# scheduler daemon fans out across many projects from
|
|
498
|
+
# one fixed tmux session by design, so #715's
|
|
499
|
+
# same-project default (meant for an interactive
|
|
500
|
+
# session's own cross-project spawns) would wrongly
|
|
501
|
+
# drop the parent link for nearly every dispatched
|
|
502
|
+
# task. Always parent to whichever session is
|
|
503
|
+
# actually running this ensure call.
|
|
504
|
+
self.created_by = pane_manager.get_current_session()
|
|
495
505
|
|
|
496
506
|
from . import session_cli
|
|
497
507
|
result = session_cli.cmd_new(NewArgs(task.role))
|
|
@@ -739,7 +749,7 @@ def cmd_task_list(args) -> int:
|
|
|
739
749
|
return 0
|
|
740
750
|
|
|
741
751
|
if not tasks:
|
|
742
|
-
print(f"No tasks defined in {project_path / '.agentwire.yml'}")
|
|
752
|
+
print(f"No tasks defined in {project_path / '.agentwire.tasks.yml'}")
|
|
743
753
|
return 0
|
|
744
754
|
|
|
745
755
|
print(f"Tasks in {project_path.name}:\n")
|
|
@@ -766,12 +766,16 @@ PROTECTED_CONTROL_PLANE_PATHS = [
|
|
|
766
766
|
# confused-deputy escape). Treat them as control plane (#466 lockdown).
|
|
767
767
|
"~/.agentwire/scheduler.yaml", # scheduler gate commands run via shell
|
|
768
768
|
"~/.agentwire/config.yaml", # service healthcheck commands run via shell
|
|
769
|
-
# Per-project task config: ``.agentwire.yml
|
|
770
|
-
#
|
|
771
|
-
#
|
|
772
|
-
#
|
|
773
|
-
#
|
|
774
|
-
|
|
769
|
+
# Per-project task-EXECUTION config (#720): split out of ``.agentwire.yml``,
|
|
770
|
+
# which is now purely declarative (type/roles/voice/parent/worktree) and
|
|
771
|
+
# agent-writable again — it carries no exec vector. ``.agentwire.tasks.yml``
|
|
772
|
+
# holds the ``tasks:`` block (pre/post/on_task_end/shell/unattended_allow),
|
|
773
|
+
# which agentwire runs the same way (confused-deputy risk above), so it
|
|
774
|
+
# stays protected. Authored via propose-and-promote: an agent drafts to the
|
|
775
|
+
# UNPROTECTED ``.agentwire.tasks.proposed.yml`` staging file; a human reviews
|
|
776
|
+
# (``agentwire tasks review``) and promotes (``agentwire tasks promote``) —
|
|
777
|
+
# the agent never writes the live file. See ``agentwire/tasks_cli.py``.
|
|
778
|
+
"*.agentwire.tasks.yml", # project task-execution config (any dir)
|
|
775
779
|
]
|
|
776
780
|
|
|
777
781
|
|
|
@@ -791,12 +795,33 @@ def _protected_path_patterns() -> List[str]:
|
|
|
791
795
|
return out
|
|
792
796
|
|
|
793
797
|
|
|
794
|
-
def
|
|
795
|
-
"""
|
|
798
|
+
def _matched_protected_pattern(file_path: str) -> Optional[str]:
|
|
799
|
+
"""The protected-path pattern that matches ``file_path``, if any."""
|
|
796
800
|
for pat in _protected_path_patterns():
|
|
797
801
|
if match_path(file_path, pat):
|
|
798
|
-
return
|
|
799
|
-
return
|
|
802
|
+
return pat
|
|
803
|
+
return None
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
def is_protected_control_plane(file_path: str) -> bool:
|
|
807
|
+
"""True if ``file_path`` is part of the damage-control control plane."""
|
|
808
|
+
return _matched_protected_pattern(file_path) is not None
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
def _protected_reason(matched_pattern: str) -> str:
|
|
812
|
+
"""Block reason for a protected-control-plane hit, tailored to the path.
|
|
813
|
+
|
|
814
|
+
``.agentwire.tasks.yml`` has a real, host-side remedy (propose-and-promote,
|
|
815
|
+
#720) — name it so the agent doesn't dead-end. Everything else keeps the
|
|
816
|
+
generic "edit on the host" message.
|
|
817
|
+
"""
|
|
818
|
+
if matched_pattern.endswith(".agentwire.tasks.yml"):
|
|
819
|
+
return (
|
|
820
|
+
"protected task-execution control-plane file (host-owned) — draft "
|
|
821
|
+
"to .agentwire.tasks.proposed.yml instead, then ask the host to run "
|
|
822
|
+
"`agentwire tasks review` and `agentwire tasks promote`"
|
|
823
|
+
)
|
|
824
|
+
return "protected control-plane file (host-owned; edit on the host)"
|
|
800
825
|
|
|
801
826
|
|
|
802
827
|
def check_protected_path(
|
|
@@ -808,10 +833,11 @@ def check_protected_path(
|
|
|
808
833
|
Used by the edit/write hooks. The allowlist (a human opt-in) may override;
|
|
809
834
|
nothing else does.
|
|
810
835
|
"""
|
|
811
|
-
|
|
836
|
+
matched = _matched_protected_pattern(file_path)
|
|
837
|
+
if matched:
|
|
812
838
|
if is_path_allowed_for_op(file_path, allowed_paths, "edit"):
|
|
813
839
|
return False, ""
|
|
814
|
-
return True,
|
|
840
|
+
return True, _protected_reason(matched)
|
|
815
841
|
return False, ""
|
|
816
842
|
|
|
817
843
|
|
|
@@ -841,7 +867,58 @@ def check_protected_command(
|
|
|
841
867
|
op = _infer_operation_from_reason(reason)
|
|
842
868
|
if is_command_path_allowed(command, allowed_paths, op):
|
|
843
869
|
break
|
|
844
|
-
return True,
|
|
870
|
+
return True, _protected_reason(path)
|
|
871
|
+
return False, ""
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
# ============================================================================
|
|
875
|
+
# PROTECTED COMMANDS (escape-hatch- AND kill-switch-EXEMPT, like the protected
|
|
876
|
+
# control plane above, but keyed on COMMAND SHAPE rather than a file path)
|
|
877
|
+
# ============================================================================
|
|
878
|
+
#
|
|
879
|
+
# Some operations are dangerous no matter which file they touch — running
|
|
880
|
+
# them at all IS the confused-deputy escape, not merely writing a particular
|
|
881
|
+
# path. ``agentwire tasks promote`` is the first case (#720/#721 review):
|
|
882
|
+
# it's the host-trusted program that copies a vetted draft into the protected
|
|
883
|
+
# ``.agentwire.tasks.yml``. If a policed/unattended agent could just invoke
|
|
884
|
+
# the CLI itself, the file protection above is moot — so this, like the
|
|
885
|
+
# protected-path check, is evaluated before ``detect_escape_hatch`` and the
|
|
886
|
+
# kill switch, and has NO allowlist override (there's no legitimate reason
|
|
887
|
+
# for an agent to ever run this; unlike a path, there's nothing to allowlist
|
|
888
|
+
# it TO). This is defense in depth on TOP OF ``cmd_tasks_promote``'s own
|
|
889
|
+
# runtime refusal (unattended check + host-context gate in ``tasks_cli.py``)
|
|
890
|
+
# — that second gate is what actually closes the ``python3 -c
|
|
891
|
+
# "from agentwire.tasks_cli import cmd_tasks_promote; ..."`` bypass, since a
|
|
892
|
+
# raw interpreter call never matches a bash command pattern at all.
|
|
893
|
+
|
|
894
|
+
PROTECTED_COMMAND_PATTERNS: List[Tuple[str, str]] = [
|
|
895
|
+
(
|
|
896
|
+
r'\bagentwire\s+tasks\s+promote\b',
|
|
897
|
+
"agentwire tasks promote writes the protected .agentwire.tasks.yml — "
|
|
898
|
+
"host-only, run it from your own terminal (not through an agent).",
|
|
899
|
+
),
|
|
900
|
+
]
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
def check_protected_bash_command(command: str) -> Tuple[bool, str]:
|
|
904
|
+
"""Block a command matching a ``PROTECTED_COMMAND_PATTERNS`` entry.
|
|
905
|
+
|
|
906
|
+
Unconditional — no allowlist override, no escape hatch, no kill switch
|
|
907
|
+
(see module note above). These are COMMAND-PREFIX patterns, so — like the
|
|
908
|
+
``anchored`` tooldef bashToolPatterns (#675) — matched only against
|
|
909
|
+
``masked_subcommands``: quoting/escaping of the command itself still
|
|
910
|
+
normalizes to the literal form (``agentwire tasks prom''ote`` can't sneak
|
|
911
|
+
past), but quoted CONTENT (a commit message, an echo string) that merely
|
|
912
|
+
*mentions* the phrase is masked out first, so it can't false-match.
|
|
913
|
+
"""
|
|
914
|
+
haystacks = masked_subcommands(command)
|
|
915
|
+
for pattern, reason in PROTECTED_COMMAND_PATTERNS:
|
|
916
|
+
for hay in haystacks:
|
|
917
|
+
try:
|
|
918
|
+
if re.search(pattern, hay, re.IGNORECASE):
|
|
919
|
+
return True, reason
|
|
920
|
+
except re.error:
|
|
921
|
+
continue
|
|
845
922
|
return False, ""
|
|
846
923
|
|
|
847
924
|
|
|
@@ -1121,6 +1198,8 @@ def check_command(command: str, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
1121
1198
|
0. Protected control plane → BLOCK (escape-hatch- AND kill-switch-exempt;
|
|
1122
1199
|
only the user's allowlist re-permits) — runs FIRST so an agent can't
|
|
1123
1200
|
self-authorize a write to the files that gate everything else.
|
|
1201
|
+
0.5. Protected commands → BLOCK (same exemption, no allowlist override —
|
|
1202
|
+
a command whose mere invocation is the escape, not a path it touches).
|
|
1124
1203
|
1. Escape hatch (``# allow: <reason>``) → ALLOW (escape=True)
|
|
1125
1204
|
2. Kill switch (``config["safety"]["enabled"] is False``) → ALLOW (disabled=True)
|
|
1126
1205
|
3. Hard-blocked bash patterns (skip if ``id`` in ``disabled_rules``)
|
|
@@ -1149,6 +1228,19 @@ def check_command(command: str, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
1149
1228
|
"protected": True,
|
|
1150
1229
|
}
|
|
1151
1230
|
|
|
1231
|
+
# Protected COMMANDS — same tier, same reason (an agent-invoked
|
|
1232
|
+
# `agentwire tasks promote` is the confused-deputy escape itself, not a
|
|
1233
|
+
# path it happens to touch).
|
|
1234
|
+
cmd_blocked, cmd_reason = check_protected_bash_command(command)
|
|
1235
|
+
if cmd_blocked:
|
|
1236
|
+
return {
|
|
1237
|
+
"decision": "block",
|
|
1238
|
+
"reason": cmd_reason,
|
|
1239
|
+
"pattern": "protectedCommand",
|
|
1240
|
+
"command": command,
|
|
1241
|
+
"protected": True,
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1152
1244
|
# Parser unavailable ⇒ no rules loaded ⇒ fail closed (block), before the
|
|
1153
1245
|
# escape hatch / kill switch can wave it through.
|
|
1154
1246
|
if config.get("_parser_unavailable"):
|