agentwire-dev 1.65.1__tar.gz → 1.65.3__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.65.1 → agentwire_dev-1.65.3}/PKG-INFO +1 -1
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_core.py +23 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_session.py +5 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/desktop.py +17 -1
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/send_cli.py +87 -5
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/server.py +14 -3
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/session_cli.py +23 -3
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/session_ready.py +15 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/desktop.js +19 -1
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/notifications-panel.js +12 -3
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/worktree.py +33 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/integration/test_worktree_cmd.py +32 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_cli_commands.py +161 -8
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_mcp_server.py +51 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_mcp_tools_args.py +33 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_portal_api.py +133 -3
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_session_ready.py +22 -1
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_worktree.py +43 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/.gitignore +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/AGENTS.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/Dockerfile.local +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/LICENSE +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/README.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/RELEASING.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/SECURITY.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/SPONSORS.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/__main__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/channels_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/chrome_tabs.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/completion.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/config.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/core.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/council/minutes.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/devices.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/doctor_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/history.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/hooks_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/inbox.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/listen.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/locking.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_chrome.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_council.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_msg.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/mcp_worktree.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/msg_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/network.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/notify_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/pane_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/projects.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/prompt_router.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/research.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/contributor.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/reviewer-worktree.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/reviewer.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/worker-worktree.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/safety/_core.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/safety_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/safety_commands.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scheduler/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scheduler/dispatch.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scheduler/models.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scheduler/report.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scheduler/schedule.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scheduler/zombie.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/security.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/services.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/css/desktop.css +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/card-terminal.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/lineage.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/session-hud-controller.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/session-hud-notices.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/session-hud-spawn.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/session-hud.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/spawn-ghost.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/terminal-pane.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/topology-render.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/utils/rich-text.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/js/workspace-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/static/topology-harness.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/system_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tabs_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tasks_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templates/council/minutes.html.j2 +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/templating.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/validation.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/design/session-card-fields.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/design/session-card-recommendation.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/logo.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/internals/session-topology.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/sessions/messaging.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/sessions/worktree-sessions.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/pyproject.toml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/conftest.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/integration/test_send_verified_tmux.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_chrome_tabs.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_control_plane_protection.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_core_created_by_rooting.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_council_minutes.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_dangling_worktrees.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_doctor_scheduler_staleness.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_doctor_task_migration.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_guarded_launch_command.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_inbox.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_msg_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_notify_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_pip_environment.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_posture_default.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_projects_registry.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_prompt_router.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_rich_text_js.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_safety_heal.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_scheduler_zombie.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_session_created_by_env.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_shim_selfheal.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_tasks_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_window_cycling_binding.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_worktree_branch_cleanup.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_worktree_layout.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.3}/tests/unit/test_worktree_registry.py +0 -0
|
@@ -162,11 +162,34 @@ def _delivery_result(data: dict, where: str) -> str:
|
|
|
162
162
|
returns ``verified``: True (landed), False (sent but not seen — likely a
|
|
163
163
|
busy/booting pane that dropped it), or None (remote — unverifiable across
|
|
164
164
|
SSH). Surface that instead of a blind "sent".
|
|
165
|
+
|
|
166
|
+
A ``False`` verify from a *session*-level send no longer just hands the
|
|
167
|
+
problem back to whichever caller reads this string (#834) — the CLI
|
|
168
|
+
falls back to the durable msg inbox (retried across ticks, dead-lettered
|
|
169
|
+
+ emailed on true exhaustion) when the direct paste can't be confirmed,
|
|
170
|
+
so report THAT outcome rather than telling the caller to notice and
|
|
171
|
+
resend by hand. A worker *pane* send has no such fallback (the msg inbox
|
|
172
|
+
only addresses sessions, not individual panes) — ``data`` won't carry a
|
|
173
|
+
``fallback`` key at all in that case, distinguishing "not attempted"
|
|
174
|
+
from "attempted and failed" so this never claims a fallback that never
|
|
175
|
+
ran.
|
|
165
176
|
"""
|
|
166
177
|
verified = data.get("verified")
|
|
167
178
|
if verified is True:
|
|
168
179
|
return f"Message delivered {where} (verified in pane)."
|
|
169
180
|
if verified is False:
|
|
181
|
+
if "fallback" in data:
|
|
182
|
+
if data.get("fallback") == "already_delivered":
|
|
183
|
+
return (f"Message sent {where} — the pane confirmation was ambiguous, but the "
|
|
184
|
+
f"message is already visible on scrollback, so it was in fact delivered. "
|
|
185
|
+
f"No action needed.")
|
|
186
|
+
if data.get("fallback") == "inbox":
|
|
187
|
+
return (f"Message sent {where} but delivery could NOT be verified in the pane — "
|
|
188
|
+
f"queued to its msg inbox instead, which guarantees delivery (retried "
|
|
189
|
+
f"automatically, dead-lettered + emailed to the owner only if it truly "
|
|
190
|
+
f"can't land). No action needed.")
|
|
191
|
+
return (f"Message sent {where} but delivery could NOT be verified, AND the msg-inbox "
|
|
192
|
+
f"fallback also failed — this message may be lost. Check the pane or resend.")
|
|
170
193
|
return (f"Message sent {where} but delivery could NOT be verified — it may "
|
|
171
194
|
f"have been dropped (busy/booting pane). Check the pane or resend.")
|
|
172
195
|
if verified is None and "verified" in data:
|
|
@@ -227,6 +227,11 @@ def session_send(session: str, message: str) -> str:
|
|
|
227
227
|
f"{message}"
|
|
228
228
|
)
|
|
229
229
|
args = ["send", "-s", session, "--verify", message]
|
|
230
|
+
if caller:
|
|
231
|
+
# Attributes a msg-inbox delivery fallback to the real caller instead
|
|
232
|
+
# of the generic "agentwire" (#835 review) — the CLI subprocess can't
|
|
233
|
+
# auto-detect the caller across the MCP boundary itself.
|
|
234
|
+
args.extend(["--caller-session", caller])
|
|
230
235
|
data = run_agentwire_cmd(args)
|
|
231
236
|
if not data.get("success"):
|
|
232
237
|
return f"Failed to send message: {data.get('error', 'Unknown error')}"
|
|
@@ -10,6 +10,22 @@ through the composed server's MRO.
|
|
|
10
10
|
from aiohttp import web
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
def _artifact_url_hash(url: str) -> str:
|
|
14
|
+
"""FNV-1a 32-bit hash of ``url``, as 8 lowercase hex chars.
|
|
15
|
+
|
|
16
|
+
Must match ``artifactUrlHash`` in static/js/desktop.js byte-for-byte —
|
|
17
|
+
the server and frontend both derive the same fallback artifact id from
|
|
18
|
+
the same URL, and a naive char-substitution slug (the prior approach)
|
|
19
|
+
let distinct URLs like "reports/jan.html" and "reports-jan.html" collide
|
|
20
|
+
onto the same id. A hash isn't lossy the way substitution is.
|
|
21
|
+
"""
|
|
22
|
+
h = 0x811C9DC5
|
|
23
|
+
for b in url.encode("utf-8"):
|
|
24
|
+
h ^= b
|
|
25
|
+
h = (h * 0x01000193) & 0xFFFFFFFF
|
|
26
|
+
return f"{h:08x}"
|
|
27
|
+
|
|
28
|
+
|
|
13
29
|
class DesktopRoutesMixin:
|
|
14
30
|
async def api_desktop_windows(self, request):
|
|
15
31
|
"""GET /api/desktop/windows — query browser clients for open windows."""
|
|
@@ -173,7 +189,7 @@ class DesktopRoutesMixin:
|
|
|
173
189
|
"url": url,
|
|
174
190
|
"title": title,
|
|
175
191
|
"artifact_id": artifact.get("artifact_id")
|
|
176
|
-
or f"artifact-{url
|
|
192
|
+
or f"artifact-{_artifact_url_hash(url)}",
|
|
177
193
|
}
|
|
178
194
|
if not text:
|
|
179
195
|
text = f"**{title}** is ready — click to open"
|
|
@@ -24,6 +24,60 @@ from .core import (
|
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
def _recover_unverified_send(session: str, prompt: str, sender: str) -> "str | None":
|
|
28
|
+
"""Fallback when `send_verified` can't confirm delivery (#834, #835 review).
|
|
29
|
+
|
|
30
|
+
First checks whether the bare message is already on scrollback outside
|
|
31
|
+
the input box. A `send_verified` failure can mean the paste genuinely
|
|
32
|
+
never landed/submitted, OR that it fully submitted and only the
|
|
33
|
+
*confirm* read was ambiguous (an unparseable box frame, or a laggy host
|
|
34
|
+
blowing the submit budget). The msg-inbox drain's own dedup can't catch
|
|
35
|
+
the latter case on its own: it matches the WRAPPED ``[MSG from ... ]
|
|
36
|
+
... <id>`` render (see ``inbox.Message.render``), never the bare text
|
|
37
|
+
this path pasted directly — enqueuing unconditionally would risk a real
|
|
38
|
+
duplicate delivery rather than the safe no-op the drain's dedup gives
|
|
39
|
+
its own messages. Checking here first avoids that duplicate in the
|
|
40
|
+
common case.
|
|
41
|
+
|
|
42
|
+
A message that lands only *after* this check runs (queued invisibly
|
|
43
|
+
mid-generation, per ``submit_confirmed``'s own docstring) can still
|
|
44
|
+
duplicate — accepted per this codebase's existing bias that a
|
|
45
|
+
recoverable duplicate beats a silently dropped message.
|
|
46
|
+
|
|
47
|
+
Known residual risk (#835 second-pass review): this is the same bare
|
|
48
|
+
whitespace-normalized substring match ``_deliver_once`` already uses for
|
|
49
|
+
its own internal idempotent-paste guard — not a new invention — but
|
|
50
|
+
reused here it trades in the *opposite* direction from most of this
|
|
51
|
+
file's checks. A false match reports "already delivered" and SKIPS the
|
|
52
|
+
inbox enqueue entirely: for a short or generic message (a bare "yes",
|
|
53
|
+
"continue", "approved") that happens to already sit in the last
|
|
54
|
+
``VERIFY_SCROLLBACK_LINES`` for an unrelated reason, a send that
|
|
55
|
+
genuinely never landed could be silently dropped instead of queued —
|
|
56
|
+
the one outcome this whole fallback exists to prevent. Tracked as a
|
|
57
|
+
follow-up (a lightweight per-attempt marker, mirroring
|
|
58
|
+
``send_verified``'s own ``marker`` param, would close this precisely);
|
|
59
|
+
not fixed here because it's strictly narrower than the bug this
|
|
60
|
+
function was written to close (needs a coincidental/repeated-text
|
|
61
|
+
match, not just any unverified send).
|
|
62
|
+
|
|
63
|
+
Returns ``"already_delivered"``, ``"inbox"``, or ``None`` (the inbox
|
|
64
|
+
fallback itself failed).
|
|
65
|
+
"""
|
|
66
|
+
from agentwire.session_ready import message_on_scrollback, recover_failed_seed, scrollback
|
|
67
|
+
|
|
68
|
+
if message_on_scrollback(scrollback(session), prompt):
|
|
69
|
+
return "already_delivered"
|
|
70
|
+
return recover_failed_seed(session, prompt, sender=sender)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _fallback_suffix(fallback: "str | None") -> str:
|
|
74
|
+
if fallback == "already_delivered":
|
|
75
|
+
return " — already delivered directly (the confirmation read was just ambiguous); no action needed"
|
|
76
|
+
if fallback == "inbox":
|
|
77
|
+
return " — queued to its msg inbox for guaranteed delivery"
|
|
78
|
+
return " and could not be queued — resend manually"
|
|
79
|
+
|
|
80
|
+
|
|
27
81
|
def cmd_send(args) -> int:
|
|
28
82
|
"""Send a prompt to a tmux session or pane (adds Enter automatically).
|
|
29
83
|
|
|
@@ -36,6 +90,13 @@ def cmd_send(args) -> int:
|
|
|
36
90
|
json_mode = getattr(args, 'json', False)
|
|
37
91
|
wait_ready = getattr(args, 'wait_ready', False)
|
|
38
92
|
verify = getattr(args, 'verify', False)
|
|
93
|
+
# Candidate sender for a msg-inbox fallback's attribution (#835 review):
|
|
94
|
+
# prefer the real calling session over the generic "agentwire" so
|
|
95
|
+
# dead-letter emails and the rendered [MSG from ...] header stay
|
|
96
|
+
# meaningful. MCP forwards --caller-session explicitly (can't reliably
|
|
97
|
+
# auto-detect the caller across that boundary); a bare CLI invocation
|
|
98
|
+
# falls back to auto-detecting its own tmux session.
|
|
99
|
+
fallback_sender = getattr(args, 'caller_session', None) or pane_manager.get_current_session() or "agentwire"
|
|
39
100
|
|
|
40
101
|
if wait_ready and pane_index is not None:
|
|
41
102
|
return _output_result(False, json_mode, "--wait-ready targets a session's pane 0; it can't be combined with --pane")
|
|
@@ -173,13 +234,22 @@ def cmd_send(args) -> int:
|
|
|
173
234
|
if not wait_for_session_ready(session, timeout=timeout):
|
|
174
235
|
return _output_result(False, json_mode, f"Agent in '{session}' not ready after {timeout:.0f}s")
|
|
175
236
|
if not send_verified(session, prompt):
|
|
237
|
+
# A caller acting on "not verified" text is optional, not
|
|
238
|
+
# guaranteed — under load this is exactly the class of message
|
|
239
|
+
# that must never depend on an LLM noticing and manually
|
|
240
|
+
# resending. Fall back to the durable msg inbox (retried across
|
|
241
|
+
# ticks, dead-lettered + emailed on true exhaustion) instead of
|
|
242
|
+
# returning inert advisory text (#834).
|
|
243
|
+
fallback = _recover_unverified_send(session, prompt, fallback_sender)
|
|
176
244
|
if json_mode:
|
|
177
|
-
print(json.dumps({"success": False, "session": session_full, "verified": False,
|
|
245
|
+
print(json.dumps({"success": False, "session": session_full, "verified": False,
|
|
246
|
+
"fallback": fallback, "error": "Delivery not verified"}))
|
|
178
247
|
else:
|
|
179
|
-
print(f"Sent to {session} but delivery could not be verified", file=sys.stderr)
|
|
248
|
+
print(f"Sent to {session} but delivery could not be verified{_fallback_suffix(fallback)}", file=sys.stderr)
|
|
180
249
|
return 1
|
|
181
250
|
if json_mode:
|
|
182
|
-
print(json.dumps({"success": True, "session": session_full, "machine": None,
|
|
251
|
+
print(json.dumps({"success": True, "session": session_full, "machine": None,
|
|
252
|
+
"verified": True, "fallback": None, "message": "Prompt sent"}))
|
|
183
253
|
else:
|
|
184
254
|
print(f"Sent to {session} (verified)")
|
|
185
255
|
return 0
|
|
@@ -197,12 +267,19 @@ def cmd_send(args) -> int:
|
|
|
197
267
|
from agentwire.session_ready import send_verified
|
|
198
268
|
|
|
199
269
|
ok = send_verified(session, prompt, retries=1)
|
|
270
|
+
fallback = None
|
|
271
|
+
if not ok:
|
|
272
|
+
# Same durable fallback as --wait-ready (#834).
|
|
273
|
+
fallback = _recover_unverified_send(session, prompt, fallback_sender)
|
|
200
274
|
if json_mode:
|
|
201
275
|
print(json.dumps({"success": True, "session": session_full, "machine": None,
|
|
202
|
-
"verified": ok,
|
|
276
|
+
"verified": ok, "fallback": fallback,
|
|
203
277
|
"message": "Prompt sent" if ok else "Prompt sent but delivery could not be verified"}))
|
|
204
278
|
else:
|
|
205
|
-
|
|
279
|
+
if ok:
|
|
280
|
+
print(f"Sent to {session} (verified)")
|
|
281
|
+
else:
|
|
282
|
+
print(f"Sent to {session} (delivery NOT verified){_fallback_suffix(fallback)}")
|
|
206
283
|
return 0
|
|
207
284
|
|
|
208
285
|
# Delegate paste + Enter handling to the shared pane_manager helper so
|
|
@@ -313,6 +390,11 @@ def register_send_parser(subparsers) -> None:
|
|
|
313
390
|
"report verified vs unconfirmed instead of blind success")
|
|
314
391
|
send_parser.add_argument("--timeout", type=float, default=30.0,
|
|
315
392
|
help="Readiness wait timeout in seconds (with --wait-ready, default: 30)")
|
|
393
|
+
send_parser.add_argument("--caller-session", dest="caller_session",
|
|
394
|
+
help="Internal: attribute a msg-inbox delivery fallback to this sender "
|
|
395
|
+
"instead of auto-detecting the calling tmux session. MCP forwards "
|
|
396
|
+
"this explicitly, since the CLI subprocess can't reliably "
|
|
397
|
+
"auto-detect the caller across that boundary.")
|
|
316
398
|
send_parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
317
399
|
send_parser.set_defaults(func=cmd_send)
|
|
318
400
|
|
|
@@ -33,7 +33,7 @@ import jinja2
|
|
|
33
33
|
import yaml
|
|
34
34
|
from aiohttp import web
|
|
35
35
|
|
|
36
|
-
from . import prompt_router, security
|
|
36
|
+
from . import __version__, prompt_router, security
|
|
37
37
|
from .cached_status import CachedStatusChecker
|
|
38
38
|
from .config import Config, load_config
|
|
39
39
|
from .routes.artifacts import ArtifactsRoutesMixin, register_artifacts_routes
|
|
@@ -66,8 +66,6 @@ from .security import (
|
|
|
66
66
|
from .ssh import ssh_base_opts
|
|
67
67
|
from .worktree import parse_session_name
|
|
68
68
|
|
|
69
|
-
__version__ = "1.3.0"
|
|
70
|
-
|
|
71
69
|
logger = logging.getLogger(__name__)
|
|
72
70
|
|
|
73
71
|
# Static asset serving (#488): gzip text on the fly + Cache-Control headers.
|
|
@@ -2479,6 +2477,19 @@ class AgentWireServer(
|
|
|
2479
2477
|
["send", "-s", session_name, "--wait-ready", "--timeout", "60", "--", message]
|
|
2480
2478
|
)
|
|
2481
2479
|
if not success:
|
|
2480
|
+
if result.get("fallback") in ("inbox", "already_delivered"):
|
|
2481
|
+
# #835: an unverified send now recovers on its own -- either
|
|
2482
|
+
# it was already delivered and the confirm read was just
|
|
2483
|
+
# ambiguous, or it's queued to the durable msg inbox. Either
|
|
2484
|
+
# way the old "paste it manually" toast would be stale,
|
|
2485
|
+
# actively wrong advice.
|
|
2486
|
+
logger.info(f"First message for {session_name} recovered via {result.get('fallback')} fallback")
|
|
2487
|
+
await self._post_toast(
|
|
2488
|
+
f"First message to {session_name} queued for guaranteed delivery"
|
|
2489
|
+
if result.get("fallback") == "inbox" else
|
|
2490
|
+
f"First message to {session_name} delivered (confirmation was just delayed)",
|
|
2491
|
+
session=session_name, priority="normal", id_prefix="firstmsg")
|
|
2492
|
+
return
|
|
2482
2493
|
logger.warning(f"First message delivery failed for {session_name}: {result.get('error')}")
|
|
2483
2494
|
await self._post_toast(
|
|
2484
2495
|
f"First message not delivered to {session_name} — paste it manually",
|
|
@@ -62,6 +62,7 @@ from .worktree import (
|
|
|
62
62
|
default_base_branch,
|
|
63
63
|
ensure_worktree,
|
|
64
64
|
git_root,
|
|
65
|
+
is_registered_worktree,
|
|
65
66
|
is_valid_branch_name,
|
|
66
67
|
parse_session_name,
|
|
67
68
|
remove_worktree,
|
|
@@ -1561,7 +1562,17 @@ def _teardown_entry(
|
|
|
1561
1562
|
Never reports worktree_removed=True while the dir is still on disk: if
|
|
1562
1563
|
`git worktree remove --force` can't clear it, this fails LOUDLY
|
|
1563
1564
|
(success: False) and leaves the registry entry in place, instead of
|
|
1564
|
-
silently "unregistering" an orphan
|
|
1565
|
+
silently "unregistering" an orphan — UNLESS git *already had no record of
|
|
1566
|
+
the path before we touched it* (see `is_registered_worktree`), in which
|
|
1567
|
+
case there's no registered worktree left to protect and the leftover
|
|
1568
|
+
directory (a stale build-tool cache, typically) is hard-deleted instead.
|
|
1569
|
+
|
|
1570
|
+
That pre-check matters: `git worktree prune` below runs unconditionally
|
|
1571
|
+
and clears any entry git marks "prunable" (e.g. one whose linked `.git`
|
|
1572
|
+
file was deleted) as a side effect of THIS call — checking registration
|
|
1573
|
+
after prune would misread a worktree that was real and registered right
|
|
1574
|
+
up until this attempt as a pre-existing orphan, and hard-delete content
|
|
1575
|
+
the fail-loud path exists to protect.
|
|
1565
1576
|
|
|
1566
1577
|
The worktree removal is attempted BEFORE the session is killed, and the
|
|
1567
1578
|
session is only killed once removal is confirmed — never the reverse.
|
|
@@ -1569,10 +1580,17 @@ def _teardown_entry(
|
|
|
1569
1580
|
disk with no session left to notice, on any removal failure (bad
|
|
1570
1581
|
project_path, a stuck worktree, ...) (#740).
|
|
1571
1582
|
"""
|
|
1583
|
+
was_registered = is_registered_worktree(project_path, worktree_path)
|
|
1584
|
+
|
|
1572
1585
|
# Force-remove the git worktree, then prune admin files either way.
|
|
1573
1586
|
_, remove_error = remove_worktree(project_path, worktree_path, force=True)
|
|
1574
1587
|
subprocess.run(["git", "-C", str(project_path), "worktree", "prune"], capture_output=True)
|
|
1575
1588
|
|
|
1589
|
+
hard_deleted_orphan = False
|
|
1590
|
+
if worktree_path.exists() and not was_registered:
|
|
1591
|
+
shutil.rmtree(worktree_path, ignore_errors=True)
|
|
1592
|
+
hard_deleted_orphan = not worktree_path.exists()
|
|
1593
|
+
|
|
1576
1594
|
if worktree_path.exists():
|
|
1577
1595
|
reason = remove_error or "worktree directory still present after `git worktree remove --force`"
|
|
1578
1596
|
return {"success": False, "session": session_name, "path": str(worktree_path),
|
|
@@ -1605,7 +1623,7 @@ def _teardown_entry(
|
|
|
1605
1623
|
return {"success": True, "session": session_name, "path": str(worktree_path),
|
|
1606
1624
|
"killed": killed, "worktree_removed": True,
|
|
1607
1625
|
"branch": branch, "branch_deleted": branch_deleted, "branch_note": branch_note,
|
|
1608
|
-
"orphaned_tabs": orphaned_tabs}
|
|
1626
|
+
"orphaned_tabs": orphaned_tabs, "hard_deleted_orphan": hard_deleted_orphan}
|
|
1609
1627
|
|
|
1610
1628
|
|
|
1611
1629
|
def _worktree_remove(args, project_path: Path, worktree_dir: Path, json_mode: bool) -> int:
|
|
@@ -1641,7 +1659,9 @@ def _worktree_remove(args, project_path: Path, worktree_dir: Path, json_mode: bo
|
|
|
1641
1659
|
else:
|
|
1642
1660
|
msg = (f"Removed worktree session '{result['session']}'"
|
|
1643
1661
|
+ (" (killed live session)" if result["killed"] else "")
|
|
1644
|
-
+ f"; worktree {result['path']} removed"
|
|
1662
|
+
+ f"; worktree {result['path']} removed"
|
|
1663
|
+
+ (" (git had no registration for it — hard-deleted the leftover directory)"
|
|
1664
|
+
if result.get("hard_deleted_orphan") else ""))
|
|
1645
1665
|
if result["branch"]:
|
|
1646
1666
|
msg += f"; branch '{result['branch']}' " + ("deleted" if result["branch_deleted"] else f"kept ({result['branch_note']})")
|
|
1647
1667
|
if result["orphaned_tabs"]:
|
|
@@ -590,6 +590,19 @@ def clear_input_box(session: str, pane_index: int = 0) -> bool:
|
|
|
590
590
|
text]`` chip) and confirms emptiness with the drain's own SGR-aware gate
|
|
591
591
|
(``prompt_router.prompt_is_empty``), so "cleared" here means exactly
|
|
592
592
|
"the drain will deliver". Returns True iff the box ends up empty.
|
|
593
|
+
|
|
594
|
+
Refuses to press Escape while the screen shows a live select-menu/dialog
|
|
595
|
+
(#835 review): this function was written for a brand-new session's
|
|
596
|
+
failed first-message seed, where nothing else could plausibly be on
|
|
597
|
+
screen. It is also reused for an already-running, independently-busy
|
|
598
|
+
session (``agentwire send --verify`` falling back after a failed
|
|
599
|
+
delivery) — there, "box not empty" can mean a permission dialog or
|
|
600
|
+
``AskUserQuestion`` menu belonging to the recipient's own unrelated
|
|
601
|
+
work, not our stuck paste. Escape is the conventional cancel/decline key
|
|
602
|
+
for those, so pressing it blind would silently cancel a decision that
|
|
603
|
+
had nothing to do with us. Returns False without touching the pane in
|
|
604
|
+
that case; the caller's msg-inbox fallback still gets enqueued and
|
|
605
|
+
waits for the box to become genuinely idle on its own.
|
|
593
606
|
"""
|
|
594
607
|
from agentwire import pane_manager, prompt_router
|
|
595
608
|
|
|
@@ -602,6 +615,8 @@ def clear_input_box(session: str, pane_index: int = 0) -> bool:
|
|
|
602
615
|
try:
|
|
603
616
|
if empty():
|
|
604
617
|
return True
|
|
618
|
+
if prompt_router.screen_shows_live_menu(_snapshot(session, pane_index)):
|
|
619
|
+
return False
|
|
605
620
|
pane_manager.run_command(
|
|
606
621
|
["tmux", "send-keys", "-t", target, "Escape"], timeout=5
|
|
607
622
|
)
|
|
@@ -824,6 +824,24 @@ function _mountSessionWindow(session, mode, machine, id) {
|
|
|
824
824
|
addTaskbarButton(id, sw);
|
|
825
825
|
}
|
|
826
826
|
|
|
827
|
+
/**
|
|
828
|
+
* FNV-1a 32-bit hash of `url`, as 8 lowercase hex chars. Must match
|
|
829
|
+
* `_artifact_url_hash` in routes/desktop.py byte-for-byte — server and
|
|
830
|
+
* frontend both derive the same fallback artifact id from the same URL. A
|
|
831
|
+
* hash isn't lossy the way the prior char-substitution slug was (distinct
|
|
832
|
+
* URLs like "reports/jan.html" and "reports-jan.html" collided onto the
|
|
833
|
+
* same id).
|
|
834
|
+
*/
|
|
835
|
+
function artifactUrlHash(url) {
|
|
836
|
+
let h = 0x811c9dc5;
|
|
837
|
+
const bytes = new TextEncoder().encode(url);
|
|
838
|
+
for (const b of bytes) {
|
|
839
|
+
h ^= b;
|
|
840
|
+
h = Math.imul(h, 0x01000193) >>> 0;
|
|
841
|
+
}
|
|
842
|
+
return h.toString(16).padStart(8, '0');
|
|
843
|
+
}
|
|
844
|
+
|
|
827
845
|
/**
|
|
828
846
|
* Open an artifact window (agent-generated HTML or external URL).
|
|
829
847
|
*
|
|
@@ -832,7 +850,7 @@ function _mountSessionWindow(session, mode, machine, id) {
|
|
|
832
850
|
* @param {string|null} artifactId - Optional explicit window ID
|
|
833
851
|
*/
|
|
834
852
|
export function openArtifactWindow(url, title = 'Artifact', artifactId = null) {
|
|
835
|
-
const id = artifactId || `artifact-${url
|
|
853
|
+
const id = artifactId || `artifact-${artifactUrlHash(url)}`;
|
|
836
854
|
|
|
837
855
|
// Check if already open — restore if minimized, otherwise focus
|
|
838
856
|
if (artifactWindows.has(id)) {
|
|
@@ -86,10 +86,19 @@ class NotificationsPanel {
|
|
|
86
86
|
this._removeToast(id, false);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
// Evict oldest if at
|
|
89
|
+
// Evict the oldest toast NOT carrying an artifact notice, if at
|
|
90
|
+
// capacity. Artifact toasts are exempt regardless of priority: an
|
|
91
|
+
// unclicked deliverable must not silently fade (#817) — the cap
|
|
92
|
+
// only trims ordinary toasts (sticky `high`-priority ones included).
|
|
93
|
+
// If every current toast is an artifact notice, the panel
|
|
94
|
+
// temporarily exceeds MAX_TOASTS rather than dropping one.
|
|
90
95
|
if (this.toasts.size >= MAX_TOASTS) {
|
|
91
|
-
const
|
|
92
|
-
|
|
96
|
+
for (const id of this.toasts.keys()) {
|
|
97
|
+
if (!this.artifactNotices.has(id)) {
|
|
98
|
+
this._removeToast(id, false);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
93
102
|
}
|
|
94
103
|
|
|
95
104
|
// Resolve auto-fade: explicit timeout wins (0 = sticky); otherwise
|
|
@@ -309,6 +309,39 @@ def remove_worktree(project_path: Path, worktree_path: Path, *, force: bool = Tr
|
|
|
309
309
|
return False, (result.stderr or result.stdout).strip()
|
|
310
310
|
|
|
311
311
|
|
|
312
|
+
def is_registered_worktree(project_path: Path, worktree_path: Path) -> bool:
|
|
313
|
+
"""Does git's own worktree registry (still) know about ``worktree_path``?
|
|
314
|
+
|
|
315
|
+
A directory can outlive its registration — e.g. `git worktree remove`
|
|
316
|
+
succeeded on a prior teardown attempt but the `rm -rf` half crashed
|
|
317
|
+
before clearing a build-tool cache dir left inside, or the admin file
|
|
318
|
+
under `.git/worktrees/` was pruned independently. In that state git
|
|
319
|
+
reports "fatal: ... is not a working tree" for every future removal
|
|
320
|
+
attempt, forever — this lets a caller distinguish that from a real
|
|
321
|
+
registered worktree that `remove --force` merely failed to clear. It
|
|
322
|
+
says nothing about whether the directory holds valuable content — that
|
|
323
|
+
judgment (e.g. "orphaned + unregistered is safe to hard-delete") belongs
|
|
324
|
+
to the caller, not this function.
|
|
325
|
+
|
|
326
|
+
Fails closed on an inconclusive read: if `git worktree list` itself
|
|
327
|
+
errors (corrupt repo, I/O, lock contention), that's reported as
|
|
328
|
+
registered rather than not — a caller gating a destructive action on
|
|
329
|
+
this should default to "assume real" when unsure, not "assume orphan".
|
|
330
|
+
"""
|
|
331
|
+
result = subprocess.run(
|
|
332
|
+
["git", "worktree", "list", "--porcelain"],
|
|
333
|
+
cwd=project_path, capture_output=True, text=True,
|
|
334
|
+
)
|
|
335
|
+
if result.returncode != 0:
|
|
336
|
+
return True
|
|
337
|
+
target = str(worktree_path.resolve())
|
|
338
|
+
for line in result.stdout.splitlines():
|
|
339
|
+
if line.startswith("worktree "):
|
|
340
|
+
if str(Path(line[len("worktree "):]).resolve()) == target:
|
|
341
|
+
return True
|
|
342
|
+
return False
|
|
343
|
+
|
|
344
|
+
|
|
312
345
|
def worktree_status(worktree_path: Path) -> dict:
|
|
313
346
|
"""Read-only git status for a worktree. Local git only — no network, no gh.
|
|
314
347
|
|
|
@@ -643,6 +643,38 @@ def test_remove_fails_loudly_when_dir_survives(tmp_path, monkeypatch, wt_env, ca
|
|
|
643
643
|
assert payload["error"]
|
|
644
644
|
|
|
645
645
|
|
|
646
|
+
def test_remove_hard_deletes_unregistered_orphan_directory(tmp_path, monkeypatch, wt_env, capsys):
|
|
647
|
+
"""A directory git no longer registers as a worktree at all (its
|
|
648
|
+
`.git/worktrees/<name>` admin entry is gone, e.g. from a prior teardown
|
|
649
|
+
that crashed mid-way) must not get stuck failing `git worktree remove`
|
|
650
|
+
forever — since git has nothing left to lose, the leftover directory is
|
|
651
|
+
hard-deleted and teardown proceeds and succeeds."""
|
|
652
|
+
import shutil
|
|
653
|
+
|
|
654
|
+
_, clone = _origin_and_clone(tmp_path, default_branch="develop")
|
|
655
|
+
wt_dir = tmp_path / "worktrees"
|
|
656
|
+
cfg = _config(wt_dir)
|
|
657
|
+
assert _run(monkeypatch, cfg, name="orphan", project=str(clone)) == 0
|
|
658
|
+
wt_path = wt_dir / "clone-repo" / "orphan"
|
|
659
|
+
assert wt_path.exists()
|
|
660
|
+
|
|
661
|
+
# Simulate the crashed-partial-teardown state: git's own registration is
|
|
662
|
+
# gone, but the directory (with leftover content) survives on disk.
|
|
663
|
+
shutil.rmtree(clone / ".git" / "worktrees" / "orphan")
|
|
664
|
+
(wt_path / "stale-cache-file").write_text("leftover\n")
|
|
665
|
+
|
|
666
|
+
capsys.readouterr()
|
|
667
|
+
rc = _run(monkeypatch, cfg, name="orphan", project=str(clone), remove=True)
|
|
668
|
+
assert rc == 0
|
|
669
|
+
assert not wt_path.exists()
|
|
670
|
+
assert reg.entries(clone.resolve()) == []
|
|
671
|
+
|
|
672
|
+
payload = json.loads(capsys.readouterr().out)
|
|
673
|
+
assert payload["success"] is True
|
|
674
|
+
assert payload["worktree_removed"] is True
|
|
675
|
+
assert payload["hard_deleted_orphan"] is True
|
|
676
|
+
|
|
677
|
+
|
|
646
678
|
def test_remove_kills_alive_session(tmp_path, monkeypatch, wt_env, capsys):
|
|
647
679
|
_, clone = _origin_and_clone(tmp_path, default_branch="develop")
|
|
648
680
|
wt_dir = tmp_path / "worktrees"
|