agentwire-dev 1.65.1__tar.gz → 1.65.2__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.2}/PKG-INFO +1 -1
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/desktop.py +17 -1
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/session_cli.py +23 -3
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/desktop.js +19 -1
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/notifications-panel.js +12 -3
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/worktree.py +33 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/integration/test_worktree_cmd.py +32 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_mcp_tools_args.py +29 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_portal_api.py +69 -3
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_worktree.py +43 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.gitignore +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/AGENTS.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/Dockerfile.local +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/LICENSE +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/README.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/RELEASING.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/SECURITY.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/SPONSORS.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/__main__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/chrome_tabs.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/completion.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/config.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/core.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/minutes.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/devices.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/doctor_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/history.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/inbox.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/listen.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/locking.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_chrome.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_core.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_council.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_msg.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_session.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_worktree.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/msg_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/network.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/notify_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/pane_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/projects.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/prompt_router.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/research.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/contributor.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/reviewer-worktree.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/reviewer.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/worker-worktree.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/safety/_core.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/safety_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/safety_commands.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/dispatch.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/models.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/report.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/schedule.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/zombie.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/security.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/server.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/services.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/session_ready.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/css/desktop.css +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/card-terminal.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/lineage.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-hud-controller.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-hud-notices.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-hud-spawn.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-hud.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/spawn-ghost.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/terminal-pane.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/topology-render.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/utils/rich-text.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/workspace-window.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/topology-harness.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/system_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tabs_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tasks_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/council/minutes.html.j2 +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templating.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/validation.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/design/session-card-fields.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/design/session-card-recommendation.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/logo.png +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/session-topology.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/sessions/messaging.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/sessions/worktree-sessions.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/pyproject.toml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/conftest.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/integration/test_send_verified_tmux.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_chrome_tabs.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_control_plane_protection.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_core_created_by_rooting.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_council_minutes.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_dangling_worktrees.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_doctor_scheduler_staleness.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_doctor_task_migration.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_guarded_launch_command.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_inbox.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_msg_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_notify_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_pip_environment.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_posture_default.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_projects_registry.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_prompt_router.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_rich_text_js.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_safety_heal.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_scheduler_zombie.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_session_created_by_env.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_session_ready.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_shim_selfheal.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tasks_cli.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_window_cycling_binding.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_worktree_branch_cleanup.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_worktree_layout.py +0 -0
- {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_worktree_registry.py +0 -0
|
@@ -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"
|
|
@@ -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"]:
|
|
@@ -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"
|
|
@@ -212,6 +212,35 @@ class TestVoiceTools:
|
|
|
212
212
|
assert "parked" in result
|
|
213
213
|
|
|
214
214
|
|
|
215
|
+
class TestNotifyUserArtifactParams:
|
|
216
|
+
"""#822: notify_user's artifact_url/artifact_title params (#821) had zero
|
|
217
|
+
test coverage — cover the body it builds for /api/desktop/notification."""
|
|
218
|
+
|
|
219
|
+
@patch("agentwire.mcp_notify._portal_request")
|
|
220
|
+
def test_artifact_url_sets_artifact_body_with_default_title(self, mock_req):
|
|
221
|
+
from agentwire.mcp_notify import notify_user
|
|
222
|
+
mock_req.return_value = _success(id="n1", clients=1)
|
|
223
|
+
notify_user(text="ready", artifact_url="report.html")
|
|
224
|
+
body = mock_req.call_args[0][2]
|
|
225
|
+
assert body["artifact"] == {"url": "report.html", "title": "Artifact"}
|
|
226
|
+
|
|
227
|
+
@patch("agentwire.mcp_notify._portal_request")
|
|
228
|
+
def test_artifact_title_overrides_default(self, mock_req):
|
|
229
|
+
from agentwire.mcp_notify import notify_user
|
|
230
|
+
mock_req.return_value = _success(id="n1", clients=1)
|
|
231
|
+
notify_user(text="ready", artifact_url="report.html", artifact_title="Q3 Report")
|
|
232
|
+
body = mock_req.call_args[0][2]
|
|
233
|
+
assert body["artifact"] == {"url": "report.html", "title": "Q3 Report"}
|
|
234
|
+
|
|
235
|
+
@patch("agentwire.mcp_notify._portal_request")
|
|
236
|
+
def test_no_artifact_url_omits_artifact_body(self, mock_req):
|
|
237
|
+
from agentwire.mcp_notify import notify_user
|
|
238
|
+
mock_req.return_value = _success(id="n1", clients=1)
|
|
239
|
+
notify_user(text="plain toast", artifact_title="ignored without a url")
|
|
240
|
+
body = mock_req.call_args[0][2]
|
|
241
|
+
assert "artifact" not in body
|
|
242
|
+
|
|
243
|
+
|
|
215
244
|
# ---------------------------------------------------------------------------
|
|
216
245
|
# Desktop tools
|
|
217
246
|
# ---------------------------------------------------------------------------
|
|
@@ -614,6 +614,35 @@ class TestApiNotify:
|
|
|
614
614
|
assert data["clients"] == 2
|
|
615
615
|
|
|
616
616
|
|
|
617
|
+
class TestArtifactUrlHash:
|
|
618
|
+
"""#822: pins `_artifact_url_hash` (routes/desktop.py) against known
|
|
619
|
+
vectors, independently cross-checked in Node against its JS twin
|
|
620
|
+
(`artifactUrlHash` in static/js/desktop.js) — the two have no shared
|
|
621
|
+
source and no JS test harness exists in this repo, so this is the only
|
|
622
|
+
automated guard against the two silently drifting apart. If you change
|
|
623
|
+
the hash algorithm on either side, recompute vectors on the OTHER side
|
|
624
|
+
(e.g. `node -e "..."` mirroring this function) before touching this
|
|
625
|
+
test — a passing Python-only test proves nothing about JS parity."""
|
|
626
|
+
|
|
627
|
+
@pytest.mark.parametrize("url,expected", [
|
|
628
|
+
("", "811c9dc5"),
|
|
629
|
+
("a", "e40c292c"),
|
|
630
|
+
("reports/jan.html", "7084fac5"),
|
|
631
|
+
("reports-jan.html", "b5f6349b"),
|
|
632
|
+
("https://example.com", "6fbc04d3"),
|
|
633
|
+
("council-proj-minutes/index.html", "d569834e"),
|
|
634
|
+
("日本語", "805f5ce7"), # multi-byte UTF-8
|
|
635
|
+
("🦉", "11131011"), # astral/surrogate-pair UTF-8
|
|
636
|
+
])
|
|
637
|
+
def test_pinned_vectors(self, url, expected):
|
|
638
|
+
from agentwire.routes.desktop import _artifact_url_hash
|
|
639
|
+
assert _artifact_url_hash(url) == expected
|
|
640
|
+
|
|
641
|
+
def test_distinct_urls_that_collided_under_the_old_slug_now_differ(self):
|
|
642
|
+
from agentwire.routes.desktop import _artifact_url_hash
|
|
643
|
+
assert _artifact_url_hash("reports/jan.html") != _artifact_url_hash("reports-jan.html")
|
|
644
|
+
|
|
645
|
+
|
|
617
646
|
class TestApiDesktopNotification:
|
|
618
647
|
async def test_toast_reports_client_count(self, portal_client):
|
|
619
648
|
"""#444: posting a toast reports how many dashboards saw it live (the
|
|
@@ -630,8 +659,10 @@ class TestApiDesktopNotification:
|
|
|
630
659
|
|
|
631
660
|
async def test_artifact_notice_defaults(self, portal_client):
|
|
632
661
|
"""#817: an artifact notice needs no text (synthesized from the title),
|
|
633
|
-
derives the frontend's
|
|
634
|
-
|
|
662
|
+
derives the frontend's hash-based window id (#822 — a lossy
|
|
663
|
+
char-substitution slug let distinct URLs collide onto the same id),
|
|
664
|
+
and defaults to sticky — an unclicked deliverable must never
|
|
665
|
+
silently fade."""
|
|
635
666
|
client, server = portal_client
|
|
636
667
|
server.broadcast_dashboard = AsyncMock()
|
|
637
668
|
resp = await client.post("/api/desktop/notification", json={
|
|
@@ -645,9 +676,27 @@ class TestApiDesktopNotification:
|
|
|
645
676
|
assert notice["artifact"] == {
|
|
646
677
|
"url": "council-proj-minutes/index.html",
|
|
647
678
|
"title": "Council minutes — proj",
|
|
648
|
-
"artifact_id": "artifact-
|
|
679
|
+
"artifact_id": "artifact-d569834e",
|
|
649
680
|
}
|
|
650
681
|
|
|
682
|
+
async def test_artifact_id_does_not_collide_across_similar_urls(self, portal_client):
|
|
683
|
+
"""#822: the fallback id used to be a lossy char-substitution slug —
|
|
684
|
+
"reports/jan.html" and "reports-jan.html" both became
|
|
685
|
+
"artifact-reports-jan-html", so a new artifact could dedup-clobber a
|
|
686
|
+
different still-pending one. A hash of the full url doesn't collide
|
|
687
|
+
on this pair, so both notices coexist."""
|
|
688
|
+
client, server = portal_client
|
|
689
|
+
server.broadcast_dashboard = AsyncMock()
|
|
690
|
+
await client.post("/api/desktop/notification", json={
|
|
691
|
+
"artifact": {"url": "reports/jan.html", "title": "Jan (nested)"},
|
|
692
|
+
})
|
|
693
|
+
await client.post("/api/desktop/notification", json={
|
|
694
|
+
"artifact": {"url": "reports-jan.html", "title": "Jan (flat)"},
|
|
695
|
+
})
|
|
696
|
+
assert len(server.active_notifications) == 2
|
|
697
|
+
ids = {n["artifact"]["artifact_id"] for n in server.active_notifications.values()}
|
|
698
|
+
assert len(ids) == 2
|
|
699
|
+
|
|
651
700
|
async def test_artifact_requires_url(self, portal_client):
|
|
652
701
|
client, server = portal_client
|
|
653
702
|
server.broadcast_dashboard = AsyncMock()
|
|
@@ -667,6 +716,23 @@ class TestApiDesktopNotification:
|
|
|
667
716
|
})
|
|
668
717
|
assert len(server.active_notifications) == 1
|
|
669
718
|
|
|
719
|
+
async def test_two_distinct_artifact_notices_coexist(self, portal_client):
|
|
720
|
+
"""Two different concurrent unclicked artifact deliverables must both
|
|
721
|
+
stay pending — dedup keys on artifact_id, so distinct artifacts must
|
|
722
|
+
never clobber each other the way a same-id re-render intentionally
|
|
723
|
+
does above."""
|
|
724
|
+
client, server = portal_client
|
|
725
|
+
server.broadcast_dashboard = AsyncMock()
|
|
726
|
+
await client.post("/api/desktop/notification", json={
|
|
727
|
+
"artifact": {"url": "report-a.html", "title": "Report A"},
|
|
728
|
+
})
|
|
729
|
+
await client.post("/api/desktop/notification", json={
|
|
730
|
+
"artifact": {"url": "report-b.html", "title": "Report B"},
|
|
731
|
+
})
|
|
732
|
+
assert len(server.active_notifications) == 2
|
|
733
|
+
titles = sorted(n["artifact"]["title"] for n in server.active_notifications.values())
|
|
734
|
+
assert titles == ["Report A", "Report B"]
|
|
735
|
+
|
|
670
736
|
async def test_session_sweep_spares_artifact_notices(self, portal_client):
|
|
671
737
|
"""The one-toast-per-session replacement must not eat a pending
|
|
672
738
|
artifact notice tagged with the same session — seeing the session
|
|
@@ -12,6 +12,7 @@ from agentwire.worktree import (
|
|
|
12
12
|
git_common_dir,
|
|
13
13
|
git_root,
|
|
14
14
|
is_git_repo,
|
|
15
|
+
is_registered_worktree,
|
|
15
16
|
is_valid_branch_name,
|
|
16
17
|
parse_session_name,
|
|
17
18
|
remove_worktree,
|
|
@@ -303,3 +304,45 @@ class TestRemoveWorktree:
|
|
|
303
304
|
removed, error = remove_worktree(not_repo, tmp_path / "wherever")
|
|
304
305
|
assert removed is False
|
|
305
306
|
assert error
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
# --- is_registered_worktree ---
|
|
310
|
+
|
|
311
|
+
class TestIsRegisteredWorktree:
|
|
312
|
+
def test_true_for_a_live_worktree(self, tmp_path):
|
|
313
|
+
repo, _ = _make_repo(tmp_path)
|
|
314
|
+
wt = tmp_path / "repo-worktrees" / "feature"
|
|
315
|
+
assert ensure_worktree(repo, "feature", wt)
|
|
316
|
+
assert is_registered_worktree(repo, wt) is True
|
|
317
|
+
|
|
318
|
+
def test_false_once_gits_own_admin_dir_is_gone(self, tmp_path):
|
|
319
|
+
"""A directory can outlive its registration (e.g. a prior teardown's
|
|
320
|
+
`rm` half crashed, or the admin dir was pruned independently) — once
|
|
321
|
+
git's `.git/worktrees/<name>` entry is gone, git itself no longer
|
|
322
|
+
considers this path a worktree, even though it still exists on disk.
|
|
323
|
+
"""
|
|
324
|
+
import shutil
|
|
325
|
+
|
|
326
|
+
repo, _ = _make_repo(tmp_path)
|
|
327
|
+
wt = tmp_path / "repo-worktrees" / "feature"
|
|
328
|
+
assert ensure_worktree(repo, "feature", wt)
|
|
329
|
+
|
|
330
|
+
shutil.rmtree(repo / ".git" / "worktrees" / "feature")
|
|
331
|
+
|
|
332
|
+
assert wt.exists() # leftover directory content untouched
|
|
333
|
+
assert is_registered_worktree(repo, wt) is False
|
|
334
|
+
|
|
335
|
+
def test_false_for_a_path_never_registered(self, tmp_path):
|
|
336
|
+
repo, _ = _make_repo(tmp_path)
|
|
337
|
+
bogus = tmp_path / "never-a-worktree"
|
|
338
|
+
bogus.mkdir()
|
|
339
|
+
assert is_registered_worktree(repo, bogus) is False
|
|
340
|
+
|
|
341
|
+
def test_fails_closed_toward_registered_when_git_errors(self, tmp_path):
|
|
342
|
+
"""An inconclusive `git worktree list` (corrupt repo, I/O error, ...)
|
|
343
|
+
must not be read as "definitely orphaned" — a caller gating a
|
|
344
|
+
destructive hard-delete on this should default to treating it as a
|
|
345
|
+
real worktree when unsure, not as safe to discard."""
|
|
346
|
+
not_a_repo = tmp_path / "not-a-repo"
|
|
347
|
+
not_a_repo.mkdir()
|
|
348
|
+
assert is_registered_worktree(not_a_repo, tmp_path / "wherever") is True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/audit_logger.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/agentwire.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/containers.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/core.yaml
RENAMED
|
File without changes
|