agent-cli 0.80.0__tar.gz → 0.81.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.80.0 → agent_cli-0.81.0}/.pre-commit-config.yaml +1 -1
- {agent_cli-0.80.0 → agent_cli-0.81.0}/PKG-INFO +1 -1
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_tools.py +1 -1
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/transcribe_live.py +1 -1
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/config.py +19 -4
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/deps.py +1 -1
- agent_cli-0.81.0/agent_cli/dev/_branch_name.py +371 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/cli.py +74 -86
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/worktree.py +2 -2
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/install/service_config.py +1 -1
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/dev.md +12 -1
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/dev/test_cli.py +469 -6
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/dev/test_worktree.py +7 -7
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_config.py +22 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.claude/skills/agent-cli-dev/SKILL.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.claude/skills/agent-cli-dev/examples.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.claude-plugin/README.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.claude-plugin/marketplace.json +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.claude-plugin/plugin.json +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.claude-plugin/skills/agent-cli-dev/SKILL.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.claude-plugin/skills/agent-cli-dev/examples.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.cursorrules +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.dockerignore +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.env.example +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/logo.svg +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/release-drafter.yml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/renovate.json +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/scripts/check_extras_sync.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/scripts/check_plugin_skill_sync.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/scripts/sync_extras.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/scripts/sync_requirements.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/workflows/automerge.yml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/workflows/docker.yml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/workflows/docs.yml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/workflows/markdown-code-runner.yml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/workflows/pytest.yml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/workflows/release-drafter.yml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/workflows/release.yml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.github/workflows/toc.yaml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.gitignore +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.jscpd.json +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.prompts/docs-review.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/.prompts/pr-review.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/CLAUDE.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/LICENSE +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/README.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/__main__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_extras.json +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/.gitkeep +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/audio.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/faster-whisper.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/kokoro.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/llm.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/memory.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/mlx-whisper.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/piper.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/rag.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/server.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/speed.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/vad.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/whisper-transformers.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/_requirements/wyoming.txt +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/_voice_agent_common.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/assistant.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/autocorrect.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/chat.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/memory/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/memory/add.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/memory/proxy.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/rag_proxy.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/speak.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/transcribe.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/agents/voice_edit.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/api.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/cli.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/config_cmd.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/constants.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/audio.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/audio_format.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/chroma.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/openai_proxy.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/process.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/reranker.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/sse.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/transcription_logger.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/utils.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/vad.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/core/watch.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/daemon/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/daemon/cli.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/aider.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/base.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/claude.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/codex.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/continue_dev.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/copilot.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/cursor_agent.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/gemini.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/opencode.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/coding_agents/registry.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/base.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/cursor.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/emacs.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/jetbrains.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/nano.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/neovim.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/registry.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/sublime.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/vim.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/vscode.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/editors/zed.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/project.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/registry.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/skill/SKILL.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/skill/examples.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/terminals/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/terminals/apple_terminal.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/terminals/base.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/terminals/gnome.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/terminals/iterm2.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/terminals/kitty.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/terminals/registry.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/terminals/tmux.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/terminals/warp.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/dev/terminals/zellij.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/docs_gen.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/example-config.toml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/install/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/install/common.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/install/extras.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/install/hotkeys.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/install/launchd.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/install/services.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/install/systemd.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_files.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_filters.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_git.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_indexer.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_ingest.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_persistence.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_prompt.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_retrieval.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_store.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_streaming.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/_tasks.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/api.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/client.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/engine.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/entities.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/memory/models.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/opts.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/py.typed +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/_indexer.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/_indexing.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/_prompt.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/_retriever.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/_store.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/_utils.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/api.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/client.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/engine.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/rag/models.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/.runtime/.gitkeep +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/linux-hotkeys/README.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/linux-hotkeys/toggle-autocorrect.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/linux-hotkeys/toggle-transcription.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/linux-hotkeys/toggle-voice-edit.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/macos-hotkeys/README.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/macos-hotkeys/skhd-config-example +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/macos-hotkeys/toggle-autocorrect.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/macos-hotkeys/toggle-transcription.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/macos-hotkeys/toggle-voice-edit.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/nvidia-asr-server/README.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/nvidia-asr-server/pyproject.toml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/nvidia-asr-server/server.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/nvidia-asr-server/shell.nix +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/nvidia-asr-server/uv.lock +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/run-openwakeword.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/setup-linux-hotkeys.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/setup-linux.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/setup-macos-hotkeys.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/setup-macos.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/setup-windows.ps1 +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/start-all-services-windows.ps1 +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/scripts/start-all-services.sh +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/cli.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/common.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/model_manager.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/model_registry.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/proxy/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/proxy/api.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/streaming.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/tts/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/tts/api.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/tts/backends/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/tts/backends/base.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/tts/backends/kokoro.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/tts/backends/piper.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/tts/model_manager.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/tts/model_registry.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/tts/wyoming_handler.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/api.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/backends/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/backends/base.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/backends/faster_whisper.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/backends/mlx.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/backends/transformers.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/languages.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/model_manager.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/model_registry.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/server/whisper/wyoming_handler.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/services/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/services/_wyoming_utils.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/services/asr.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/services/llm.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/services/tts.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/agent_cli/services/wake_word.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docker/docker-compose.yml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docker/memory-proxy.Dockerfile +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docker/rag-proxy.Dockerfile +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docker/transcribe-proxy.Dockerfile +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docker/tts.Dockerfile +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docker/whisper.Dockerfile +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/CNAME +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/architecture/index.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/architecture/memory.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/architecture/rag.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/assistant.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/autocorrect.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/chat.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/config.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/daemon.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/index.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/install-extras.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/install-hotkeys.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/install-services.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/memory.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/rag-proxy.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/server/index.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/server/transcribe-proxy.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/server/tts.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/server/whisper.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/speak.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/start-services.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/transcribe-live.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/transcribe.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/commands/voice-edit.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/configuration.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/getting-started.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/iOS_Shortcut_Guide.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/index.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/installation/docker.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/installation/index.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/installation/linux.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/installation/macos.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/installation/nixos.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/installation/windows.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/logo-clean.svg +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/overrides/partials/integrations/analytics/custom.html +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/run_markdown_code_runner.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/docs/system-integration.md +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/example.agent-cli-config.toml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/justfile +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/pyproject.toml +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/shell.nix +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_fix_my_text.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_interactive.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_interactive_extra.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_memory_add.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_speak.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_speak_e2e.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_transcribe.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_transcribe_agent.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_transcribe_e2e.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_transcribe_live.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_transcribe_recovery.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_tts_common.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_tts_common_extra.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_voice_agent_common.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_voice_edit.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_voice_edit_e2e.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/agents/test_wake_word_assistant.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/conftest.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/core/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/core/test_audio_format.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/core/test_chroma.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/core/test_sse.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/core/test_vad.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/core/test_watch.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/dev/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/dev/test_coding_agents.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/dev/test_editors.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/dev/test_project.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/dev/test_terminals.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/dev/test_verification.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/install/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/install/test_extras.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_api_health.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_api_integration_liveish.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_client.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_engine.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_files.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_filters.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_git_integration.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_indexer.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_memory_integration.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_proxy_passthrough.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_store.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/memory/test_utils.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/mocks/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/mocks/audio.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/mocks/llm.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/mocks/wyoming.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/__init__.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_api.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_engine.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_history.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_indexer.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_indexing.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_rag_client.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_rag_integration_liveish.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_rag_proxy_passthrough.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_retriever.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_store.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/rag/test_utils.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_api.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_api_integration.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_asr.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_asr_recovery.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_audio_e2e.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_cli.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_config_cmd.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_daemon.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_docs_gen.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_env_vars.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_json_output.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_llm.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_llm_gemini.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_memory_tools.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_mlx_backend.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_process_manager.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_requires_extras.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_server_streaming.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_server_tts.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_server_whisper.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_services.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_tools.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_transformers_backend.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_tts.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_utils.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_wake_word.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/tests/test_wyoming_utils.py +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/uv.lock +0 -0
- {agent_cli-0.80.0 → agent_cli-0.81.0}/zensical.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.81.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>
|
|
@@ -130,7 +130,7 @@ def execute_code(code: str) -> str:
|
|
|
130
130
|
except subprocess.CalledProcessError as e:
|
|
131
131
|
return f"Error executing code: {e.stderr}"
|
|
132
132
|
except FileNotFoundError:
|
|
133
|
-
return f"Error: Command not found: {code.split()[0]}"
|
|
133
|
+
return f"Error: Command not found: {code.split(maxsplit=1)[0]}"
|
|
134
134
|
|
|
135
135
|
|
|
136
136
|
def add_memory(content: str, category: str = "general", tags: str = "") -> str:
|
|
@@ -188,7 +188,7 @@ async def _process_segment( # noqa: PLR0912
|
|
|
188
188
|
if cfg.clipboard:
|
|
189
189
|
import pyperclip # noqa: PLC0415
|
|
190
190
|
|
|
191
|
-
text_to_copy = processed
|
|
191
|
+
text_to_copy = processed or transcript
|
|
192
192
|
pyperclip.copy(text_to_copy)
|
|
193
193
|
|
|
194
194
|
# Log
|
|
@@ -264,6 +264,9 @@ class Dev(BaseModel):
|
|
|
264
264
|
|
|
265
265
|
default_agent: str | None = None
|
|
266
266
|
default_editor: str | None = None
|
|
267
|
+
branch_name_mode: Literal["random", "auto", "ai"] = "random"
|
|
268
|
+
branch_name_agent: Literal["claude", "codex", "gemini"] | None = None
|
|
269
|
+
branch_name_timeout: float = 20.0 # seconds
|
|
267
270
|
agent_args: dict[str, list[str]] | None = (
|
|
268
271
|
None # Per-agent args, e.g. {"claude": ["--dangerously-skip-permissions"]}
|
|
269
272
|
)
|
|
@@ -319,16 +322,28 @@ def normalize_provider_defaults(cfg: dict[str, Any]) -> dict[str, Any]:
|
|
|
319
322
|
return normalized
|
|
320
323
|
|
|
321
324
|
|
|
322
|
-
def _replace_dashed_keys(cfg:
|
|
323
|
-
|
|
325
|
+
def _replace_dashed_keys(cfg: Any) -> Any:
|
|
326
|
+
"""Recursively replace dashed keys in dictionaries."""
|
|
327
|
+
if isinstance(cfg, dict):
|
|
328
|
+
return {k.replace("-", "_"): _replace_dashed_keys(v) for k, v in cfg.items()}
|
|
329
|
+
return cfg
|
|
324
330
|
|
|
325
331
|
|
|
326
332
|
def _flatten_nested_sections(cfg: dict[str, Any], prefix: str = "") -> dict[str, Any]:
|
|
327
|
-
"""Flatten nested TOML sections
|
|
328
|
-
|
|
333
|
+
"""Flatten nested TOML sections while preserving scalar parent options.
|
|
334
|
+
|
|
335
|
+
Example:
|
|
336
|
+
{"a": {"x": 1, "b": {"y": 2}}} -> {"a": {"x": 1}, "a.b": {"y": 2}}
|
|
337
|
+
{"a": {"b": {"x": 1}}} -> {"a.b": {"x": 1}}
|
|
338
|
+
|
|
339
|
+
"""
|
|
340
|
+
result: dict[str, Any] = {}
|
|
329
341
|
for key, value in cfg.items():
|
|
330
342
|
full_key = f"{prefix}.{key}" if prefix else key
|
|
331
343
|
if isinstance(value, dict) and any(isinstance(v, dict) for v in value.values()):
|
|
344
|
+
scalar_items = {k: v for k, v in value.items() if not isinstance(v, dict)}
|
|
345
|
+
if scalar_items:
|
|
346
|
+
result[full_key] = scalar_items
|
|
332
347
|
result.update(_flatten_nested_sections(value, full_key))
|
|
333
348
|
else:
|
|
334
349
|
result[full_key] = value
|
|
@@ -61,7 +61,7 @@ EXTRAS: dict[str, tuple[str, list[str]]] = {
|
|
|
61
61
|
|
|
62
62
|
def _check_package_installed(pkg: str) -> bool:
|
|
63
63
|
"""Check if a single package is installed."""
|
|
64
|
-
top_module = pkg.split(".")[0]
|
|
64
|
+
top_module = pkg.split(".", maxsplit=1)[0]
|
|
65
65
|
try:
|
|
66
66
|
return find_spec(top_module) is not None
|
|
67
67
|
except (ValueError, ModuleNotFoundError):
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"""Branch name generation for dev worktrees."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import random
|
|
7
|
+
import re
|
|
8
|
+
import shutil
|
|
9
|
+
import subprocess
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from agent_cli.core.utils import err_console
|
|
13
|
+
|
|
14
|
+
from . import worktree
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from collections.abc import Callable
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
AGENTS: tuple[str, ...] = ("claude", "codex", "gemini")
|
|
21
|
+
|
|
22
|
+
_ADJECTIVES = [
|
|
23
|
+
"happy",
|
|
24
|
+
"clever",
|
|
25
|
+
"swift",
|
|
26
|
+
"bright",
|
|
27
|
+
"calm",
|
|
28
|
+
"eager",
|
|
29
|
+
"fancy",
|
|
30
|
+
"gentle",
|
|
31
|
+
"jolly",
|
|
32
|
+
"keen",
|
|
33
|
+
"lively",
|
|
34
|
+
"merry",
|
|
35
|
+
"nice",
|
|
36
|
+
"proud",
|
|
37
|
+
"quick",
|
|
38
|
+
"sharp",
|
|
39
|
+
"smart",
|
|
40
|
+
"sunny",
|
|
41
|
+
"witty",
|
|
42
|
+
"zesty",
|
|
43
|
+
"bold",
|
|
44
|
+
"cool",
|
|
45
|
+
"fresh",
|
|
46
|
+
"grand",
|
|
47
|
+
]
|
|
48
|
+
_NOUNS = [
|
|
49
|
+
"fox",
|
|
50
|
+
"owl",
|
|
51
|
+
"bear",
|
|
52
|
+
"wolf",
|
|
53
|
+
"hawk",
|
|
54
|
+
"lion",
|
|
55
|
+
"tiger",
|
|
56
|
+
"eagle",
|
|
57
|
+
"falcon",
|
|
58
|
+
"otter",
|
|
59
|
+
"panda",
|
|
60
|
+
"raven",
|
|
61
|
+
"shark",
|
|
62
|
+
"whale",
|
|
63
|
+
"zebra",
|
|
64
|
+
"bison",
|
|
65
|
+
"crane",
|
|
66
|
+
"dolphin",
|
|
67
|
+
"gecko",
|
|
68
|
+
"heron",
|
|
69
|
+
"koala",
|
|
70
|
+
"lemur",
|
|
71
|
+
"moose",
|
|
72
|
+
"newt",
|
|
73
|
+
"oriole",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
_MAX_BRANCH_NAME_LEN = 80
|
|
77
|
+
_MAX_BRANCH_TASK_LEN = 1200
|
|
78
|
+
_CLAUDE_BRANCH_SCHEMA = json.dumps(
|
|
79
|
+
{
|
|
80
|
+
"type": "object",
|
|
81
|
+
"properties": {
|
|
82
|
+
"branch": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"pattern": r"^[a-z0-9][a-z0-9._/-]{1,79}$",
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
"required": ["branch"],
|
|
88
|
+
"additionalProperties": False,
|
|
89
|
+
},
|
|
90
|
+
separators=(",", ":"),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _branch_exists_in_repo(repo_root: Path, branch_name: str) -> bool:
|
|
95
|
+
"""Check whether a branch already exists locally or on origin."""
|
|
96
|
+
return any(worktree.check_branch_exists(branch_name, repo_root))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _ensure_unique_branch_name(
|
|
100
|
+
base_name: str,
|
|
101
|
+
existing_branches: set[str] | None = None,
|
|
102
|
+
*,
|
|
103
|
+
repo_root: Path | None = None,
|
|
104
|
+
) -> str:
|
|
105
|
+
"""Add a numeric suffix when a branch name collides."""
|
|
106
|
+
existing = existing_branches or set()
|
|
107
|
+
|
|
108
|
+
def is_available(candidate: str) -> bool:
|
|
109
|
+
if candidate in existing:
|
|
110
|
+
return False
|
|
111
|
+
return repo_root is None or not _branch_exists_in_repo(repo_root, candidate)
|
|
112
|
+
|
|
113
|
+
if is_available(base_name):
|
|
114
|
+
return base_name
|
|
115
|
+
|
|
116
|
+
for i in range(2, 100):
|
|
117
|
+
candidate = f"{base_name}-{i}"
|
|
118
|
+
if is_available(candidate):
|
|
119
|
+
return candidate
|
|
120
|
+
|
|
121
|
+
for _ in range(20):
|
|
122
|
+
candidate = f"{base_name}-{random.randint(100, 999)}" # noqa: S311
|
|
123
|
+
if is_available(candidate):
|
|
124
|
+
return candidate
|
|
125
|
+
|
|
126
|
+
# Last resort: large range, unchecked (98 sequential + 20 random exhausted)
|
|
127
|
+
return f"{base_name}-{random.randint(1000, 9999)}" # noqa: S311
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _parse_json_lines(output: str) -> list[dict[str, object]]:
|
|
131
|
+
"""Parse JSONL output and ignore non-JSON lines."""
|
|
132
|
+
parsed: list[dict[str, object]] = []
|
|
133
|
+
for raw_line in output.splitlines():
|
|
134
|
+
stripped_line = raw_line.strip()
|
|
135
|
+
if not stripped_line:
|
|
136
|
+
continue
|
|
137
|
+
try:
|
|
138
|
+
item = json.loads(stripped_line)
|
|
139
|
+
except json.JSONDecodeError:
|
|
140
|
+
continue
|
|
141
|
+
if isinstance(item, dict):
|
|
142
|
+
parsed.append(item)
|
|
143
|
+
return parsed
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _extract_branch_from_claude_output(output: str) -> str | None:
|
|
147
|
+
"""Extract branch name from `claude -p --output-format json` output."""
|
|
148
|
+
for event in reversed(_parse_json_lines(output)):
|
|
149
|
+
structured = event.get("structured_output")
|
|
150
|
+
if isinstance(structured, dict):
|
|
151
|
+
branch = structured.get("branch")
|
|
152
|
+
if isinstance(branch, str) and branch.strip():
|
|
153
|
+
return branch
|
|
154
|
+
result = event.get("result")
|
|
155
|
+
if isinstance(result, str) and result.strip():
|
|
156
|
+
return result
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _extract_branch_from_codex_output(output: str) -> str | None:
|
|
161
|
+
"""Extract branch name from `codex exec --json` output."""
|
|
162
|
+
branch: str | None = None
|
|
163
|
+
for event in _parse_json_lines(output):
|
|
164
|
+
if event.get("type") != "item.completed":
|
|
165
|
+
continue
|
|
166
|
+
item = event.get("item")
|
|
167
|
+
if not isinstance(item, dict):
|
|
168
|
+
continue
|
|
169
|
+
if item.get("type") != "agent_message":
|
|
170
|
+
continue
|
|
171
|
+
text = item.get("text")
|
|
172
|
+
if isinstance(text, str) and text.strip():
|
|
173
|
+
branch = text
|
|
174
|
+
return branch
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _extract_branch_from_gemini_output(output: str) -> str | None:
|
|
178
|
+
"""Extract branch name from `gemini -p -o json` output."""
|
|
179
|
+
for raw_line in output.splitlines():
|
|
180
|
+
stripped = raw_line.strip()
|
|
181
|
+
if not stripped:
|
|
182
|
+
continue
|
|
183
|
+
try:
|
|
184
|
+
item = json.loads(stripped)
|
|
185
|
+
except json.JSONDecodeError:
|
|
186
|
+
continue
|
|
187
|
+
if isinstance(item, dict):
|
|
188
|
+
response = item.get("response")
|
|
189
|
+
if isinstance(response, str) and response.strip():
|
|
190
|
+
return response
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _normalize_ai_branch_candidate(candidate: str, repo_root: Path) -> str | None:
|
|
195
|
+
"""Normalize model output into a safe branch slug."""
|
|
196
|
+
lines = [line.strip() for line in candidate.replace("`", "").splitlines() if line.strip()]
|
|
197
|
+
if not lines:
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
branch = lines[0].strip().strip("'\"")
|
|
201
|
+
branch = re.sub(r"^(branch|name)\s*:\s*", "", branch, flags=re.IGNORECASE)
|
|
202
|
+
branch = branch.lower()
|
|
203
|
+
branch = re.sub(r"\s+", "-", branch)
|
|
204
|
+
branch = re.sub(r"[^a-z0-9._/-]", "-", branch)
|
|
205
|
+
branch = re.sub(r"/{2,}", "/", branch)
|
|
206
|
+
branch = re.sub(r"-{2,}", "-", branch)
|
|
207
|
+
branch = branch.strip("./-")
|
|
208
|
+
if len(branch) > _MAX_BRANCH_NAME_LEN:
|
|
209
|
+
branch = branch[:_MAX_BRANCH_NAME_LEN].rstrip("./-")
|
|
210
|
+
if not branch:
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
result = subprocess.run(
|
|
215
|
+
["git", "check-ref-format", "--branch", branch], # noqa: S607
|
|
216
|
+
cwd=repo_root,
|
|
217
|
+
check=False,
|
|
218
|
+
capture_output=True,
|
|
219
|
+
text=True,
|
|
220
|
+
)
|
|
221
|
+
except OSError:
|
|
222
|
+
return None
|
|
223
|
+
return branch if result.returncode == 0 else None
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _build_branch_naming_prompt(
|
|
227
|
+
repo_root: Path,
|
|
228
|
+
prompt: str | None,
|
|
229
|
+
from_ref: str | None,
|
|
230
|
+
) -> str:
|
|
231
|
+
"""Build a constrained prompt for branch name generation."""
|
|
232
|
+
task = (prompt or "").strip()
|
|
233
|
+
if not task:
|
|
234
|
+
task = "General maintenance task."
|
|
235
|
+
if len(task) > _MAX_BRANCH_TASK_LEN:
|
|
236
|
+
task = task[:_MAX_BRANCH_TASK_LEN] + "..."
|
|
237
|
+
|
|
238
|
+
base_ref = from_ref or "default branch"
|
|
239
|
+
return (
|
|
240
|
+
"Generate exactly one git branch name.\n"
|
|
241
|
+
"Return only the branch name and nothing else.\n"
|
|
242
|
+
"Do not use tools, do not inspect files, and do not ask follow-up questions.\n"
|
|
243
|
+
"Rules:\n"
|
|
244
|
+
"- lowercase ascii only\n"
|
|
245
|
+
"- allowed characters: a-z 0-9 / - _ .\n"
|
|
246
|
+
"- no spaces, no backticks, no explanation\n"
|
|
247
|
+
"- max 80 characters\n"
|
|
248
|
+
f"Repository: {repo_root.name}\n"
|
|
249
|
+
f"Base ref: {base_ref}\n"
|
|
250
|
+
f"Task: {task}\n"
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _generate_branch_name_with_agent(
|
|
255
|
+
agent_name: str,
|
|
256
|
+
repo_root: Path,
|
|
257
|
+
prompt: str | None,
|
|
258
|
+
from_ref: str | None,
|
|
259
|
+
timeout_seconds: float,
|
|
260
|
+
) -> str | None:
|
|
261
|
+
"""Run a headless agent to generate a branch name."""
|
|
262
|
+
naming_prompt = _build_branch_naming_prompt(repo_root, prompt, from_ref)
|
|
263
|
+
|
|
264
|
+
agent_commands: dict[str, tuple[list[str], Callable[[str], str | None]]] = {
|
|
265
|
+
"claude": (
|
|
266
|
+
[
|
|
267
|
+
"claude",
|
|
268
|
+
"-p",
|
|
269
|
+
"--output-format",
|
|
270
|
+
"json",
|
|
271
|
+
"--permission-mode",
|
|
272
|
+
"plan",
|
|
273
|
+
"--no-session-persistence",
|
|
274
|
+
"--json-schema",
|
|
275
|
+
_CLAUDE_BRANCH_SCHEMA,
|
|
276
|
+
naming_prompt,
|
|
277
|
+
],
|
|
278
|
+
_extract_branch_from_claude_output,
|
|
279
|
+
),
|
|
280
|
+
"codex": (
|
|
281
|
+
[
|
|
282
|
+
"codex",
|
|
283
|
+
"-a",
|
|
284
|
+
"never",
|
|
285
|
+
"exec",
|
|
286
|
+
"-s",
|
|
287
|
+
"read-only",
|
|
288
|
+
"--json",
|
|
289
|
+
naming_prompt,
|
|
290
|
+
],
|
|
291
|
+
_extract_branch_from_codex_output,
|
|
292
|
+
),
|
|
293
|
+
"gemini": (
|
|
294
|
+
["gemini", "-p", naming_prompt, "-o", "json"],
|
|
295
|
+
_extract_branch_from_gemini_output,
|
|
296
|
+
),
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
entry = agent_commands.get(agent_name)
|
|
300
|
+
if entry is None:
|
|
301
|
+
return None
|
|
302
|
+
command, extractor = entry
|
|
303
|
+
|
|
304
|
+
try:
|
|
305
|
+
result = subprocess.run(
|
|
306
|
+
command,
|
|
307
|
+
check=False,
|
|
308
|
+
capture_output=True,
|
|
309
|
+
text=True,
|
|
310
|
+
timeout=timeout_seconds,
|
|
311
|
+
cwd=repo_root,
|
|
312
|
+
)
|
|
313
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
314
|
+
return None
|
|
315
|
+
if result.returncode != 0:
|
|
316
|
+
return None
|
|
317
|
+
|
|
318
|
+
raw_branch = extractor(result.stdout)
|
|
319
|
+
if not raw_branch:
|
|
320
|
+
return None
|
|
321
|
+
return _normalize_ai_branch_candidate(raw_branch, repo_root)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def generate_ai_branch_name(
|
|
325
|
+
repo_root: Path,
|
|
326
|
+
existing_branches: set[str],
|
|
327
|
+
prompt: str | None,
|
|
328
|
+
from_ref: str | None,
|
|
329
|
+
preferred_agent: str | None,
|
|
330
|
+
timeout_seconds: float,
|
|
331
|
+
) -> str | None:
|
|
332
|
+
"""Generate an AI branch name, trying available agents in order."""
|
|
333
|
+
if preferred_agent:
|
|
334
|
+
agent = preferred_agent.lower().strip()
|
|
335
|
+
if agent not in AGENTS or shutil.which(agent) is None:
|
|
336
|
+
return None
|
|
337
|
+
agents = [agent]
|
|
338
|
+
else:
|
|
339
|
+
agents = [a for a in AGENTS if shutil.which(a)]
|
|
340
|
+
|
|
341
|
+
for agent_name in agents:
|
|
342
|
+
with err_console.status(f"Generating branch name with {agent_name}..."):
|
|
343
|
+
branch = _generate_branch_name_with_agent(
|
|
344
|
+
agent_name,
|
|
345
|
+
repo_root,
|
|
346
|
+
prompt,
|
|
347
|
+
from_ref,
|
|
348
|
+
timeout_seconds,
|
|
349
|
+
)
|
|
350
|
+
if branch:
|
|
351
|
+
return _ensure_unique_branch_name(
|
|
352
|
+
branch,
|
|
353
|
+
existing_branches,
|
|
354
|
+
repo_root=repo_root,
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
return None
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def generate_random_branch_name(
|
|
361
|
+
existing_branches: set[str] | None = None,
|
|
362
|
+
*,
|
|
363
|
+
repo_root: Path | None = None,
|
|
364
|
+
) -> str:
|
|
365
|
+
"""Generate a unique random branch name like 'clever-fox'.
|
|
366
|
+
|
|
367
|
+
If the name already exists, adds a numeric suffix (clever-fox-2).
|
|
368
|
+
"""
|
|
369
|
+
existing = existing_branches or set()
|
|
370
|
+
base = f"{random.choice(_ADJECTIVES)}-{random.choice(_NOUNS)}" # noqa: S311
|
|
371
|
+
return _ensure_unique_branch_name(base, existing, repo_root=repo_root)
|
|
@@ -4,13 +4,12 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
6
|
import os
|
|
7
|
-
import random
|
|
8
7
|
import shlex
|
|
9
8
|
import shutil
|
|
10
9
|
import subprocess
|
|
11
10
|
import tempfile
|
|
12
11
|
from pathlib import Path
|
|
13
|
-
from typing import TYPE_CHECKING, Annotated, NoReturn
|
|
12
|
+
from typing import TYPE_CHECKING, Annotated, Literal, NoReturn
|
|
14
13
|
|
|
15
14
|
import typer
|
|
16
15
|
from rich.panel import Panel
|
|
@@ -22,85 +21,11 @@ from agent_cli.config import load_config
|
|
|
22
21
|
from agent_cli.core.process import set_process_title
|
|
23
22
|
from agent_cli.core.utils import console, err_console
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"bright",
|
|
31
|
-
"calm",
|
|
32
|
-
"eager",
|
|
33
|
-
"fancy",
|
|
34
|
-
"gentle",
|
|
35
|
-
"jolly",
|
|
36
|
-
"keen",
|
|
37
|
-
"lively",
|
|
38
|
-
"merry",
|
|
39
|
-
"nice",
|
|
40
|
-
"proud",
|
|
41
|
-
"quick",
|
|
42
|
-
"sharp",
|
|
43
|
-
"smart",
|
|
44
|
-
"sunny",
|
|
45
|
-
"witty",
|
|
46
|
-
"zesty",
|
|
47
|
-
"bold",
|
|
48
|
-
"cool",
|
|
49
|
-
"fresh",
|
|
50
|
-
"grand",
|
|
51
|
-
]
|
|
52
|
-
_NOUNS = [
|
|
53
|
-
"fox",
|
|
54
|
-
"owl",
|
|
55
|
-
"bear",
|
|
56
|
-
"wolf",
|
|
57
|
-
"hawk",
|
|
58
|
-
"lion",
|
|
59
|
-
"tiger",
|
|
60
|
-
"eagle",
|
|
61
|
-
"falcon",
|
|
62
|
-
"otter",
|
|
63
|
-
"panda",
|
|
64
|
-
"raven",
|
|
65
|
-
"shark",
|
|
66
|
-
"whale",
|
|
67
|
-
"zebra",
|
|
68
|
-
"bison",
|
|
69
|
-
"crane",
|
|
70
|
-
"dolphin",
|
|
71
|
-
"gecko",
|
|
72
|
-
"heron",
|
|
73
|
-
"koala",
|
|
74
|
-
"lemur",
|
|
75
|
-
"moose",
|
|
76
|
-
"newt",
|
|
77
|
-
"oriole",
|
|
78
|
-
]
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def _generate_branch_name(existing_branches: set[str] | None = None) -> str:
|
|
82
|
-
"""Generate a unique random branch name like 'clever-fox'.
|
|
83
|
-
|
|
84
|
-
If the name already exists, adds a numeric suffix (clever-fox-2).
|
|
85
|
-
"""
|
|
86
|
-
existing = existing_branches or set()
|
|
87
|
-
base = f"{random.choice(_ADJECTIVES)}-{random.choice(_NOUNS)}" # noqa: S311
|
|
88
|
-
|
|
89
|
-
if base not in existing:
|
|
90
|
-
return base
|
|
91
|
-
|
|
92
|
-
# Add numeric suffix to avoid collision
|
|
93
|
-
for i in range(2, 100):
|
|
94
|
-
candidate = f"{base}-{i}"
|
|
95
|
-
if candidate not in existing:
|
|
96
|
-
return candidate
|
|
97
|
-
|
|
98
|
-
# Fallback: add random digits
|
|
99
|
-
return f"{base}-{random.randint(100, 999)}" # noqa: S311
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
from . import coding_agents, editors, terminals, worktree # noqa: E402
|
|
103
|
-
from .project import ( # noqa: E402
|
|
24
|
+
from . import coding_agents, editors, terminals, worktree
|
|
25
|
+
from ._branch_name import AGENTS as _BRANCH_NAME_AGENTS
|
|
26
|
+
from ._branch_name import generate_ai_branch_name as _generate_ai_branch_name
|
|
27
|
+
from ._branch_name import generate_random_branch_name as _generate_branch_name
|
|
28
|
+
from .project import (
|
|
104
29
|
copy_env_files,
|
|
105
30
|
detect_project_type,
|
|
106
31
|
is_direnv_available,
|
|
@@ -156,6 +81,17 @@ def dev_callback(
|
|
|
156
81
|
has its own branch, allowing parallel development without stashing changes.
|
|
157
82
|
"""
|
|
158
83
|
set_config_defaults(ctx, config_file)
|
|
84
|
+
|
|
85
|
+
# The [dev] section config is intended for `dev new` options.
|
|
86
|
+
# Click expects subcommand defaults under ctx.default_map["new"].
|
|
87
|
+
if isinstance(ctx.default_map, dict):
|
|
88
|
+
flat_defaults = {k: v for k, v in ctx.default_map.items() if not isinstance(v, dict)}
|
|
89
|
+
nested_defaults = {k: dict(v) for k, v in ctx.default_map.items() if isinstance(v, dict)}
|
|
90
|
+
|
|
91
|
+
if flat_defaults:
|
|
92
|
+
nested_defaults["new"] = {**flat_defaults, **nested_defaults.get("new", {})}
|
|
93
|
+
ctx.default_map = nested_defaults
|
|
94
|
+
|
|
159
95
|
if ctx.invoked_subcommand is not None:
|
|
160
96
|
set_process_title(f"dev-{ctx.invoked_subcommand}")
|
|
161
97
|
|
|
@@ -311,7 +247,7 @@ def _get_config_agent_env() -> dict[str, dict[str, str]] | None:
|
|
|
311
247
|
agent_name = key[len(prefix) :]
|
|
312
248
|
result[agent_name] = value
|
|
313
249
|
|
|
314
|
-
return result
|
|
250
|
+
return result or None
|
|
315
251
|
|
|
316
252
|
|
|
317
253
|
def _get_agent_env(agent: CodingAgent) -> dict[str, str]:
|
|
@@ -350,7 +286,7 @@ def _merge_agent_args(
|
|
|
350
286
|
if cli_args:
|
|
351
287
|
result.extend(cli_args)
|
|
352
288
|
|
|
353
|
-
return result
|
|
289
|
+
return result or None
|
|
354
290
|
|
|
355
291
|
|
|
356
292
|
def _is_ssh_session() -> bool:
|
|
@@ -488,7 +424,7 @@ def new( # noqa: C901, PLR0912, PLR0915
|
|
|
488
424
|
branch: Annotated[
|
|
489
425
|
str | None,
|
|
490
426
|
typer.Argument(
|
|
491
|
-
help="Branch name for the worktree. If omitted, generates
|
|
427
|
+
help="Branch name for the worktree. If omitted, auto-generates one (random by default, AI with --branch-name-mode)",
|
|
492
428
|
),
|
|
493
429
|
] = None,
|
|
494
430
|
from_ref: Annotated[
|
|
@@ -558,6 +494,29 @@ def new( # noqa: C901, PLR0912, PLR0915
|
|
|
558
494
|
help="Run 'git fetch' before creating the worktree to ensure refs are up-to-date",
|
|
559
495
|
),
|
|
560
496
|
] = True,
|
|
497
|
+
branch_name_mode: Annotated[
|
|
498
|
+
Literal["random", "auto", "ai"],
|
|
499
|
+
typer.Option(
|
|
500
|
+
"--branch-name-mode",
|
|
501
|
+
case_sensitive=False,
|
|
502
|
+
help="How to auto-name branches when BRANCH is omitted: random (default), auto (AI only when --prompt/--prompt-file is set), or ai (always try AI first)",
|
|
503
|
+
),
|
|
504
|
+
] = "random",
|
|
505
|
+
branch_name_agent: Annotated[
|
|
506
|
+
str | None,
|
|
507
|
+
typer.Option(
|
|
508
|
+
"--branch-name-agent",
|
|
509
|
+
help="Headless agent for AI branch naming: claude, codex, or gemini. If omitted, uses --with-agent when supported, otherwise tries available agents in that order",
|
|
510
|
+
),
|
|
511
|
+
] = None,
|
|
512
|
+
branch_name_timeout: Annotated[
|
|
513
|
+
float,
|
|
514
|
+
typer.Option(
|
|
515
|
+
"--branch-name-timeout",
|
|
516
|
+
min=1.0,
|
|
517
|
+
help="Timeout in seconds for AI branch naming command",
|
|
518
|
+
),
|
|
519
|
+
] = 20.0,
|
|
561
520
|
direnv: Annotated[
|
|
562
521
|
bool | None,
|
|
563
522
|
typer.Option(
|
|
@@ -619,6 +578,7 @@ def new( # noqa: C901, PLR0912, PLR0915
|
|
|
619
578
|
- `dev new feature-x -a` — Create + start Claude/detected agent
|
|
620
579
|
- `dev new feature-x -e -a` — Create + open editor + start agent
|
|
621
580
|
- `dev new -a --prompt "Fix auth bug"` — Auto-named branch + agent with task
|
|
581
|
+
- `dev new --branch-name-mode ai -a --prompt "Refactor auth flow"` — AI-generated branch name
|
|
622
582
|
- `dev new hotfix --from v1.2.3` — Branch from a tag instead of main
|
|
623
583
|
- `dev new feature-x --from origin/develop` — Branch from develop instead
|
|
624
584
|
- `dev new feature-x --with-agent aider --with-editor cursor` — Specific tools
|
|
@@ -637,8 +597,36 @@ def new( # noqa: C901, PLR0912, PLR0915
|
|
|
637
597
|
if branch is None:
|
|
638
598
|
# Get existing branches to avoid collisions
|
|
639
599
|
existing = {wt.branch for wt in worktree.list_worktrees() if wt.branch}
|
|
640
|
-
|
|
641
|
-
|
|
600
|
+
# In auto mode, only use AI naming when we have task context.
|
|
601
|
+
if branch_name_mode == "auto" and not prompt:
|
|
602
|
+
use_ai = False
|
|
603
|
+
else:
|
|
604
|
+
use_ai = branch_name_mode != "random"
|
|
605
|
+
|
|
606
|
+
if not use_ai:
|
|
607
|
+
branch = _generate_branch_name(existing, repo_root=repo_root)
|
|
608
|
+
_info(f"Generated branch name: {branch}")
|
|
609
|
+
else:
|
|
610
|
+
effective_branch_name_agent = branch_name_agent
|
|
611
|
+
if effective_branch_name_agent is None and agent_name:
|
|
612
|
+
candidate = agent_name.lower().strip()
|
|
613
|
+
if candidate in _BRANCH_NAME_AGENTS:
|
|
614
|
+
effective_branch_name_agent = candidate
|
|
615
|
+
|
|
616
|
+
branch = _generate_ai_branch_name(
|
|
617
|
+
repo_root,
|
|
618
|
+
existing,
|
|
619
|
+
prompt,
|
|
620
|
+
from_ref,
|
|
621
|
+
effective_branch_name_agent,
|
|
622
|
+
branch_name_timeout,
|
|
623
|
+
)
|
|
624
|
+
if branch:
|
|
625
|
+
_info(f"AI-generated branch name: {branch}")
|
|
626
|
+
else:
|
|
627
|
+
_warn("Could not generate branch name with AI. Falling back to random naming.")
|
|
628
|
+
branch = _generate_branch_name(existing, repo_root=repo_root)
|
|
629
|
+
_info(f"Generated branch name: {branch}")
|
|
642
630
|
|
|
643
631
|
# Create the worktree
|
|
644
632
|
_info(f"Creating worktree for branch '{branch}'...")
|