agent-cli 0.84.2__tar.gz → 0.86.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.
- {agent_cli-0.84.2/agent_cli/dev/skill → agent_cli-0.86.0/.claude/skills/agent-cli-dev}/SKILL.md +4 -3
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.claude/skills/agent-cli-dev/examples.md +1 -1
- {agent_cli-0.84.2/.claude → agent_cli-0.86.0/.claude-plugin}/skills/agent-cli-dev/SKILL.md +4 -3
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.claude-plugin/skills/agent-cli-dev/examples.md +1 -1
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.pre-commit-config.yaml +1 -1
- {agent_cli-0.84.2 → agent_cli-0.86.0}/PKG-INFO +1 -1
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/cli.py +4 -3
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/config.py +1 -0
- agent_cli-0.86.0/agent_cli/dev/_config.py +59 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/cli.py +72 -8
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/coding_agents/base.py +11 -0
- agent_cli-0.86.0/agent_cli/dev/coding_agents/codex.py +92 -0
- agent_cli-0.86.0/agent_cli/dev/hooks.py +138 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/launch.py +20 -33
- {agent_cli-0.84.2/.claude-plugin/skills/agent-cli-dev → agent_cli-0.86.0/agent_cli/dev/skill}/SKILL.md +4 -3
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/skill/examples.md +1 -1
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/worktree.py +28 -1
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/example-config.toml +7 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/dev.md +34 -3
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/dev/test_cli.py +243 -7
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/dev/test_coding_agents.py +60 -0
- agent_cli-0.86.0/tests/dev/test_hooks.py +154 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/dev/test_launch.py +83 -1
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/dev/test_worktree.py +117 -0
- agent_cli-0.84.2/agent_cli/dev/coding_agents/codex.py +0 -24
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.claude-plugin/README.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.claude-plugin/marketplace.json +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.claude-plugin/plugin.json +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.cursorrules +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.dockerignore +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.env.example +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/logo.svg +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/release-drafter.yml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/renovate.json +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/scripts/check_extras_sync.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/scripts/check_plugin_skill_sync.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/scripts/sync_extras.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/scripts/sync_requirements.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/workflows/automerge.yml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/workflows/docker.yml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/workflows/docs.yml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/workflows/markdown-code-runner.yml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/workflows/pytest.yml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/workflows/release-drafter.yml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/workflows/release.yml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.github/workflows/toc.yaml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.gitignore +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.jscpd.json +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.prompts/docs-review.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/.prompts/pr-review.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/CLAUDE.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/LICENSE +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/README.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/__main__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_extras.json +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/.gitkeep +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/audio.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/faster-whisper.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/kokoro.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/llm.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/memory.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/mlx-whisper.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/piper.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/rag.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/server.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/speed.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/vad.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/vectordb.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/whisper-transformers.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_requirements/wyoming.txt +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/_tools.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/_voice_agent_common.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/assistant.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/autocorrect.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/chat.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/memory/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/memory/add.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/memory/proxy.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/rag_proxy.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/speak.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/transcribe.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/transcribe_live.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/agents/voice_edit.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/api.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/config_cmd.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/constants.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/audio.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/audio_format.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/chroma.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/deps.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/openai_proxy.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/process.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/reranker.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/sse.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/transcription_logger.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/utils.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/vad.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/core/watch.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/daemon/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/daemon/cli.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/_branch_name.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/_output.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/cleanup.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/coding_agents/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/coding_agents/aider.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/coding_agents/claude.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/coding_agents/continue_dev.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/coding_agents/copilot.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/coding_agents/cursor_agent.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/coding_agents/gemini.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/coding_agents/opencode.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/coding_agents/registry.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/base.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/cursor.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/emacs.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/jetbrains.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/nano.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/neovim.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/registry.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/sublime.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/vim.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/vscode.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/editors/zed.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/project.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/registry.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/terminals/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/terminals/apple_terminal.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/terminals/base.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/terminals/gnome.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/terminals/iterm2.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/terminals/kitty.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/terminals/registry.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/terminals/tmux.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/terminals/warp.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/dev/terminals/zellij.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/docs_gen.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/install/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/install/common.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/install/extras.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/install/hotkeys.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/install/launchd.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/install/service_config.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/install/services.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/install/systemd.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_files.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_filters.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_git.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_indexer.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_ingest.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_persistence.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_prompt.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_retrieval.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_store.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_streaming.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/_tasks.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/api.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/client.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/engine.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/entities.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/memory/models.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/opts.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/py.typed +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/_indexer.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/_indexing.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/_prompt.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/_retriever.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/_store.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/_utils.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/api.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/client.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/engine.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/rag/models.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/.runtime/.gitkeep +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/linux-hotkeys/README.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/linux-hotkeys/toggle-autocorrect.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/linux-hotkeys/toggle-transcription.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/linux-hotkeys/toggle-voice-edit.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/macos-hotkeys/README.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/macos-hotkeys/skhd-config-example +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/macos-hotkeys/toggle-autocorrect.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/macos-hotkeys/toggle-transcription.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/macos-hotkeys/toggle-voice-edit.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/nvidia-asr-server/README.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/nvidia-asr-server/pyproject.toml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/nvidia-asr-server/server.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/nvidia-asr-server/shell.nix +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/nvidia-asr-server/uv.lock +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/run-openwakeword.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/setup-linux-hotkeys.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/setup-linux.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/setup-macos-hotkeys.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/setup-macos.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/setup-windows.ps1 +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/start-all-services-windows.ps1 +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/scripts/start-all-services.sh +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/cli.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/common.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/model_manager.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/model_registry.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/proxy/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/proxy/api.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/streaming.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/tts/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/tts/api.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/tts/backends/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/tts/backends/base.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/tts/backends/kokoro.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/tts/backends/piper.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/tts/model_manager.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/tts/model_registry.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/tts/wyoming_handler.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/api.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/backends/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/backends/base.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/backends/faster_whisper.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/backends/mlx.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/backends/transformers.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/languages.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/model_manager.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/model_registry.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/server/whisper/wyoming_handler.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/services/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/services/_wyoming_utils.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/services/asr.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/services/llm.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/services/tts.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/agent_cli/services/wake_word.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docker/docker-compose.yml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docker/memory-proxy.Dockerfile +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docker/rag-proxy.Dockerfile +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docker/transcribe-proxy.Dockerfile +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docker/tts.Dockerfile +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docker/whisper.Dockerfile +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/CNAME +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/architecture/index.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/architecture/memory.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/architecture/rag.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/assistant.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/autocorrect.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/chat.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/config.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/daemon.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/index.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/install-extras.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/install-hotkeys.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/install-services.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/memory.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/rag-proxy.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/server/index.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/server/transcribe-proxy.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/server/tts.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/server/whisper.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/speak.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/start-services.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/transcribe-live.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/transcribe.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/commands/voice-edit.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/configuration.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/getting-started.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/iOS_Shortcut_Guide.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/index.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/installation/docker.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/installation/index.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/installation/linux.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/installation/macos.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/installation/nixos.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/installation/windows.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/logo-clean.svg +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/overrides/partials/integrations/analytics/custom.html +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/run_markdown_code_runner.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/docs/system-integration.md +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/example.agent-cli-config.toml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/justfile +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/pyproject.toml +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/shell.nix +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_fix_my_text.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_interactive.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_interactive_extra.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_memory_add.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_speak.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_speak_e2e.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_transcribe.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_transcribe_agent.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_transcribe_e2e.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_transcribe_live.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_transcribe_recovery.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_tts_common.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_tts_common_extra.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_voice_agent_common.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_voice_edit.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_voice_edit_e2e.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/agents/test_wake_word_assistant.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/conftest.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/core/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/core/test_audio.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/core/test_audio_format.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/core/test_chroma.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/core/test_sse.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/core/test_vad.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/core/test_watch.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/dev/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/dev/test_editors.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/dev/test_project.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/dev/test_terminals.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/dev/test_verification.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/install/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/install/test_extras.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_api_health.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_api_integration_liveish.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_client.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_engine.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_files.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_filters.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_git_integration.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_indexer.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_memory_integration.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_proxy_passthrough.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_store.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/memory/test_utils.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/mocks/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/mocks/audio.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/mocks/llm.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/mocks/wyoming.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/__init__.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_api.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_engine.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_history.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_indexer.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_indexing.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_rag_client.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_rag_integration_liveish.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_rag_proxy_passthrough.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_retriever.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_store.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/rag/test_utils.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_api.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_api_integration.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_asr.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_asr_recovery.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_audio_e2e.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_cli.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_config.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_config_cmd.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_daemon.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_docs_gen.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_env_vars.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_json_output.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_llm.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_llm_gemini.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_memory_tools.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_mlx_backend.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_process_manager.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_requires_extras.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_server_streaming.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_server_tts.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_server_whisper.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_services.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_tools.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_transformers_backend.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_tts.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_utils.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_wake_word.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/tests/test_wyoming_utils.py +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/uv.lock +0 -0
- {agent_cli-0.84.2 → agent_cli-0.86.0}/zensical.toml +0 -0
{agent_cli-0.84.2/agent_cli/dev/skill → agent_cli-0.86.0/.claude/skills/agent-cli-dev}/SKILL.md
RENAMED
|
@@ -56,7 +56,7 @@ agent-cli dev new <branch-name> --from HEAD --agent --prompt-file path/to/prompt
|
|
|
56
56
|
This creates:
|
|
57
57
|
1. A new git worktree with its own branch
|
|
58
58
|
2. Runs project setup (installs dependencies)
|
|
59
|
-
3. Saves your prompt to `.claude
|
|
59
|
+
3. Saves your prompt to a unique task file in `.claude/` in the worktree (for reference)
|
|
60
60
|
4. Opens a new terminal tab with an AI coding agent
|
|
61
61
|
5. Passes your prompt to the agent
|
|
62
62
|
|
|
@@ -144,11 +144,12 @@ agent-cli dev agent review-auth -m tmux --prompt-file .claude/review-tests.md
|
|
|
144
144
|
|
|
145
145
|
Key rules for same-worktree launches:
|
|
146
146
|
- Use `dev agent`, not `dev new`, after the worktree already exists
|
|
147
|
+
- Use `dev agent -a <agent>` to select a specific agent for an existing worktree; `--with-agent` remains a deprecated alias on this subcommand
|
|
147
148
|
- Use `-m tmux` for headless or scripted launching; it works even when not already inside tmux
|
|
148
149
|
- Each launch joins the same deterministic repo-scoped tmux session, so related agents stay grouped together
|
|
149
150
|
- Ask each agent to write to a unique report path such as `.claude/REPORT-security-<run-id>.md` or `.claude/REPORT-tests-<run-id>.md`
|
|
150
151
|
- If you rerun the same prompt repeatedly, include a timestamp or other run id in the report filename so later runs do not overwrite earlier ones
|
|
151
|
-
-
|
|
152
|
+
- Each agent launch gets its own unique task file in `.claude/` (e.g., `TASK-{timestamp}-{hex}.md`), so parallel launches do not overwrite each other
|
|
152
153
|
|
|
153
154
|
### Prompt guidance for shared worktrees
|
|
154
155
|
|
|
@@ -174,7 +175,7 @@ agent-cli dev new validation-a --from HEAD --agent --with-agent codex -m tmux \
|
|
|
174
175
|
--prompt-file .claude/validation-a.md
|
|
175
176
|
```
|
|
176
177
|
|
|
177
|
-
This works without an attached terminal. `agent-cli` creates or reuses a detached tmux session and returns a pane handle plus attach command.
|
|
178
|
+
This works without an attached terminal. `agent-cli` creates or reuses a detached tmux session and returns a pane handle plus attach command. Launches may also run pre-launch preparation by default; use `--no-hooks` only when you explicitly need to bypass that behavior.
|
|
178
179
|
|
|
179
180
|
## Example: Multi-feature implementation
|
|
180
181
|
|
|
@@ -585,7 +585,7 @@ Write findings to .claude/REPORT-tests-$run_id.md:
|
|
|
585
585
|
- If you rerun the same prompt often, include a timestamp or run id in the filename so reports do not get replaced
|
|
586
586
|
- `-m tmux` works even when the caller is not already inside tmux
|
|
587
587
|
- All three agents land in the same deterministic tmux session for that repo
|
|
588
|
-
-
|
|
588
|
+
- Each agent launch gets its own unique task file in `.claude/`, so parallel launches do not conflict
|
|
589
589
|
|
|
590
590
|
## Scenario 7: Parallel test validation
|
|
591
591
|
|
|
@@ -56,7 +56,7 @@ agent-cli dev new <branch-name> --from HEAD --agent --prompt-file path/to/prompt
|
|
|
56
56
|
This creates:
|
|
57
57
|
1. A new git worktree with its own branch
|
|
58
58
|
2. Runs project setup (installs dependencies)
|
|
59
|
-
3. Saves your prompt to `.claude
|
|
59
|
+
3. Saves your prompt to a unique task file in `.claude/` in the worktree (for reference)
|
|
60
60
|
4. Opens a new terminal tab with an AI coding agent
|
|
61
61
|
5. Passes your prompt to the agent
|
|
62
62
|
|
|
@@ -144,11 +144,12 @@ agent-cli dev agent review-auth -m tmux --prompt-file .claude/review-tests.md
|
|
|
144
144
|
|
|
145
145
|
Key rules for same-worktree launches:
|
|
146
146
|
- Use `dev agent`, not `dev new`, after the worktree already exists
|
|
147
|
+
- Use `dev agent -a <agent>` to select a specific agent for an existing worktree; `--with-agent` remains a deprecated alias on this subcommand
|
|
147
148
|
- Use `-m tmux` for headless or scripted launching; it works even when not already inside tmux
|
|
148
149
|
- Each launch joins the same deterministic repo-scoped tmux session, so related agents stay grouped together
|
|
149
150
|
- Ask each agent to write to a unique report path such as `.claude/REPORT-security-<run-id>.md` or `.claude/REPORT-tests-<run-id>.md`
|
|
150
151
|
- If you rerun the same prompt repeatedly, include a timestamp or other run id in the report filename so later runs do not overwrite earlier ones
|
|
151
|
-
-
|
|
152
|
+
- Each agent launch gets its own unique task file in `.claude/` (e.g., `TASK-{timestamp}-{hex}.md`), so parallel launches do not overwrite each other
|
|
152
153
|
|
|
153
154
|
### Prompt guidance for shared worktrees
|
|
154
155
|
|
|
@@ -174,7 +175,7 @@ agent-cli dev new validation-a --from HEAD --agent --with-agent codex -m tmux \
|
|
|
174
175
|
--prompt-file .claude/validation-a.md
|
|
175
176
|
```
|
|
176
177
|
|
|
177
|
-
This works without an attached terminal. `agent-cli` creates or reuses a detached tmux session and returns a pane handle plus attach command.
|
|
178
|
+
This works without an attached terminal. `agent-cli` creates or reuses a detached tmux session and returns a pane handle plus attach command. Launches may also run pre-launch preparation by default; use `--no-hooks` only when you explicitly need to bypass that behavior.
|
|
178
179
|
|
|
179
180
|
## Example: Multi-feature implementation
|
|
180
181
|
|
|
@@ -585,7 +585,7 @@ Write findings to .claude/REPORT-tests-$run_id.md:
|
|
|
585
585
|
- If you rerun the same prompt often, include a timestamp or run id in the filename so reports do not get replaced
|
|
586
586
|
- `-m tmux` works even when the caller is not already inside tmux
|
|
587
587
|
- All three agents land in the same deterministic tmux session for that repo
|
|
588
|
-
-
|
|
588
|
+
- Each agent launch gets its own unique task file in `.claude/`, so parallel launches do not conflict
|
|
589
589
|
|
|
590
590
|
## Scenario 7: Parallel test validation
|
|
591
591
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.86.0
|
|
4
4
|
Summary: A suite of AI-powered command-line tools for text correction, audio transcription, and voice assistance.
|
|
5
5
|
Project-URL: Homepage, https://github.com/basnijholt/agent-cli
|
|
6
6
|
Author-email: Bas Nijholt <bas@nijho.lt>
|
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Annotated
|
|
7
|
+
from typing import Annotated, Any
|
|
8
8
|
|
|
9
9
|
import typer
|
|
10
10
|
from rich.table import Table
|
|
@@ -93,7 +93,7 @@ def main(
|
|
|
93
93
|
set_process_title(ctx.invoked_subcommand)
|
|
94
94
|
|
|
95
95
|
|
|
96
|
-
def set_config_defaults(ctx: typer.Context, config_file: str | None) ->
|
|
96
|
+
def set_config_defaults(ctx: typer.Context, config_file: str | None) -> dict[str, Any]:
|
|
97
97
|
"""Set the default values for the CLI based on the config file."""
|
|
98
98
|
config = load_config(config_file)
|
|
99
99
|
wildcard_config = normalize_provider_defaults(config.get("defaults", {}))
|
|
@@ -101,7 +101,7 @@ def set_config_defaults(ctx: typer.Context, config_file: str | None) -> None:
|
|
|
101
101
|
command_key = ctx.command.name or ""
|
|
102
102
|
if not command_key:
|
|
103
103
|
ctx.default_map = wildcard_config
|
|
104
|
-
return
|
|
104
|
+
return config
|
|
105
105
|
|
|
106
106
|
# For nested subcommands (e.g., "memory proxy"), build "memory.proxy"
|
|
107
107
|
if ctx.parent and ctx.parent.command.name and ctx.parent.command.name != "agent-cli":
|
|
@@ -109,6 +109,7 @@ def set_config_defaults(ctx: typer.Context, config_file: str | None) -> None:
|
|
|
109
109
|
|
|
110
110
|
command_config = normalize_provider_defaults(config.get(command_key, {}))
|
|
111
111
|
ctx.default_map = {**wildcard_config, **command_config}
|
|
112
|
+
return config
|
|
112
113
|
|
|
113
114
|
|
|
114
115
|
# Import commands from other modules to register them
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Helpers for reading runtime dev configuration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
from agent_cli.config import load_config
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_runtime_config() -> dict[str, Any]:
|
|
13
|
+
"""Return the config dict active for the current CLI invocation."""
|
|
14
|
+
ctx = click.get_current_context(silent=True)
|
|
15
|
+
while ctx is not None:
|
|
16
|
+
if isinstance(ctx.obj, dict) and isinstance(ctx.obj.get("config"), dict):
|
|
17
|
+
return ctx.obj["config"]
|
|
18
|
+
ctx = ctx.parent
|
|
19
|
+
return load_config(None)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_dev_config() -> dict[str, Any]:
|
|
23
|
+
"""Return the `[dev]` config table for the current CLI invocation."""
|
|
24
|
+
dev_config = get_runtime_config().get("dev", {})
|
|
25
|
+
return dev_config if isinstance(dev_config, dict) else {}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_dev_table(name: str) -> dict[str, Any]:
|
|
29
|
+
"""Return a merged `[dev.<name>]` table from nested or flattened config."""
|
|
30
|
+
result: dict[str, Any] = {}
|
|
31
|
+
|
|
32
|
+
nested = get_dev_config().get(name)
|
|
33
|
+
if isinstance(nested, dict):
|
|
34
|
+
result.update(nested)
|
|
35
|
+
|
|
36
|
+
flat = get_runtime_config().get(f"dev.{name}")
|
|
37
|
+
if isinstance(flat, dict):
|
|
38
|
+
result.update(flat)
|
|
39
|
+
|
|
40
|
+
return result
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_dev_child_tables(name: str) -> dict[str, dict[str, Any]]:
|
|
44
|
+
"""Return merged `[dev.<name>.<child>]` tables keyed by child name."""
|
|
45
|
+
result = {
|
|
46
|
+
child: value for child, value in get_dev_table(name).items() if isinstance(value, dict)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
prefix = f"dev.{name}."
|
|
50
|
+
for key, value in get_runtime_config().items():
|
|
51
|
+
if key.startswith(prefix) and isinstance(value, dict):
|
|
52
|
+
result[key[len(prefix) :]] = value
|
|
53
|
+
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_dev_child_table(name: str, child: str) -> dict[str, Any]:
|
|
58
|
+
"""Return a single merged `[dev.<name>.<child>]` table."""
|
|
59
|
+
return get_dev_child_tables(name).get(child, {})
|
|
@@ -23,6 +23,7 @@ from . import cleanup, coding_agents, editors, terminals, worktree
|
|
|
23
23
|
from ._branch_name import AGENTS as BRANCH_NAME_AGENTS
|
|
24
24
|
from ._branch_name import generate_ai_branch_name, generate_random_branch_name
|
|
25
25
|
from ._output import error, info, success, warn
|
|
26
|
+
from .hooks import LaunchContext, prepare_agent_launch
|
|
26
27
|
from .launch import (
|
|
27
28
|
get_agent_env,
|
|
28
29
|
launch_agent,
|
|
@@ -83,7 +84,11 @@ def dev_callback(
|
|
|
83
84
|
Creates isolated working directories for each feature branch. Each worktree
|
|
84
85
|
has its own branch, allowing parallel development without stashing changes.
|
|
85
86
|
"""
|
|
86
|
-
set_config_defaults(ctx, config_file)
|
|
87
|
+
config = set_config_defaults(ctx, config_file)
|
|
88
|
+
if isinstance(ctx.obj, dict):
|
|
89
|
+
ctx.obj["config"] = config
|
|
90
|
+
else:
|
|
91
|
+
ctx.obj = {"config": config}
|
|
87
92
|
|
|
88
93
|
# The [dev] section config is intended for `dev new` options.
|
|
89
94
|
# Click expects subcommand defaults under ctx.default_map["new"].
|
|
@@ -368,7 +373,7 @@ def new(
|
|
|
368
373
|
typer.Option(
|
|
369
374
|
"--prompt",
|
|
370
375
|
"-p",
|
|
371
|
-
help="Initial task for the AI agent. Saved to .claude/
|
|
376
|
+
help="Initial task for the AI agent. Saved to a unique file in .claude/ to avoid conflicts. Implies --agent. Example: --prompt='Fix the login bug'",
|
|
372
377
|
),
|
|
373
378
|
] = None,
|
|
374
379
|
prompt_file: Annotated[
|
|
@@ -390,6 +395,13 @@ def new(
|
|
|
390
395
|
help="Launch the agent in a specific multiplexer. Currently supported: tmux. When started outside tmux, creates or reuses a detached session and reports the pane handle",
|
|
391
396
|
),
|
|
392
397
|
] = None,
|
|
398
|
+
hooks: Annotated[
|
|
399
|
+
bool,
|
|
400
|
+
typer.Option(
|
|
401
|
+
"--hooks/--no-hooks",
|
|
402
|
+
help="Run built-in agent preparation (like Codex auto-trust) and configured pre-launch hooks before starting the agent",
|
|
403
|
+
),
|
|
404
|
+
] = True,
|
|
393
405
|
verbose: Annotated[
|
|
394
406
|
bool,
|
|
395
407
|
typer.Option(
|
|
@@ -491,6 +503,18 @@ def new(
|
|
|
491
503
|
if resolved_agent and resolved_agent.is_available():
|
|
492
504
|
merged_args = merge_agent_args(resolved_agent, agent_args)
|
|
493
505
|
agent_env = get_agent_env(resolved_agent)
|
|
506
|
+
prepare_agent_launch(
|
|
507
|
+
LaunchContext(
|
|
508
|
+
agent=resolved_agent,
|
|
509
|
+
worktree_path=result.path,
|
|
510
|
+
repo_root=repo_root,
|
|
511
|
+
branch=result.branch,
|
|
512
|
+
worktree_name=result.path.name,
|
|
513
|
+
task_file=task_file,
|
|
514
|
+
agent_env=agent_env,
|
|
515
|
+
),
|
|
516
|
+
hooks_enabled=hooks,
|
|
517
|
+
)
|
|
494
518
|
agent_handle = launch_agent(
|
|
495
519
|
result.path,
|
|
496
520
|
resolved_agent,
|
|
@@ -752,7 +776,9 @@ def status_cmd( # noqa: PLR0915
|
|
|
752
776
|
def remove(
|
|
753
777
|
name: Annotated[
|
|
754
778
|
str,
|
|
755
|
-
typer.Argument(
|
|
779
|
+
typer.Argument(
|
|
780
|
+
help="Worktree to remove. Can be branch name, directory name, or '.' for current"
|
|
781
|
+
),
|
|
756
782
|
],
|
|
757
783
|
force: Annotated[
|
|
758
784
|
bool,
|
|
@@ -816,7 +842,9 @@ def remove(
|
|
|
816
842
|
def path_cmd(
|
|
817
843
|
name: Annotated[
|
|
818
844
|
str,
|
|
819
|
-
typer.Argument(
|
|
845
|
+
typer.Argument(
|
|
846
|
+
help="Worktree to get path for. Can be branch name, directory name, or '.' for current"
|
|
847
|
+
),
|
|
820
848
|
],
|
|
821
849
|
) -> None:
|
|
822
850
|
"""Print the absolute path to a dev environment.
|
|
@@ -838,7 +866,9 @@ def path_cmd(
|
|
|
838
866
|
def open_editor(
|
|
839
867
|
name: Annotated[
|
|
840
868
|
str,
|
|
841
|
-
typer.Argument(
|
|
869
|
+
typer.Argument(
|
|
870
|
+
help="Worktree to open. Can be branch name, directory name, or '.' for current"
|
|
871
|
+
),
|
|
842
872
|
],
|
|
843
873
|
editor_name: Annotated[
|
|
844
874
|
str | None,
|
|
@@ -887,7 +917,7 @@ def start_agent(
|
|
|
887
917
|
name: Annotated[
|
|
888
918
|
str,
|
|
889
919
|
typer.Argument(
|
|
890
|
-
help="Worktree to start the agent in. Can be branch name or
|
|
920
|
+
help="Worktree to start the agent in. Can be branch name, directory name, or '.' for current",
|
|
891
921
|
),
|
|
892
922
|
],
|
|
893
923
|
agent_name: Annotated[
|
|
@@ -898,6 +928,14 @@ def start_agent(
|
|
|
898
928
|
help="Which agent: claude, codex, gemini, aider, copilot, cn, opencode, cursor-agent. Auto-detects if omitted",
|
|
899
929
|
),
|
|
900
930
|
] = None,
|
|
931
|
+
agent_name_deprecated: Annotated[
|
|
932
|
+
str | None,
|
|
933
|
+
typer.Option(
|
|
934
|
+
"--with-agent",
|
|
935
|
+
hidden=True,
|
|
936
|
+
help="[Deprecated: use --agent/-a] Which agent to start",
|
|
937
|
+
),
|
|
938
|
+
] = None,
|
|
901
939
|
agent_args: Annotated[
|
|
902
940
|
list[str] | None,
|
|
903
941
|
typer.Option(
|
|
@@ -910,7 +948,7 @@ def start_agent(
|
|
|
910
948
|
typer.Option(
|
|
911
949
|
"--prompt",
|
|
912
950
|
"-p",
|
|
913
|
-
help="Initial task for the agent. Saved to .claude/
|
|
951
|
+
help="Initial task for the agent. Saved to a unique file in .claude/ to avoid conflicts. Example: --prompt='Add unit tests for auth'",
|
|
914
952
|
),
|
|
915
953
|
] = None,
|
|
916
954
|
prompt_file: Annotated[
|
|
@@ -932,6 +970,13 @@ def start_agent(
|
|
|
932
970
|
help="Launch the agent in a specific multiplexer instead of the current terminal. Currently supported: tmux",
|
|
933
971
|
),
|
|
934
972
|
] = None,
|
|
973
|
+
hooks: Annotated[
|
|
974
|
+
bool,
|
|
975
|
+
typer.Option(
|
|
976
|
+
"--hooks/--no-hooks",
|
|
977
|
+
help="Run built-in agent preparation (like Codex auto-trust) and configured pre-launch hooks before starting the agent",
|
|
978
|
+
),
|
|
979
|
+
] = True,
|
|
935
980
|
) -> None:
|
|
936
981
|
"""Start an AI coding agent in an existing dev environment.
|
|
937
982
|
|
|
@@ -944,6 +989,11 @@ def start_agent(
|
|
|
944
989
|
- `dev agent my-feature -a claude` — Start Claude specifically
|
|
945
990
|
- `dev agent my-feature -p "Continue the auth refactor"` — Start with a task
|
|
946
991
|
"""
|
|
992
|
+
# Handle deprecated --with-agent alias
|
|
993
|
+
if agent_name_deprecated is not None:
|
|
994
|
+
warn("--with-agent is deprecated for 'dev agent', use --agent/-a instead")
|
|
995
|
+
agent_name = agent_name or agent_name_deprecated
|
|
996
|
+
|
|
947
997
|
prompt = _resolve_prompt_text(prompt, prompt_file=prompt_file)
|
|
948
998
|
|
|
949
999
|
repo_root = _ensure_git_repo()
|
|
@@ -970,6 +1020,18 @@ def start_agent(
|
|
|
970
1020
|
|
|
971
1021
|
merged_args = merge_agent_args(agent, agent_args)
|
|
972
1022
|
agent_env = get_agent_env(agent)
|
|
1023
|
+
prepare_agent_launch(
|
|
1024
|
+
LaunchContext(
|
|
1025
|
+
agent=agent,
|
|
1026
|
+
worktree_path=wt.path,
|
|
1027
|
+
repo_root=repo_root,
|
|
1028
|
+
branch=wt.branch,
|
|
1029
|
+
worktree_name=wt.name,
|
|
1030
|
+
task_file=task_file,
|
|
1031
|
+
agent_env=agent_env,
|
|
1032
|
+
),
|
|
1033
|
+
hooks_enabled=hooks,
|
|
1034
|
+
)
|
|
973
1035
|
|
|
974
1036
|
if multiplexer:
|
|
975
1037
|
handle = launch_agent(
|
|
@@ -1190,7 +1252,9 @@ def _doctor_check_git() -> None:
|
|
|
1190
1252
|
def run_cmd(
|
|
1191
1253
|
name: Annotated[
|
|
1192
1254
|
str,
|
|
1193
|
-
typer.Argument(
|
|
1255
|
+
typer.Argument(
|
|
1256
|
+
help="Worktree to run command in. Can be branch name, directory name, or '.' for current"
|
|
1257
|
+
),
|
|
1194
1258
|
],
|
|
1195
1259
|
command: Annotated[
|
|
1196
1260
|
list[str],
|
|
@@ -117,6 +117,17 @@ class CodingAgent(ABC):
|
|
|
117
117
|
"""Get any additional environment variables needed."""
|
|
118
118
|
return {}
|
|
119
119
|
|
|
120
|
+
def prepare_launch(
|
|
121
|
+
self,
|
|
122
|
+
worktree_path: Path, # noqa: ARG002
|
|
123
|
+
repo_root: Path, # noqa: ARG002
|
|
124
|
+
) -> str | None:
|
|
125
|
+
"""Perform any agent-specific preparation before launch.
|
|
126
|
+
|
|
127
|
+
Returns an optional human-readable message describing a change that was made.
|
|
128
|
+
"""
|
|
129
|
+
return None
|
|
130
|
+
|
|
120
131
|
def __repr__(self) -> str: # noqa: D105
|
|
121
132
|
status = "available" if self.is_available() else "not installed"
|
|
122
133
|
return f"<{self.__class__.__name__} {self.name!r} ({status})>"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""OpenAI Codex CLI coding agent adapter."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from .base import CodingAgent
|
|
8
|
+
|
|
9
|
+
CODEX_CONFIG_PATH = Path.home() / ".codex" / "config.toml"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _project_section_header(path: Path) -> str:
|
|
13
|
+
"""Build the TOML section header for a trusted Codex project path."""
|
|
14
|
+
escaped = str(path).replace("\\", "\\\\").replace('"', '\\"')
|
|
15
|
+
return f'[projects."{escaped}"]'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _ensure_project_trusted(project_path: Path, config_path: Path | None = None) -> bool:
|
|
19
|
+
"""Ensure Codex trusts the launched project path for headless launches.
|
|
20
|
+
|
|
21
|
+
Returns True when the config file was modified.
|
|
22
|
+
"""
|
|
23
|
+
project_path = project_path.expanduser().resolve()
|
|
24
|
+
config_path = (config_path or CODEX_CONFIG_PATH).expanduser()
|
|
25
|
+
header = _project_section_header(project_path)
|
|
26
|
+
trust_line = 'trust_level = "trusted"'
|
|
27
|
+
|
|
28
|
+
if not config_path.exists():
|
|
29
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
30
|
+
config_path.write_text(f"{header}\n{trust_line}\n", encoding="utf-8")
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
text = config_path.read_text(encoding="utf-8")
|
|
34
|
+
lines = text.splitlines()
|
|
35
|
+
|
|
36
|
+
for idx, line in enumerate(lines):
|
|
37
|
+
if line.strip() != header:
|
|
38
|
+
continue
|
|
39
|
+
|
|
40
|
+
end = len(lines)
|
|
41
|
+
for j in range(idx + 1, len(lines)):
|
|
42
|
+
if lines[j].strip().startswith("[") and lines[j].strip().endswith("]"):
|
|
43
|
+
end = j
|
|
44
|
+
break
|
|
45
|
+
|
|
46
|
+
for j in range(idx + 1, end):
|
|
47
|
+
stripped = lines[j].strip()
|
|
48
|
+
if not stripped.startswith("trust_level"):
|
|
49
|
+
continue
|
|
50
|
+
if stripped == trust_line:
|
|
51
|
+
return False
|
|
52
|
+
msg = (
|
|
53
|
+
f"Codex trust for {project_path} is already configured in {config_path}. "
|
|
54
|
+
"Update that section or disable [dev].auto_trust."
|
|
55
|
+
)
|
|
56
|
+
raise RuntimeError(msg)
|
|
57
|
+
|
|
58
|
+
lines.insert(idx + 1, trust_line)
|
|
59
|
+
config_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
60
|
+
return True
|
|
61
|
+
|
|
62
|
+
new_text = text.rstrip("\n")
|
|
63
|
+
if new_text:
|
|
64
|
+
new_text += "\n\n"
|
|
65
|
+
new_text += f"{header}\n{trust_line}\n"
|
|
66
|
+
config_path.write_text(new_text, encoding="utf-8")
|
|
67
|
+
return True
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class Codex(CodingAgent):
|
|
71
|
+
"""OpenAI Codex CLI coding agent."""
|
|
72
|
+
|
|
73
|
+
name = "codex"
|
|
74
|
+
command = "codex"
|
|
75
|
+
install_url = "https://github.com/openai/codex"
|
|
76
|
+
detect_process_name = "codex"
|
|
77
|
+
|
|
78
|
+
def prompt_args(self, prompt: str) -> list[str]:
|
|
79
|
+
"""Return prompt as positional argument.
|
|
80
|
+
|
|
81
|
+
Codex accepts prompt as a positional argument:
|
|
82
|
+
`codex "your prompt here"`
|
|
83
|
+
|
|
84
|
+
See: codex --help
|
|
85
|
+
"""
|
|
86
|
+
return [prompt]
|
|
87
|
+
|
|
88
|
+
def prepare_launch(self, worktree_path: Path, repo_root: Path) -> str | None: # noqa: ARG002
|
|
89
|
+
"""Ensure Codex trusts the repository root before launch."""
|
|
90
|
+
if _ensure_project_trusted(repo_root, CODEX_CONFIG_PATH):
|
|
91
|
+
return f"Trusted {repo_root.resolve()} in Codex config"
|
|
92
|
+
return None
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""Launch preparation helpers for `agent-cli dev`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import shlex
|
|
7
|
+
import subprocess
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
11
|
+
|
|
12
|
+
from ._config import get_dev_child_table, get_dev_config, get_dev_table
|
|
13
|
+
from ._output import info
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from .coding_agents.base import CodingAgent
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class LaunchContext:
|
|
21
|
+
"""Context provided to built-in preparation and user hooks."""
|
|
22
|
+
|
|
23
|
+
agent: CodingAgent
|
|
24
|
+
worktree_path: Path
|
|
25
|
+
repo_root: Path
|
|
26
|
+
branch: str | None
|
|
27
|
+
worktree_name: str
|
|
28
|
+
task_file: Path | None
|
|
29
|
+
agent_env: dict[str, str]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _normalize_hook_commands(value: Any, *, config_key: str) -> list[str]:
|
|
33
|
+
"""Normalize a hook config entry to a list of shell commands."""
|
|
34
|
+
if value is None:
|
|
35
|
+
return []
|
|
36
|
+
if isinstance(value, str):
|
|
37
|
+
value = [value]
|
|
38
|
+
if not isinstance(value, list) or not all(isinstance(item, str) for item in value):
|
|
39
|
+
msg = f"{config_key} must be a string or list of strings"
|
|
40
|
+
raise RuntimeError(msg)
|
|
41
|
+
commands = [item.strip() for item in value if item.strip()]
|
|
42
|
+
if len(commands) != len(value):
|
|
43
|
+
msg = f"{config_key} contains an empty command"
|
|
44
|
+
raise RuntimeError(msg)
|
|
45
|
+
return commands
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _load_dev_hook_settings(agent_name: str) -> tuple[bool, list[str]]:
|
|
49
|
+
"""Load auto-trust and pre-launch hook settings for an agent."""
|
|
50
|
+
auto_trust = bool(get_dev_config().get("auto_trust", True))
|
|
51
|
+
global_hooks = get_dev_table("hooks")
|
|
52
|
+
agent_hooks = get_dev_child_table("hooks", agent_name)
|
|
53
|
+
|
|
54
|
+
pre_launch_hooks = _normalize_hook_commands(
|
|
55
|
+
global_hooks.get("pre_launch"),
|
|
56
|
+
config_key="[dev.hooks].pre_launch",
|
|
57
|
+
)
|
|
58
|
+
pre_launch_hooks.extend(
|
|
59
|
+
_normalize_hook_commands(
|
|
60
|
+
agent_hooks.get("pre_launch"),
|
|
61
|
+
config_key=f"[dev.hooks.{agent_name}].pre_launch",
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
return auto_trust, pre_launch_hooks
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _build_hook_env(context: LaunchContext) -> dict[str, str]:
|
|
68
|
+
"""Build the environment passed to pre-launch hooks."""
|
|
69
|
+
env = os.environ.copy()
|
|
70
|
+
env.update(context.agent_env)
|
|
71
|
+
env.update(
|
|
72
|
+
{
|
|
73
|
+
"AGENT_CLI_AGENT": context.agent.name,
|
|
74
|
+
"AGENT_CLI_WORKTREE": str(context.worktree_path),
|
|
75
|
+
"AGENT_CLI_REPO_ROOT": str(context.repo_root),
|
|
76
|
+
"AGENT_CLI_BRANCH": context.branch or "",
|
|
77
|
+
"AGENT_CLI_NAME": context.worktree_name,
|
|
78
|
+
"AGENT_CLI_TASK_FILE": str(context.task_file or ""),
|
|
79
|
+
# Keep the proposal name as an alias for compatibility.
|
|
80
|
+
"AGENT_CLI_PROMPT_FILE": str(context.task_file or ""),
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
return env
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _resolve_hook_command(command: str) -> list[str]:
|
|
87
|
+
"""Parse a configured hook command into argv."""
|
|
88
|
+
argv = shlex.split(command)
|
|
89
|
+
if not argv:
|
|
90
|
+
msg = "Hook command cannot be empty"
|
|
91
|
+
raise RuntimeError(msg)
|
|
92
|
+
|
|
93
|
+
first = Path(argv[0]).expanduser()
|
|
94
|
+
if argv[0].startswith("~") or "/" in argv[0]:
|
|
95
|
+
argv[0] = str(first)
|
|
96
|
+
return argv
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _run_pre_launch_hook(command: str, context: LaunchContext) -> None:
|
|
100
|
+
"""Run a single pre-launch hook."""
|
|
101
|
+
argv = _resolve_hook_command(command)
|
|
102
|
+
info(f"Running pre-launch hook: {command}")
|
|
103
|
+
try:
|
|
104
|
+
result = subprocess.run(
|
|
105
|
+
argv,
|
|
106
|
+
cwd=context.worktree_path,
|
|
107
|
+
env=_build_hook_env(context),
|
|
108
|
+
check=False,
|
|
109
|
+
capture_output=True,
|
|
110
|
+
text=True,
|
|
111
|
+
)
|
|
112
|
+
except FileNotFoundError as e:
|
|
113
|
+
msg = f"Pre-launch hook not found: {argv[0]}"
|
|
114
|
+
raise RuntimeError(msg) from e
|
|
115
|
+
|
|
116
|
+
if result.returncode == 0:
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
details = (result.stderr or result.stdout).strip()
|
|
120
|
+
msg = f"Pre-launch hook failed ({result.returncode}): {command}"
|
|
121
|
+
if details:
|
|
122
|
+
msg += f"\n{details}"
|
|
123
|
+
raise RuntimeError(msg)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def prepare_agent_launch(context: LaunchContext, *, hooks_enabled: bool = True) -> None:
|
|
127
|
+
"""Run built-in preparation and configured pre-launch hooks."""
|
|
128
|
+
if not hooks_enabled:
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
auto_trust, pre_launch_hooks = _load_dev_hook_settings(context.agent.name)
|
|
132
|
+
if auto_trust and (
|
|
133
|
+
message := context.agent.prepare_launch(context.worktree_path, context.repo_root)
|
|
134
|
+
):
|
|
135
|
+
info(message)
|
|
136
|
+
|
|
137
|
+
for command in pre_launch_hooks:
|
|
138
|
+
_run_pre_launch_hook(command, context)
|