agentwire-dev 1.55.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.55.0 → agentwire_dev-1.56.0}/PKG-INFO +1 -1
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/__main__.py +35 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/channels_cli.py +11 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/config.py +13 -2
- {agentwire_dev-1.55.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.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_council.py +51 -4
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_worktree.py +3 -3
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/project_config.py +51 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/council-orchestrator.md +8 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/artifacts.py +42 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/session_cli.py +69 -42
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/css/desktop.css +23 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/artifact-window.js +61 -0
- agentwire_dev-1.56.0/agentwire/templates/council/minutes.html.j2 +193 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/worktree.py +0 -17
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/worktree_registry.py +1 -1
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/council.md +32 -2
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/worktree-sessions.md +21 -5
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/integration/test_worktree_cmd.py +166 -7
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_cli_commands.py +1 -0
- agentwire_dev-1.56.0/tests/unit/test_council_minutes.py +305 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_portal_api.py +62 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_project_config.py +59 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_routes_snapshot.py +2 -0
- {agentwire_dev-1.55.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.55.0 → agentwire_dev-1.56.0}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/.gitignore +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/AGENTS.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/LICENSE +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/README.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/RELEASING.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/SECURITY.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/core.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/doctor_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/hooks_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/inbox.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_core.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_msg.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_session.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_voiceclone.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/msg_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/notify_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/pane_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/prompt_router.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/contributor.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles/worktree-session.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/desktop.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/safety/_core.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/safety_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/safety_commands.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/scheduler/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/scheduler/dispatch.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/scheduler/models.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/scheduler/report.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/scheduler/schedule.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/security.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/server.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/session_ready.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/desktop.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/system_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/voiceclone.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/logo.png +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/messaging.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/pyproject.toml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/integration/test_send_verified_tmux.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_control_plane_protection.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_inbox.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_msg_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_notify_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_pip_environment.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_prompt_router.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_safety_heal.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_session_ready.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.55.0 → agentwire_dev-1.56.0}/tests/unit/test_window_cycling_binding.py +0 -0
- {agentwire_dev-1.55.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
|
|
@@ -52,25 +52,37 @@ def council_start(name: str = "", roster: str = "", model: str = "") -> str:
|
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
@mcp.tool()
|
|
55
|
-
def council_stop(name: str = "") -> str:
|
|
55
|
+
def council_stop(name: str = "", minutes: bool = True, synthesis: str = "") -> str:
|
|
56
56
|
"""Stop a council sitting: kill all soul sessions + the orchestrator.
|
|
57
57
|
|
|
58
|
-
Prompt history under ``~/.agentwire/council/<name>/prompts/`` is kept
|
|
58
|
+
Prompt history under ``~/.agentwire/council/<name>/prompts/`` is kept, and
|
|
59
|
+
by default the sitting's minutes artifact is rendered on the way out
|
|
60
|
+
(when any prompt exists) — pass your synthesis so the record includes it.
|
|
59
61
|
|
|
60
62
|
Args:
|
|
61
63
|
name: Sitting name (empty = cwd-repo-slug / sole live sitting)
|
|
64
|
+
minutes: Render the minutes artifact (default True; skipped anyway
|
|
65
|
+
when the sitting has no prompt history)
|
|
66
|
+
synthesis: Your synthesis for the minutes — text, or a path to a file
|
|
62
67
|
|
|
63
68
|
Returns:
|
|
64
|
-
Which sessions were killed.
|
|
69
|
+
Which sessions were killed, plus the minutes path when rendered.
|
|
65
70
|
"""
|
|
66
71
|
args = ["council", "stop"]
|
|
67
72
|
if name:
|
|
68
73
|
args += ["--name", name]
|
|
74
|
+
if not minutes:
|
|
75
|
+
args += ["--no-minutes"]
|
|
76
|
+
if synthesis:
|
|
77
|
+
args += ["--synthesis", synthesis]
|
|
69
78
|
data = run_agentwire_cmd(args, timeout=60)
|
|
70
79
|
if not data.get("success"):
|
|
71
80
|
return f"Failed to stop council: {data.get('error', 'Unknown error')}"
|
|
72
81
|
killed = data.get("killed") or []
|
|
73
|
-
|
|
82
|
+
out = f"{_council_tag(data)}Council stopped. Killed: {', '.join(killed) or '(none)'}"
|
|
83
|
+
if data.get("minutes"):
|
|
84
|
+
out += f"\nMinutes: {data['minutes']}"
|
|
85
|
+
return out
|
|
74
86
|
|
|
75
87
|
|
|
76
88
|
@mcp.tool()
|
|
@@ -191,3 +203,38 @@ def council_collect(prompt_id: int = 0, timeout: int = 120, name: str = "") -> s
|
|
|
191
203
|
for r in data.get("replies") or []:
|
|
192
204
|
lines.append(f"\n--- {r['soul']} ({r['kind']}) ---\n{r['text']}")
|
|
193
205
|
return "\n".join(lines)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@mcp.tool()
|
|
209
|
+
def council_minutes(name: str = "", prompt: str = "", synthesis: str = "") -> str:
|
|
210
|
+
"""Render a sitting's minutes: question, synthesis, verbatim takes → HTML.
|
|
211
|
+
|
|
212
|
+
Deterministically renders the sitting's persisted prompt history
|
|
213
|
+
(question + attributed take/ack/pass replies) plus your optional
|
|
214
|
+
synthesis into a self-contained HTML artifact at
|
|
215
|
+
``~/.agentwire/artifacts/council-<name>-minutes/index.html``, and opens
|
|
216
|
+
it as a portal artifact window when the portal is up. Works for live and
|
|
217
|
+
dismissed sittings alike — prompt history survives ``council_stop``.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
prompt: Prompt id to render, or 'all' (empty = all)
|
|
221
|
+
synthesis: Your synthesis of the takes — text, or a path to a file
|
|
222
|
+
name: Sitting name (empty = cwd-repo-slug / sole live sitting)
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
The rendered artifact's path, and whether a portal window opened.
|
|
226
|
+
"""
|
|
227
|
+
args = ["council", "minutes"]
|
|
228
|
+
if name:
|
|
229
|
+
args += ["--name", name]
|
|
230
|
+
if prompt:
|
|
231
|
+
args += ["--prompt", prompt]
|
|
232
|
+
if synthesis:
|
|
233
|
+
args += ["--synthesis", synthesis]
|
|
234
|
+
data = run_agentwire_cmd(args, timeout=60)
|
|
235
|
+
if not data.get("success"):
|
|
236
|
+
return f"Failed to render minutes: {data.get('error') or data}"
|
|
237
|
+
out = f"{_council_tag(data)}Minutes: {data.get('path')}"
|
|
238
|
+
if data.get("opened"):
|
|
239
|
+
out += "\nOpened as a portal artifact window."
|
|
240
|
+
return out
|
|
@@ -19,9 +19,9 @@ def worktree_create(
|
|
|
19
19
|
|
|
20
20
|
The spawn half of the worktree lifecycle (paired with worktree_status /
|
|
21
21
|
worktree_list / worktree_remove). Creates a branch off origin/<base>, a
|
|
22
|
-
worktree
|
|
23
|
-
worktree-session safety etiquette auto-injected. This is how
|
|
24
|
-
anchor fans out correspondents.
|
|
22
|
+
worktree at ~/worktrees/<project>/<name>/, and a tmux session running an
|
|
23
|
+
agent with the worktree-session safety etiquette auto-injected. This is how
|
|
24
|
+
a Briefing Mode anchor fans out correspondents.
|
|
25
25
|
|
|
26
26
|
Args:
|
|
27
27
|
name: Worktree/branch name (becomes the branch + session suffix).
|
|
@@ -5,6 +5,7 @@ This file lives in project directories and is the source of truth for session co
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import subprocess
|
|
8
|
+
import sys
|
|
8
9
|
from dataclasses import dataclass, field
|
|
9
10
|
from enum import Enum
|
|
10
11
|
from pathlib import Path
|
|
@@ -138,6 +139,47 @@ def compose_session_type(harness: str, posture: str) -> str:
|
|
|
138
139
|
return harness
|
|
139
140
|
|
|
140
141
|
|
|
142
|
+
@dataclass
|
|
143
|
+
class WorktreeOverrides:
|
|
144
|
+
"""Per-project overrides for `agentwire worktree` (the `worktree:` block).
|
|
145
|
+
|
|
146
|
+
Sits between per-invocation flags and the global config in the
|
|
147
|
+
precedence chain (#705): CLI/MCP flag → this block → global `worktree:`
|
|
148
|
+
in config.yaml → built-ins. ``dir`` only moves the root — the nesting
|
|
149
|
+
shape is unchanged: ``<dir>/<project>/<name>/``.
|
|
150
|
+
"""
|
|
151
|
+
dir: Optional[Path] = None # overrides worktree.worktree_dir for this project
|
|
152
|
+
base: Optional[str] = None # overrides worktree.default_base for this project
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
_WORKTREE_OVERRIDE_KEYS = {"dir", "base"}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _parse_worktree_overrides(data: Any) -> WorktreeOverrides:
|
|
159
|
+
"""Parse the optional ``worktree:`` block. Unknown keys warn, never fail."""
|
|
160
|
+
if not isinstance(data, dict):
|
|
161
|
+
if data is not None:
|
|
162
|
+
print(
|
|
163
|
+
f"Warning: .agentwire.yml `worktree:` should be a mapping "
|
|
164
|
+
f"with dir/base keys, got {type(data).__name__} — ignoring",
|
|
165
|
+
file=sys.stderr,
|
|
166
|
+
)
|
|
167
|
+
return WorktreeOverrides()
|
|
168
|
+
unknown = sorted(set(data) - _WORKTREE_OVERRIDE_KEYS)
|
|
169
|
+
if unknown:
|
|
170
|
+
print(
|
|
171
|
+
f"Warning: unknown key(s) in .agentwire.yml `worktree:` block: "
|
|
172
|
+
f"{', '.join(unknown)} (expected: dir, base)",
|
|
173
|
+
file=sys.stderr,
|
|
174
|
+
)
|
|
175
|
+
dir_val = data.get("dir")
|
|
176
|
+
base_val = data.get("base")
|
|
177
|
+
return WorktreeOverrides(
|
|
178
|
+
dir=Path(str(dir_val)).expanduser() if dir_val else None,
|
|
179
|
+
base=str(base_val) if base_val else None,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
141
183
|
@dataclass
|
|
142
184
|
class ProjectConfig:
|
|
143
185
|
"""Project-level configuration for a project directory.
|
|
@@ -154,6 +196,7 @@ class ProjectConfig:
|
|
|
154
196
|
parent: Optional[str] = None # Parent session for hierarchical notifications
|
|
155
197
|
shell: Optional[str] = None # Default shell for task commands (default: /bin/sh)
|
|
156
198
|
tasks: dict[str, Any] = field(default_factory=dict) # Task definitions (raw dict, parsed by tasks.py)
|
|
199
|
+
worktree: WorktreeOverrides = field(default_factory=WorktreeOverrides) # `agentwire worktree` overrides (#705)
|
|
157
200
|
|
|
158
201
|
def to_dict(self) -> dict:
|
|
159
202
|
"""Convert to dictionary for YAML serialization."""
|
|
@@ -170,6 +213,13 @@ class ProjectConfig:
|
|
|
170
213
|
d["shell"] = self.shell
|
|
171
214
|
if self.tasks:
|
|
172
215
|
d["tasks"] = self.tasks
|
|
216
|
+
if self.worktree.dir or self.worktree.base:
|
|
217
|
+
wt: dict[str, Any] = {}
|
|
218
|
+
if self.worktree.dir:
|
|
219
|
+
wt["dir"] = str(self.worktree.dir)
|
|
220
|
+
if self.worktree.base:
|
|
221
|
+
wt["base"] = self.worktree.base
|
|
222
|
+
d["worktree"] = wt
|
|
173
223
|
return d
|
|
174
224
|
|
|
175
225
|
@classmethod
|
|
@@ -189,6 +239,7 @@ class ProjectConfig:
|
|
|
189
239
|
parent=parent,
|
|
190
240
|
shell=shell,
|
|
191
241
|
tasks=tasks if isinstance(tasks, dict) else {},
|
|
242
|
+
worktree=_parse_worktree_overrides(data.get("worktree")),
|
|
192
243
|
)
|
|
193
244
|
|
|
194
245
|
|
|
@@ -32,3 +32,11 @@ user's prompts out to them, collect their takes, and synthesize.
|
|
|
32
32
|
- `council_status` shows roster health if something seems stuck.
|
|
33
33
|
- Don't editorialize the lenses away. If Critic and Gut disagree, the
|
|
34
34
|
disagreement *is* the product — surface it.
|
|
35
|
+
|
|
36
|
+
## Closing the sitting
|
|
37
|
+
|
|
38
|
+
When the user wraps up, stop with your synthesis so the minutes artifact
|
|
39
|
+
carries it: `council_stop(synthesis="<your synthesis>")`. Stop renders the
|
|
40
|
+
minutes (question + verbatim attributed takes + your synthesis) automatically
|
|
41
|
+
whenever any prompt was asked. To (re)render the record at any other moment —
|
|
42
|
+
including for a past sitting — use `council_minutes(synthesis=...)`.
|