agentwire-dev 1.54.0__tar.gz → 1.56.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/PKG-INFO +1 -1
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/__main__.py +35 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/channels_cli.py +11 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/config.py +13 -2
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/council/cli.py +126 -8
- agentwire_dev-1.56.0/agentwire/council/minutes.py +174 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/inbox.py +59 -7
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_council.py +51 -4
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_msg.py +20 -6
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_worktree.py +33 -7
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/msg_cli.py +35 -8
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/pane_manager.py +8 -1
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/project_config.py +51 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/prompt_router.py +13 -7
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/council-orchestrator.md +8 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/artifacts.py +42 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/scheduler/schedule.py +12 -2
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/session_cli.py +106 -51
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/session_ready.py +239 -94
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/css/desktop.css +23 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/artifact-window.js +61 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/desktop.js +22 -29
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/shortcuts.js +1 -1
- agentwire_dev-1.56.0/agentwire/templates/council/minutes.html.j2 +193 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/worktree.py +0 -17
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/worktree_registry.py +1 -1
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/council.md +32 -2
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/messaging.md +66 -24
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/worktree-sessions.md +21 -5
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/conftest.py +16 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/integration/test_send_verified_tmux.py +89 -28
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/integration/test_worktree_cmd.py +166 -7
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_cli_commands.py +78 -0
- agentwire_dev-1.56.0/tests/unit/test_council_minutes.py +305 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_inbox.py +96 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_mcp_tools_args.py +63 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_msg_cli.py +96 -2
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_portal_api.py +62 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_project_config.py +59 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_prompt_router.py +34 -5
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_routes_snapshot.py +2 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_scheduler.py +15 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_session_ready.py +306 -60
- agentwire_dev-1.56.0/tests/unit/test_window_cycling_binding.py +65 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_worktree.py +0 -26
- agentwire_dev-1.56.0/tests/unit/test_worktree_layout.py +89 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/.gitignore +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/AGENTS.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/LICENSE +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/README.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/RELEASING.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/SECURITY.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/core.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/doctor_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/hooks_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_core.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_session.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_voiceclone.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/notify_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/pane_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/contributor.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles/worktree-session.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/desktop.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/safety/_core.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/safety_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/safety_commands.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/scheduler/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/scheduler/dispatch.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/scheduler/models.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/scheduler/report.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/security.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/system_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/voiceclone.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/logo.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/pyproject.toml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_control_plane_protection.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_notify_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_pip_environment.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_safety_heal.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.56.0}/tests/unit/test_worktree_registry.py +0 -0
|
@@ -268,6 +268,17 @@ Command Categories:
|
|
|
268
268
|
"stop", help="Kill the sitting's sessions (prompt history kept)"
|
|
269
269
|
)
|
|
270
270
|
c_stop.add_argument("--name", help=_name_help)
|
|
271
|
+
c_stop.add_argument(
|
|
272
|
+
"--minutes", dest="minutes", action="store_true", default=None,
|
|
273
|
+
help="Render the minutes artifact (default: render when any prompt exists)",
|
|
274
|
+
)
|
|
275
|
+
c_stop.add_argument(
|
|
276
|
+
"--no-minutes", dest="minutes", action="store_false",
|
|
277
|
+
help="Skip the minutes artifact",
|
|
278
|
+
)
|
|
279
|
+
c_stop.add_argument(
|
|
280
|
+
"--synthesis", help="Synthesis for the minutes: text, or a path to a file"
|
|
281
|
+
)
|
|
271
282
|
c_stop.add_argument("--json", action="store_true", help="Output JSON")
|
|
272
283
|
c_stop.set_defaults(func=council_cli.cmd_council_stop)
|
|
273
284
|
|
|
@@ -332,6 +343,30 @@ Command Categories:
|
|
|
332
343
|
c_reply.add_argument("--json", action="store_true", help="Output JSON")
|
|
333
344
|
c_reply.set_defaults(func=council_cli.cmd_council_reply)
|
|
334
345
|
|
|
346
|
+
# council minutes
|
|
347
|
+
c_minutes = council_subparsers.add_parser(
|
|
348
|
+
"minutes",
|
|
349
|
+
help="Render a sitting's minutes artifact (question + takes + synthesis)",
|
|
350
|
+
description=(
|
|
351
|
+
"Deterministically renders the sitting's persisted prompt history "
|
|
352
|
+
"(question + attributed verbatim take/ack/pass replies) plus an "
|
|
353
|
+
"optional orchestrator-supplied synthesis into a self-contained "
|
|
354
|
+
"HTML artifact at ~/.agentwire/artifacts/council-<name>-minutes/, "
|
|
355
|
+
"and opens it as a portal artifact window when the portal is up. "
|
|
356
|
+
"Works for live and dismissed sittings (prompt history is kept "
|
|
357
|
+
"on stop)."
|
|
358
|
+
),
|
|
359
|
+
)
|
|
360
|
+
c_minutes.add_argument("--name", help=_name_help)
|
|
361
|
+
c_minutes.add_argument(
|
|
362
|
+
"--prompt", help="Prompt id to render, or 'all' (default: all)"
|
|
363
|
+
)
|
|
364
|
+
c_minutes.add_argument(
|
|
365
|
+
"--synthesis", help="Synthesis: text, or a path to a file containing it"
|
|
366
|
+
)
|
|
367
|
+
c_minutes.add_argument("--json", action="store_true", help="Output JSON")
|
|
368
|
+
c_minutes.set_defaults(func=council_cli.cmd_council_minutes)
|
|
369
|
+
|
|
335
370
|
return parser
|
|
336
371
|
|
|
337
372
|
|
|
@@ -57,9 +57,11 @@ def _infer_session_from_path() -> str | None:
|
|
|
57
57
|
|
|
58
58
|
~/projects/myapp -> myapp
|
|
59
59
|
~/projects/myapp-worktrees/feature -> myapp/feature
|
|
60
|
+
~/worktrees/myapp/fix-bug -> myapp-fix-bug (worktree session)
|
|
60
61
|
"""
|
|
61
62
|
cwd = Path.cwd()
|
|
62
63
|
projects_dir = Path.home() / "projects"
|
|
64
|
+
worktrees_dir = Path.home() / "worktrees"
|
|
63
65
|
|
|
64
66
|
try:
|
|
65
67
|
rel = cwd.relative_to(projects_dir)
|
|
@@ -76,6 +78,15 @@ def _infer_session_from_path() -> str | None:
|
|
|
76
78
|
except ValueError:
|
|
77
79
|
pass
|
|
78
80
|
|
|
81
|
+
try:
|
|
82
|
+
# Worktree sessions live at ~/worktrees/<project>/<name>/ with a flat
|
|
83
|
+
# tmux session name {project}-{name}.
|
|
84
|
+
parts = cwd.relative_to(worktrees_dir).parts
|
|
85
|
+
if len(parts) >= 2:
|
|
86
|
+
return f"{parts[0]}-{parts[1]}"
|
|
87
|
+
except ValueError:
|
|
88
|
+
pass
|
|
89
|
+
|
|
79
90
|
return None
|
|
80
91
|
|
|
81
92
|
|
|
@@ -84,7 +84,16 @@ class ServerConfig:
|
|
|
84
84
|
|
|
85
85
|
@dataclass
|
|
86
86
|
class WorktreesConfig:
|
|
87
|
-
"""Git worktrees configuration for
|
|
87
|
+
"""Git worktrees configuration for `project/branch` sessions.
|
|
88
|
+
|
|
89
|
+
Governs the legacy ``project/branch`` session layout under
|
|
90
|
+
``~/projects/<project>-worktrees/``. Still ALIVE (#703): the scheduler's
|
|
91
|
+
worktree+PR dispatch creates its sessions via
|
|
92
|
+
``agentwire new -s <project>/<branch>``, and ``copy_files`` seeds every
|
|
93
|
+
fresh worktree (including scheduler dispatches). Standalone
|
|
94
|
+
``agentwire worktree`` sessions use :class:`WorktreeConfig` instead
|
|
95
|
+
(``~/worktrees/<project>/<name>/``).
|
|
96
|
+
"""
|
|
88
97
|
|
|
89
98
|
enabled: bool = True
|
|
90
99
|
suffix: str = "-worktrees"
|
|
@@ -128,7 +137,9 @@ class WorktreeConfig:
|
|
|
128
137
|
default_project: Repo path used when ``--project`` is omitted and
|
|
129
138
|
cwd is not inside a git repo. ``None`` → infer from cwd's git
|
|
130
139
|
root, else cwd.
|
|
131
|
-
worktree_dir:
|
|
140
|
+
worktree_dir: Root under which worktrees are created, nested per
|
|
141
|
+
project — ``<worktree_dir>/<project>/<name>/`` — mirroring
|
|
142
|
+
``~/projects/<project>/``.
|
|
132
143
|
naming: Optional branch-name template applied in default (new-branch)
|
|
133
144
|
mode, e.g. ``"{user}/{slug}"`` or ``"feature-{slug}"``.
|
|
134
145
|
Placeholders: ``{name}`` (raw), ``{slug}`` (slugified),
|
|
@@ -16,12 +16,15 @@ recency) otherwise, and **every command echoes which sitting it acted on**.
|
|
|
16
16
|
Subcommands:
|
|
17
17
|
|
|
18
18
|
- ``start`` — spin up the orchestrator + lens soul sessions (a *sitting*)
|
|
19
|
-
- ``stop`` — kill the sitting's sessions, clear state (history kept)
|
|
19
|
+
- ``stop`` — kill the sitting's sessions, clear state (history kept);
|
|
20
|
+
renders the minutes artifact by default when any prompt exists (#708)
|
|
20
21
|
- ``status`` — sitting + per-session liveness + open prompts
|
|
21
22
|
- ``ask`` — fan a prompt out to every soul (creates the inbox first)
|
|
22
23
|
- ``collect`` — block until every soul has filed take/ack/pass, or timeout
|
|
23
24
|
- ``reply`` — file a soul's reply (souls run this via Bash)
|
|
24
25
|
- ``list`` — every live/known sitting, oldest-first
|
|
26
|
+
- ``minutes`` — render a sitting's persisted record to a standalone HTML
|
|
27
|
+
artifact (question + attributed verbatim takes + optional synthesis)
|
|
25
28
|
"""
|
|
26
29
|
|
|
27
30
|
from __future__ import annotations
|
|
@@ -30,9 +33,10 @@ import json
|
|
|
30
33
|
import subprocess
|
|
31
34
|
import sys
|
|
32
35
|
from datetime import datetime, timezone
|
|
36
|
+
from pathlib import Path
|
|
33
37
|
from typing import Any
|
|
34
38
|
|
|
35
|
-
from agentwire.council import inbox, state
|
|
39
|
+
from agentwire.council import inbox, state, view
|
|
36
40
|
|
|
37
41
|
# --- output helpers -----------------------------------------------------------
|
|
38
42
|
|
|
@@ -160,6 +164,35 @@ def current_session() -> str | None:
|
|
|
160
164
|
return pane_manager.get_current_session()
|
|
161
165
|
|
|
162
166
|
|
|
167
|
+
def open_artifact_window(url: str, title: str) -> bool:
|
|
168
|
+
"""Best-effort: open a rendered artifact as a portal window.
|
|
169
|
+
|
|
170
|
+
Returns True only when the portal accepted the open; a down or erroring
|
|
171
|
+
portal returns False — the artifact file exists on disk either way.
|
|
172
|
+
"""
|
|
173
|
+
import os
|
|
174
|
+
|
|
175
|
+
from agentwire import core
|
|
176
|
+
|
|
177
|
+
portal = os.environ.get("AGENTWIRE_PORTAL_URL")
|
|
178
|
+
if not portal:
|
|
179
|
+
try:
|
|
180
|
+
portal = (core.load_config().get("portal", {}) or {}).get("url")
|
|
181
|
+
except Exception:
|
|
182
|
+
portal = None
|
|
183
|
+
portal = portal or core._default_portal_url()
|
|
184
|
+
try:
|
|
185
|
+
resp = core.portal_request(
|
|
186
|
+
"POST",
|
|
187
|
+
f"{portal}/api/desktop/window/open",
|
|
188
|
+
json={"type": "artifact", "url": url, "title": title},
|
|
189
|
+
timeout=5,
|
|
190
|
+
)
|
|
191
|
+
return resp.status_code == 200 and bool(resp.json().get("success"))
|
|
192
|
+
except Exception:
|
|
193
|
+
return False
|
|
194
|
+
|
|
195
|
+
|
|
163
196
|
# --- targeting / resolution -----------------------------------------------------
|
|
164
197
|
|
|
165
198
|
|
|
@@ -322,6 +355,39 @@ def cmd_council_start(args) -> int:
|
|
|
322
355
|
return _emit(args, payload, human, exit_code=0 if payload["success"] else 1, council=name)
|
|
323
356
|
|
|
324
357
|
|
|
358
|
+
def _synthesis_text(value: str | None) -> str:
|
|
359
|
+
"""Resolve ``--synthesis <file-or-text>``: an existing file's content,
|
|
360
|
+
else the value verbatim."""
|
|
361
|
+
if not value:
|
|
362
|
+
return ""
|
|
363
|
+
try:
|
|
364
|
+
path = Path(value).expanduser()
|
|
365
|
+
if path.is_file():
|
|
366
|
+
return path.read_text()
|
|
367
|
+
except (OSError, ValueError):
|
|
368
|
+
pass # not a readable path — the value is the synthesis itself
|
|
369
|
+
return value
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def _render_minutes(
|
|
373
|
+
name: str, prompt_ids: list[int] | None = None, synthesis: str = ""
|
|
374
|
+
) -> tuple[str | None, bool | None]:
|
|
375
|
+
"""Write the minutes artifact and best-effort open it in the portal.
|
|
376
|
+
|
|
377
|
+
Returns ``(path, opened)`` — both None when the sitting has no matching
|
|
378
|
+
prompt history (nothing rendered, nothing opened).
|
|
379
|
+
"""
|
|
380
|
+
from agentwire.council import minutes
|
|
381
|
+
|
|
382
|
+
path = minutes.write_minutes(name, prompt_ids, synthesis=synthesis)
|
|
383
|
+
if path is None:
|
|
384
|
+
return None, None
|
|
385
|
+
opened = open_artifact_window(
|
|
386
|
+
minutes.artifact_url(name), f"Council minutes — {name}"
|
|
387
|
+
)
|
|
388
|
+
return str(path), opened
|
|
389
|
+
|
|
390
|
+
|
|
325
391
|
def cmd_council_stop(args) -> int:
|
|
326
392
|
name, err = resolve_name(args)
|
|
327
393
|
if err:
|
|
@@ -330,6 +396,15 @@ def cmd_council_stop(args) -> int:
|
|
|
330
396
|
if sitting is None:
|
|
331
397
|
return _emit_error(args, f"no council sitting '{name}'")
|
|
332
398
|
|
|
399
|
+
# Minutes before teardown (#708): tri-state --minutes/--no-minutes,
|
|
400
|
+
# default (None) renders exactly when any prompt history exists.
|
|
401
|
+
minutes_path: str | None = None
|
|
402
|
+
minutes_opened: bool | None = None
|
|
403
|
+
if getattr(args, "minutes", None) is not False:
|
|
404
|
+
minutes_path, minutes_opened = _render_minutes(
|
|
405
|
+
name, synthesis=_synthesis_text(getattr(args, "synthesis", None))
|
|
406
|
+
)
|
|
407
|
+
|
|
333
408
|
live = list_live_sessions()
|
|
334
409
|
killed: list[str] = []
|
|
335
410
|
not_running: list[str] = []
|
|
@@ -340,14 +415,57 @@ def cmd_council_stop(args) -> int:
|
|
|
340
415
|
not_running.append(session)
|
|
341
416
|
state.clear_sitting(name)
|
|
342
417
|
|
|
343
|
-
payload = {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
418
|
+
payload = {
|
|
419
|
+
"success": True,
|
|
420
|
+
"killed": killed,
|
|
421
|
+
"not_running": not_running,
|
|
422
|
+
"minutes": minutes_path,
|
|
423
|
+
"minutes_opened": minutes_opened,
|
|
424
|
+
}
|
|
425
|
+
human = (
|
|
426
|
+
f"Council '{name}' stopped ({len(killed)} sessions killed). "
|
|
427
|
+
"Prompt history kept."
|
|
428
|
+
)
|
|
429
|
+
if minutes_path:
|
|
430
|
+
human += f"\nMinutes: {minutes_path}"
|
|
431
|
+
return _emit(args, payload, human, council=name)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def cmd_council_minutes(args) -> int:
|
|
435
|
+
name, err = resolve_name(args)
|
|
436
|
+
if err:
|
|
437
|
+
return _emit_error(args, err)
|
|
438
|
+
|
|
439
|
+
available = view.available_prompt_ids(name)
|
|
440
|
+
if not available:
|
|
441
|
+
return _emit_error(args, f"council '{name}' has no prompt history to render")
|
|
442
|
+
|
|
443
|
+
prompt_arg = getattr(args, "prompt", None) or "all"
|
|
444
|
+
prompt_ids: list[int] | None = None
|
|
445
|
+
if str(prompt_arg) != "all":
|
|
446
|
+
try:
|
|
447
|
+
prompt_ids = [int(prompt_arg)]
|
|
448
|
+
except (TypeError, ValueError):
|
|
449
|
+
return _emit_error(
|
|
450
|
+
args, f"--prompt must be a prompt id or 'all', got {prompt_arg!r}"
|
|
451
|
+
)
|
|
452
|
+
if prompt_ids[0] not in available:
|
|
453
|
+
return _emit_error(
|
|
454
|
+
args,
|
|
455
|
+
f"no prompt #{prompt_ids[0]} in council '{name}' "
|
|
456
|
+
f"(available: {', '.join(map(str, available))})",
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
path, opened = _render_minutes(
|
|
460
|
+
name, prompt_ids, synthesis=_synthesis_text(getattr(args, "synthesis", None))
|
|
349
461
|
)
|
|
350
462
|
|
|
463
|
+
payload = {"success": True, "path": path, "opened": opened}
|
|
464
|
+
human = f"Minutes: {path}"
|
|
465
|
+
if opened:
|
|
466
|
+
human += "\nOpened as a portal artifact window."
|
|
467
|
+
return _emit(args, payload, human, council=name)
|
|
468
|
+
|
|
351
469
|
|
|
352
470
|
def cmd_council_status(args) -> int:
|
|
353
471
|
name, err = resolve_name(args)
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""Council minutes — deterministic HTML render of a sitting's persisted record.
|
|
2
|
+
|
|
3
|
+
Handoff pattern (#708): everything verbatim (the question, the attributed
|
|
4
|
+
take/ack/pass replies) already persists under
|
|
5
|
+
``~/.agentwire/council/<name>/prompts/NNNN/``, so the renderer is a pure
|
|
6
|
+
function of disk state. The synthesis exists only in the orchestrator's
|
|
7
|
+
context, so it arrives as an *input* — omitted, the minutes render without a
|
|
8
|
+
synthesis section.
|
|
9
|
+
|
|
10
|
+
Output is one fully self-contained HTML file (inline CSS only — the portal's
|
|
11
|
+
artifact CSP blocks external fetches), theme-aware via
|
|
12
|
+
``prefers-color-scheme``, at::
|
|
13
|
+
|
|
14
|
+
~/.agentwire/artifacts/council-<name>-minutes/index.html
|
|
15
|
+
|
|
16
|
+
Works for live and dismissed sittings alike — prompt history is disk-derived,
|
|
17
|
+
sitting metadata falls back from ``sitting.json`` to the preserved
|
|
18
|
+
``archive.json``.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from datetime import datetime
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
import jinja2
|
|
27
|
+
|
|
28
|
+
from agentwire.council import inbox, state, view
|
|
29
|
+
|
|
30
|
+
# --- paths ------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def artifacts_dir() -> Path:
|
|
34
|
+
"""The portal artifacts root (config override honored)."""
|
|
35
|
+
try:
|
|
36
|
+
from agentwire.config import load_config
|
|
37
|
+
|
|
38
|
+
return Path(str(load_config().artifacts.dir)).expanduser()
|
|
39
|
+
except Exception:
|
|
40
|
+
return Path.home() / ".agentwire" / "artifacts"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def minutes_path(name: str) -> Path:
|
|
44
|
+
return artifacts_dir() / f"council-{name}-minutes" / "index.html"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def artifact_url(name: str) -> str:
|
|
48
|
+
"""Path relative to the artifacts root — what the portal iframe loads."""
|
|
49
|
+
return f"council-{name}-minutes/index.html"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# --- gather -----------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _fmt_ts(iso: str) -> str:
|
|
56
|
+
"""ISO timestamp → compact display form (``2026-07-04 15:38 UTC``)."""
|
|
57
|
+
if not iso:
|
|
58
|
+
return ""
|
|
59
|
+
try:
|
|
60
|
+
dt = datetime.fromisoformat(iso)
|
|
61
|
+
except (ValueError, TypeError):
|
|
62
|
+
return iso
|
|
63
|
+
suffix = " UTC" if dt.tzinfo is not None else ""
|
|
64
|
+
return dt.strftime("%Y-%m-%d %H:%M") + suffix
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def gather(name: str, prompt_ids: list[int] | None = None) -> dict | None:
|
|
68
|
+
"""Collect a sitting's persisted record into a render-ready dict.
|
|
69
|
+
|
|
70
|
+
``prompt_ids`` filters to specific rounds (None = every prompt on disk).
|
|
71
|
+
Returns ``None`` when nothing matches — a sitting that never deliberated
|
|
72
|
+
has no minutes. Reply dicts carry only content (soul, kind, text,
|
|
73
|
+
timestamp), never local filesystem paths: the artifact is built to be
|
|
74
|
+
shared.
|
|
75
|
+
"""
|
|
76
|
+
available = view.available_prompt_ids(name)
|
|
77
|
+
selected = (
|
|
78
|
+
available if prompt_ids is None else [p for p in prompt_ids if p in available]
|
|
79
|
+
)
|
|
80
|
+
if not selected:
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
sitting = state.read_sitting(name)
|
|
84
|
+
archived = sitting is None
|
|
85
|
+
dismissed_at = ""
|
|
86
|
+
if archived:
|
|
87
|
+
raw = state.read_archive_dict(name)
|
|
88
|
+
dismissed_at = (raw or {}).get("dismissed_at", "")
|
|
89
|
+
sitting = (
|
|
90
|
+
state.Sitting.from_dict(raw)
|
|
91
|
+
if raw is not None
|
|
92
|
+
else state.Sitting(
|
|
93
|
+
orchestrator=state.orchestrator_for(name),
|
|
94
|
+
roster=[],
|
|
95
|
+
sessions={},
|
|
96
|
+
started_at="",
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
prompts = []
|
|
101
|
+
for pid in selected:
|
|
102
|
+
meta = inbox.read_meta(name, pid)
|
|
103
|
+
try:
|
|
104
|
+
question = (inbox.prompt_dir(name, pid) / "prompt.md").read_text()
|
|
105
|
+
except OSError:
|
|
106
|
+
question = ""
|
|
107
|
+
replies = [
|
|
108
|
+
{
|
|
109
|
+
"soul": r.soul,
|
|
110
|
+
"kind": r.kind,
|
|
111
|
+
"text": r.text.strip(),
|
|
112
|
+
"written_at": _fmt_ts(r.written_at),
|
|
113
|
+
}
|
|
114
|
+
for r in inbox.list_replies(name, pid)
|
|
115
|
+
]
|
|
116
|
+
prompts.append(
|
|
117
|
+
{
|
|
118
|
+
"id": pid,
|
|
119
|
+
"question": question.strip(),
|
|
120
|
+
"created_at": _fmt_ts(meta.get("created_at", "")),
|
|
121
|
+
"roster": meta.get("roster") or list(sitting.roster),
|
|
122
|
+
"replies": replies,
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
roster = list(sitting.roster) or prompts[0]["roster"]
|
|
127
|
+
return {
|
|
128
|
+
"name": name,
|
|
129
|
+
"archived": archived,
|
|
130
|
+
"started_at": _fmt_ts(sitting.started_at),
|
|
131
|
+
"dismissed_at": _fmt_ts(dismissed_at),
|
|
132
|
+
"roster": roster,
|
|
133
|
+
"prompts": prompts,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# --- render -----------------------------------------------------------------
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _env() -> jinja2.Environment:
|
|
141
|
+
# autoescape=True explicitly: select_autoescape keys off the *final*
|
|
142
|
+
# extension, and ``.html.j2`` ends in ``.j2`` — verbatim soul takes are
|
|
143
|
+
# untrusted content, so escaping must never silently switch off.
|
|
144
|
+
templates = Path(__file__).resolve().parent.parent / "templates"
|
|
145
|
+
return jinja2.Environment(
|
|
146
|
+
loader=jinja2.FileSystemLoader(str(templates)),
|
|
147
|
+
autoescape=True,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def render_html(record: dict, synthesis: str = "") -> str:
|
|
152
|
+
template = _env().get_template("council/minutes.html.j2")
|
|
153
|
+
return template.render(
|
|
154
|
+
record=record,
|
|
155
|
+
synthesis=(synthesis or "").strip(),
|
|
156
|
+
generated_at=_fmt_ts(state.now_iso()),
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def write_minutes(
|
|
161
|
+
name: str, prompt_ids: list[int] | None = None, synthesis: str = ""
|
|
162
|
+
) -> Path | None:
|
|
163
|
+
"""Render and write the minutes artifact; return its path.
|
|
164
|
+
|
|
165
|
+
Returns ``None`` (writes nothing) when the sitting has no matching prompt
|
|
166
|
+
history — a zero-prompt sitting leaves no minutes behind.
|
|
167
|
+
"""
|
|
168
|
+
record = gather(name, prompt_ids)
|
|
169
|
+
if record is None:
|
|
170
|
+
return None
|
|
171
|
+
out = minutes_path(name)
|
|
172
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
173
|
+
out.write_text(render_html(record, synthesis), encoding="utf-8")
|
|
174
|
+
return out
|
|
@@ -62,6 +62,13 @@ BROADCAST_TOKEN = "@all"
|
|
|
62
62
|
# being permanently busy/typed-in).
|
|
63
63
|
MAX_ATTEMPTS = 40
|
|
64
64
|
|
|
65
|
+
# A recipient that positively does not exist gets a much shorter window (#694):
|
|
66
|
+
# a gone session can't clear its box by itself — it only comes back if someone
|
|
67
|
+
# recreates it — so the grace is ~5 watchdog ticks (≈5 min), enough for a
|
|
68
|
+
# restart/recreate to land, not the 40-minute busy cap. Counted separately
|
|
69
|
+
# (``Message.gone_attempts``) so prior busy penalties don't erode the grace.
|
|
70
|
+
GONE_MAX_ATTEMPTS = 5
|
|
71
|
+
|
|
65
72
|
# Defer reasons that DON'T penalize: the target is legitimately busy — running a
|
|
66
73
|
# long command (unparseable box → "target_busy") or generating with human-queued
|
|
67
74
|
# input (the "queued messages" placeholder → "queued_placeholder"), or the box
|
|
@@ -106,6 +113,7 @@ class Message:
|
|
|
106
113
|
text: str
|
|
107
114
|
ts: int # epoch ms
|
|
108
115
|
attempts: int = 0
|
|
116
|
+
gone_attempts: int = 0 # ticks the drain observed the target session gone
|
|
109
117
|
reason: str = "" # last defer reason (why delivery kept failing)
|
|
110
118
|
dead_ts: int = 0 # epoch ms when dead-lettered (0 = still live)
|
|
111
119
|
ref: str = "" # optional machine-readable pointer (e.g. a report path) — for ingest
|
|
@@ -120,6 +128,7 @@ class Message:
|
|
|
120
128
|
"text": self.text,
|
|
121
129
|
"ts": self.ts,
|
|
122
130
|
"attempts": self.attempts,
|
|
131
|
+
"gone_attempts": self.gone_attempts,
|
|
123
132
|
"reason": self.reason,
|
|
124
133
|
"dead_ts": self.dead_ts,
|
|
125
134
|
"ref": self.ref,
|
|
@@ -251,6 +260,7 @@ def _read_message(path: Path) -> "Message | None":
|
|
|
251
260
|
text=str(data.get("text", "")),
|
|
252
261
|
ts=int(data.get("ts", 0)),
|
|
253
262
|
attempts=int(data.get("attempts", 0)),
|
|
263
|
+
gone_attempts=int(data.get("gone_attempts", 0)),
|
|
254
264
|
reason=str(data.get("reason", "")),
|
|
255
265
|
dead_ts=int(data.get("dead_ts", 0)),
|
|
256
266
|
ref=str(data.get("ref", "")),
|
|
@@ -484,19 +494,34 @@ def gc_sender(sender: str) -> dict:
|
|
|
484
494
|
# =============================================================================
|
|
485
495
|
|
|
486
496
|
|
|
487
|
-
def
|
|
488
|
-
"""Every tmux session
|
|
489
|
-
|
|
497
|
+
def live_sessions() -> "set[str] | None":
|
|
498
|
+
"""Every live tmux session name, or None when tmux is unreachable.
|
|
499
|
+
|
|
500
|
+
``None`` (no server / no tmux) is deliberately distinct from ``set()``:
|
|
501
|
+
the gone fast-path (#694) and the send-time warning only fire on POSITIVE
|
|
502
|
+
knowledge that tmux is reachable but the target isn't there. With the
|
|
503
|
+
server down everything is equally unreachable — that's an outage, not a
|
|
504
|
+
gone recipient, so callers fall back to the ordinary defer path.
|
|
505
|
+
"""
|
|
490
506
|
from .usage_limit import _tmux
|
|
491
507
|
|
|
492
508
|
try:
|
|
493
509
|
result = _tmux(["list-sessions", "-F", "#{session_name}"])
|
|
494
510
|
except Exception:
|
|
495
|
-
return
|
|
511
|
+
return None
|
|
496
512
|
if result.returncode != 0:
|
|
513
|
+
return None
|
|
514
|
+
return {s for s in result.stdout.split("\n") if s.strip()}
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
def _live_agent_sessions() -> list[str]:
|
|
518
|
+
"""Every tmux session whose pane 0 runs an agent (Claude/pi)."""
|
|
519
|
+
from . import prompt_router
|
|
520
|
+
|
|
521
|
+
sessions = live_sessions()
|
|
522
|
+
if not sessions:
|
|
497
523
|
return []
|
|
498
|
-
|
|
499
|
-
return [s for s in sessions if prompt_router.is_agent_pane(s, 0)]
|
|
524
|
+
return [s for s in sorted(sessions) if prompt_router.is_agent_pane(s, 0)]
|
|
500
525
|
|
|
501
526
|
|
|
502
527
|
def resolve_targets(to: str, sender: "str | None") -> list[str]:
|
|
@@ -639,6 +664,15 @@ def _bump_attempts(messages: list[Message], reason: str = "") -> int:
|
|
|
639
664
|
``reason`` is the defer reason that caused this pass; it's stamped onto the
|
|
640
665
|
message so a dead-lettered one carries *why* it never got delivered.
|
|
641
666
|
Returns the number dead-lettered this pass.
|
|
667
|
+
|
|
668
|
+
``target_gone`` additionally bumps the per-message ``gone_attempts``
|
|
669
|
+
counter and dead-letters at the fast ``GONE_MAX_ATTEMPTS`` cap (#694) — a
|
|
670
|
+
gone session can't un-go by itself, so it gets minutes of grace (enough
|
|
671
|
+
for a recreate to land), not the 40-minute busy window. The counter is
|
|
672
|
+
separate from ``attempts`` so busy penalties accrued while the target
|
|
673
|
+
lived don't erode the grace, and cumulative across gone observations —
|
|
674
|
+
a target that flaps in and out without ever accepting delivery still
|
|
675
|
+
burns out on schedule.
|
|
642
676
|
"""
|
|
643
677
|
dead = 0
|
|
644
678
|
for msg in messages:
|
|
@@ -657,7 +691,9 @@ def _bump_attempts(messages: list[Message], reason: str = "") -> int:
|
|
|
657
691
|
|
|
658
692
|
msg.attempts += 1
|
|
659
693
|
msg.reason = reason
|
|
660
|
-
if
|
|
694
|
+
if reason == "target_gone":
|
|
695
|
+
msg.gone_attempts += 1
|
|
696
|
+
if msg.attempts >= MAX_ATTEMPTS or msg.gone_attempts >= GONE_MAX_ATTEMPTS:
|
|
661
697
|
msg.dead_ts = _now_ms()
|
|
662
698
|
target = dead_dir(msg.to or "unknown") / msg.path.name
|
|
663
699
|
try:
|
|
@@ -737,6 +773,22 @@ def flush_session(session: str, force: bool = False) -> dict:
|
|
|
737
773
|
if not messages:
|
|
738
774
|
return {"session": session, "delivered": 0, "deferred": False, "reason": "empty"}
|
|
739
775
|
|
|
776
|
+
# Gone gate FIRST (#694): a recipient that positively doesn't exist can
|
|
777
|
+
# never clear a box, and the ordinary gates misread it — capturing a
|
|
778
|
+
# gone session parses as "no box" → target_busy, a NO-penalty defer, so
|
|
779
|
+
# a done to a stale parent once sat queued ~24h instead of burning out.
|
|
780
|
+
# Gone is its own penalized reason with the fast GONE_MAX_ATTEMPTS cap.
|
|
781
|
+
# Only positive knowledge counts: with tmux unreachable live_sessions()
|
|
782
|
+
# is None and the ordinary defer path applies.
|
|
783
|
+
live = live_sessions()
|
|
784
|
+
if live is not None and session not in live:
|
|
785
|
+
dead = _bump_attempts(messages, "target_gone")
|
|
786
|
+
_log_event("deferred", to=session, count=len(messages), reason="target_gone")
|
|
787
|
+
return {
|
|
788
|
+
"session": session, "delivered": 0, "deferred": True,
|
|
789
|
+
"reason": "target_gone", "dead": dead,
|
|
790
|
+
}
|
|
791
|
+
|
|
740
792
|
pre_consumed = 0
|
|
741
793
|
if not force:
|
|
742
794
|
# Collision guard FIRST (cheap, and refuses dialogs/busy too via None).
|