agent-cli 0.79.0__tar.gz → 0.80.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.
Files changed (367) hide show
  1. {agent_cli-0.79.0 → agent_cli-0.80.0}/PKG-INFO +1 -1
  2. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/cli.py +17 -4
  3. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/setup-macos.sh +5 -15
  4. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/tts/backends/piper.py +76 -80
  5. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/dev.md +1 -0
  6. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/installation/macos.md +15 -14
  7. {agent_cli-0.79.0 → agent_cli-0.80.0}/.claude/skills/agent-cli-dev/SKILL.md +0 -0
  8. {agent_cli-0.79.0 → agent_cli-0.80.0}/.claude/skills/agent-cli-dev/examples.md +0 -0
  9. {agent_cli-0.79.0 → agent_cli-0.80.0}/.claude-plugin/README.md +0 -0
  10. {agent_cli-0.79.0 → agent_cli-0.80.0}/.claude-plugin/marketplace.json +0 -0
  11. {agent_cli-0.79.0 → agent_cli-0.80.0}/.claude-plugin/plugin.json +0 -0
  12. {agent_cli-0.79.0 → agent_cli-0.80.0}/.claude-plugin/skills/agent-cli-dev/SKILL.md +0 -0
  13. {agent_cli-0.79.0 → agent_cli-0.80.0}/.claude-plugin/skills/agent-cli-dev/examples.md +0 -0
  14. {agent_cli-0.79.0 → agent_cli-0.80.0}/.cursorrules +0 -0
  15. {agent_cli-0.79.0 → agent_cli-0.80.0}/.dockerignore +0 -0
  16. {agent_cli-0.79.0 → agent_cli-0.80.0}/.env.example +0 -0
  17. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/logo.svg +0 -0
  18. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/release-drafter.yml +0 -0
  19. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/renovate.json +0 -0
  20. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/scripts/check_extras_sync.py +0 -0
  21. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/scripts/check_plugin_skill_sync.py +0 -0
  22. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/scripts/sync_extras.py +0 -0
  23. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/scripts/sync_requirements.py +0 -0
  24. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/workflows/automerge.yml +0 -0
  25. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/workflows/docker.yml +0 -0
  26. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/workflows/docs.yml +0 -0
  27. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/workflows/markdown-code-runner.yml +0 -0
  28. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/workflows/pytest.yml +0 -0
  29. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/workflows/release-drafter.yml +0 -0
  30. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/workflows/release.yml +0 -0
  31. {agent_cli-0.79.0 → agent_cli-0.80.0}/.github/workflows/toc.yaml +0 -0
  32. {agent_cli-0.79.0 → agent_cli-0.80.0}/.gitignore +0 -0
  33. {agent_cli-0.79.0 → agent_cli-0.80.0}/.jscpd.json +0 -0
  34. {agent_cli-0.79.0 → agent_cli-0.80.0}/.pre-commit-config.yaml +0 -0
  35. {agent_cli-0.79.0 → agent_cli-0.80.0}/.prompts/docs-review.md +0 -0
  36. {agent_cli-0.79.0 → agent_cli-0.80.0}/.prompts/pr-review.md +0 -0
  37. {agent_cli-0.79.0 → agent_cli-0.80.0}/CLAUDE.md +0 -0
  38. {agent_cli-0.79.0 → agent_cli-0.80.0}/LICENSE +0 -0
  39. {agent_cli-0.79.0 → agent_cli-0.80.0}/README.md +0 -0
  40. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/__init__.py +0 -0
  41. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/__main__.py +0 -0
  42. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_extras.json +0 -0
  43. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/.gitkeep +0 -0
  44. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/audio.txt +0 -0
  45. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/faster-whisper.txt +0 -0
  46. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/kokoro.txt +0 -0
  47. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/llm.txt +0 -0
  48. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/memory.txt +0 -0
  49. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/mlx-whisper.txt +0 -0
  50. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/piper.txt +0 -0
  51. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/rag.txt +0 -0
  52. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/server.txt +0 -0
  53. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/speed.txt +0 -0
  54. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/vad.txt +0 -0
  55. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/whisper-transformers.txt +0 -0
  56. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_requirements/wyoming.txt +0 -0
  57. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/_tools.py +0 -0
  58. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/__init__.py +0 -0
  59. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/_voice_agent_common.py +0 -0
  60. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/assistant.py +0 -0
  61. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/autocorrect.py +0 -0
  62. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/chat.py +0 -0
  63. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/memory/__init__.py +0 -0
  64. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/memory/add.py +0 -0
  65. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/memory/proxy.py +0 -0
  66. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/rag_proxy.py +0 -0
  67. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/speak.py +0 -0
  68. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/transcribe.py +0 -0
  69. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/transcribe_live.py +0 -0
  70. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/agents/voice_edit.py +0 -0
  71. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/api.py +0 -0
  72. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/cli.py +0 -0
  73. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/config.py +0 -0
  74. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/config_cmd.py +0 -0
  75. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/constants.py +0 -0
  76. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/__init__.py +0 -0
  77. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/audio.py +0 -0
  78. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/audio_format.py +0 -0
  79. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/chroma.py +0 -0
  80. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/deps.py +0 -0
  81. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/openai_proxy.py +0 -0
  82. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/process.py +0 -0
  83. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/reranker.py +0 -0
  84. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/sse.py +0 -0
  85. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/transcription_logger.py +0 -0
  86. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/utils.py +0 -0
  87. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/vad.py +0 -0
  88. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/core/watch.py +0 -0
  89. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/daemon/__init__.py +0 -0
  90. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/daemon/cli.py +0 -0
  91. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/__init__.py +0 -0
  92. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/__init__.py +0 -0
  93. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/aider.py +0 -0
  94. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/base.py +0 -0
  95. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/claude.py +0 -0
  96. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/codex.py +0 -0
  97. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/continue_dev.py +0 -0
  98. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/copilot.py +0 -0
  99. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/cursor_agent.py +0 -0
  100. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/gemini.py +0 -0
  101. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/opencode.py +0 -0
  102. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/coding_agents/registry.py +0 -0
  103. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/__init__.py +0 -0
  104. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/base.py +0 -0
  105. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/cursor.py +0 -0
  106. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/emacs.py +0 -0
  107. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/jetbrains.py +0 -0
  108. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/nano.py +0 -0
  109. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/neovim.py +0 -0
  110. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/registry.py +0 -0
  111. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/sublime.py +0 -0
  112. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/vim.py +0 -0
  113. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/vscode.py +0 -0
  114. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/editors/zed.py +0 -0
  115. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/project.py +0 -0
  116. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/registry.py +0 -0
  117. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/skill/SKILL.md +0 -0
  118. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/skill/examples.md +0 -0
  119. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/terminals/__init__.py +0 -0
  120. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/terminals/apple_terminal.py +0 -0
  121. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/terminals/base.py +0 -0
  122. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/terminals/gnome.py +0 -0
  123. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/terminals/iterm2.py +0 -0
  124. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/terminals/kitty.py +0 -0
  125. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/terminals/registry.py +0 -0
  126. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/terminals/tmux.py +0 -0
  127. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/terminals/warp.py +0 -0
  128. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/terminals/zellij.py +0 -0
  129. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/dev/worktree.py +0 -0
  130. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/docs_gen.py +0 -0
  131. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/example-config.toml +0 -0
  132. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/install/__init__.py +0 -0
  133. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/install/common.py +0 -0
  134. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/install/extras.py +0 -0
  135. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/install/hotkeys.py +0 -0
  136. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/install/launchd.py +0 -0
  137. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/install/service_config.py +0 -0
  138. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/install/services.py +0 -0
  139. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/install/systemd.py +0 -0
  140. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/__init__.py +0 -0
  141. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_files.py +0 -0
  142. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_filters.py +0 -0
  143. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_git.py +0 -0
  144. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_indexer.py +0 -0
  145. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_ingest.py +0 -0
  146. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_persistence.py +0 -0
  147. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_prompt.py +0 -0
  148. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_retrieval.py +0 -0
  149. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_store.py +0 -0
  150. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_streaming.py +0 -0
  151. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/_tasks.py +0 -0
  152. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/api.py +0 -0
  153. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/client.py +0 -0
  154. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/engine.py +0 -0
  155. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/entities.py +0 -0
  156. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/memory/models.py +0 -0
  157. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/opts.py +0 -0
  158. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/py.typed +0 -0
  159. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/__init__.py +0 -0
  160. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/_indexer.py +0 -0
  161. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/_indexing.py +0 -0
  162. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/_prompt.py +0 -0
  163. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/_retriever.py +0 -0
  164. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/_store.py +0 -0
  165. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/_utils.py +0 -0
  166. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/api.py +0 -0
  167. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/client.py +0 -0
  168. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/engine.py +0 -0
  169. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/rag/models.py +0 -0
  170. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/.runtime/.gitkeep +0 -0
  171. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/__init__.py +0 -0
  172. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/linux-hotkeys/README.md +0 -0
  173. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/linux-hotkeys/toggle-autocorrect.sh +0 -0
  174. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/linux-hotkeys/toggle-transcription.sh +0 -0
  175. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/linux-hotkeys/toggle-voice-edit.sh +0 -0
  176. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/macos-hotkeys/README.md +0 -0
  177. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/macos-hotkeys/skhd-config-example +0 -0
  178. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/macos-hotkeys/toggle-autocorrect.sh +0 -0
  179. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/macos-hotkeys/toggle-transcription.sh +0 -0
  180. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/macos-hotkeys/toggle-voice-edit.sh +0 -0
  181. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/nvidia-asr-server/README.md +0 -0
  182. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/nvidia-asr-server/pyproject.toml +0 -0
  183. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/nvidia-asr-server/server.py +0 -0
  184. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/nvidia-asr-server/shell.nix +0 -0
  185. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/nvidia-asr-server/uv.lock +0 -0
  186. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/run-openwakeword.sh +0 -0
  187. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/setup-linux-hotkeys.sh +0 -0
  188. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/setup-linux.sh +0 -0
  189. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/setup-macos-hotkeys.sh +0 -0
  190. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/setup-windows.ps1 +0 -0
  191. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/start-all-services-windows.ps1 +0 -0
  192. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/scripts/start-all-services.sh +0 -0
  193. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/__init__.py +0 -0
  194. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/cli.py +0 -0
  195. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/common.py +0 -0
  196. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/model_manager.py +0 -0
  197. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/model_registry.py +0 -0
  198. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/proxy/__init__.py +0 -0
  199. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/proxy/api.py +0 -0
  200. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/streaming.py +0 -0
  201. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/tts/__init__.py +0 -0
  202. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/tts/api.py +0 -0
  203. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/tts/backends/__init__.py +0 -0
  204. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/tts/backends/base.py +0 -0
  205. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/tts/backends/kokoro.py +0 -0
  206. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/tts/model_manager.py +0 -0
  207. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/tts/model_registry.py +0 -0
  208. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/tts/wyoming_handler.py +0 -0
  209. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/__init__.py +0 -0
  210. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/api.py +0 -0
  211. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/backends/__init__.py +0 -0
  212. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/backends/base.py +0 -0
  213. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/backends/faster_whisper.py +0 -0
  214. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/backends/mlx.py +0 -0
  215. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/backends/transformers.py +0 -0
  216. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/languages.py +0 -0
  217. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/model_manager.py +0 -0
  218. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/model_registry.py +0 -0
  219. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/server/whisper/wyoming_handler.py +0 -0
  220. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/services/__init__.py +0 -0
  221. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/services/_wyoming_utils.py +0 -0
  222. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/services/asr.py +0 -0
  223. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/services/llm.py +0 -0
  224. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/services/tts.py +0 -0
  225. {agent_cli-0.79.0 → agent_cli-0.80.0}/agent_cli/services/wake_word.py +0 -0
  226. {agent_cli-0.79.0 → agent_cli-0.80.0}/docker/docker-compose.yml +0 -0
  227. {agent_cli-0.79.0 → agent_cli-0.80.0}/docker/memory-proxy.Dockerfile +0 -0
  228. {agent_cli-0.79.0 → agent_cli-0.80.0}/docker/rag-proxy.Dockerfile +0 -0
  229. {agent_cli-0.79.0 → agent_cli-0.80.0}/docker/transcribe-proxy.Dockerfile +0 -0
  230. {agent_cli-0.79.0 → agent_cli-0.80.0}/docker/tts.Dockerfile +0 -0
  231. {agent_cli-0.79.0 → agent_cli-0.80.0}/docker/whisper.Dockerfile +0 -0
  232. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/CNAME +0 -0
  233. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/architecture/index.md +0 -0
  234. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/architecture/memory.md +0 -0
  235. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/architecture/rag.md +0 -0
  236. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/assistant.md +0 -0
  237. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/autocorrect.md +0 -0
  238. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/chat.md +0 -0
  239. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/config.md +0 -0
  240. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/daemon.md +0 -0
  241. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/index.md +0 -0
  242. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/install-extras.md +0 -0
  243. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/install-hotkeys.md +0 -0
  244. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/install-services.md +0 -0
  245. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/memory.md +0 -0
  246. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/rag-proxy.md +0 -0
  247. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/server/index.md +0 -0
  248. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/server/transcribe-proxy.md +0 -0
  249. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/server/tts.md +0 -0
  250. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/server/whisper.md +0 -0
  251. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/speak.md +0 -0
  252. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/start-services.md +0 -0
  253. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/transcribe-live.md +0 -0
  254. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/transcribe.md +0 -0
  255. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/commands/voice-edit.md +0 -0
  256. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/configuration.md +0 -0
  257. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/getting-started.md +0 -0
  258. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/iOS_Shortcut_Guide.md +0 -0
  259. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/index.md +0 -0
  260. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/installation/docker.md +0 -0
  261. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/installation/index.md +0 -0
  262. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/installation/linux.md +0 -0
  263. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/installation/nixos.md +0 -0
  264. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/installation/windows.md +0 -0
  265. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/logo-clean.svg +0 -0
  266. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/overrides/partials/integrations/analytics/custom.html +0 -0
  267. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/run_markdown_code_runner.py +0 -0
  268. {agent_cli-0.79.0 → agent_cli-0.80.0}/docs/system-integration.md +0 -0
  269. {agent_cli-0.79.0 → agent_cli-0.80.0}/example.agent-cli-config.toml +0 -0
  270. {agent_cli-0.79.0 → agent_cli-0.80.0}/justfile +0 -0
  271. {agent_cli-0.79.0 → agent_cli-0.80.0}/pyproject.toml +0 -0
  272. {agent_cli-0.79.0 → agent_cli-0.80.0}/shell.nix +0 -0
  273. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/__init__.py +0 -0
  274. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/__init__.py +0 -0
  275. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_fix_my_text.py +0 -0
  276. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_interactive.py +0 -0
  277. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_interactive_extra.py +0 -0
  278. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_memory_add.py +0 -0
  279. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_speak.py +0 -0
  280. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_speak_e2e.py +0 -0
  281. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_transcribe.py +0 -0
  282. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_transcribe_agent.py +0 -0
  283. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_transcribe_e2e.py +0 -0
  284. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_transcribe_live.py +0 -0
  285. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_transcribe_recovery.py +0 -0
  286. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_tts_common.py +0 -0
  287. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_tts_common_extra.py +0 -0
  288. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_voice_agent_common.py +0 -0
  289. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_voice_edit.py +0 -0
  290. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_voice_edit_e2e.py +0 -0
  291. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/agents/test_wake_word_assistant.py +0 -0
  292. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/conftest.py +0 -0
  293. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/core/__init__.py +0 -0
  294. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/core/test_audio_format.py +0 -0
  295. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/core/test_chroma.py +0 -0
  296. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/core/test_sse.py +0 -0
  297. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/core/test_vad.py +0 -0
  298. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/core/test_watch.py +0 -0
  299. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/dev/__init__.py +0 -0
  300. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/dev/test_cli.py +0 -0
  301. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/dev/test_coding_agents.py +0 -0
  302. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/dev/test_editors.py +0 -0
  303. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/dev/test_project.py +0 -0
  304. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/dev/test_terminals.py +0 -0
  305. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/dev/test_verification.py +0 -0
  306. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/dev/test_worktree.py +0 -0
  307. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/install/__init__.py +0 -0
  308. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/install/test_extras.py +0 -0
  309. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/__init__.py +0 -0
  310. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_api_health.py +0 -0
  311. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_api_integration_liveish.py +0 -0
  312. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_client.py +0 -0
  313. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_engine.py +0 -0
  314. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_files.py +0 -0
  315. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_filters.py +0 -0
  316. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_git_integration.py +0 -0
  317. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_indexer.py +0 -0
  318. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_memory_integration.py +0 -0
  319. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_proxy_passthrough.py +0 -0
  320. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_store.py +0 -0
  321. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/memory/test_utils.py +0 -0
  322. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/mocks/__init__.py +0 -0
  323. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/mocks/audio.py +0 -0
  324. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/mocks/llm.py +0 -0
  325. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/mocks/wyoming.py +0 -0
  326. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/__init__.py +0 -0
  327. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_api.py +0 -0
  328. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_engine.py +0 -0
  329. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_history.py +0 -0
  330. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_indexer.py +0 -0
  331. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_indexing.py +0 -0
  332. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_rag_client.py +0 -0
  333. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_rag_integration_liveish.py +0 -0
  334. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_rag_proxy_passthrough.py +0 -0
  335. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_retriever.py +0 -0
  336. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_store.py +0 -0
  337. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/rag/test_utils.py +0 -0
  338. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_api.py +0 -0
  339. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_api_integration.py +0 -0
  340. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_asr.py +0 -0
  341. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_asr_recovery.py +0 -0
  342. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_audio_e2e.py +0 -0
  343. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_cli.py +0 -0
  344. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_config.py +0 -0
  345. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_config_cmd.py +0 -0
  346. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_daemon.py +0 -0
  347. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_docs_gen.py +0 -0
  348. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_env_vars.py +0 -0
  349. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_json_output.py +0 -0
  350. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_llm.py +0 -0
  351. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_llm_gemini.py +0 -0
  352. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_memory_tools.py +0 -0
  353. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_mlx_backend.py +0 -0
  354. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_process_manager.py +0 -0
  355. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_requires_extras.py +0 -0
  356. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_server_streaming.py +0 -0
  357. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_server_tts.py +0 -0
  358. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_server_whisper.py +0 -0
  359. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_services.py +0 -0
  360. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_tools.py +0 -0
  361. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_transformers_backend.py +0 -0
  362. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_tts.py +0 -0
  363. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_utils.py +0 -0
  364. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_wake_word.py +0 -0
  365. {agent_cli-0.79.0 → agent_cli-0.80.0}/tests/test_wyoming_utils.py +0 -0
  366. {agent_cli-0.79.0 → agent_cli-0.80.0}/uv.lock +0 -0
  367. {agent_cli-0.79.0 → agent_cli-0.80.0}/zensical.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-cli
3
- Version: 0.79.0
3
+ Version: 0.80.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>
@@ -1469,6 +1469,8 @@ def _clean_merged_worktrees(
1469
1469
  repo_root: Path,
1470
1470
  dry_run: bool,
1471
1471
  yes: bool,
1472
+ *,
1473
+ force: bool = False,
1472
1474
  ) -> None:
1473
1475
  """Remove worktrees with merged PRs (requires gh CLI)."""
1474
1476
  _info("Checking for worktrees with merged PRs...")
@@ -1509,7 +1511,7 @@ def _clean_merged_worktrees(
1509
1511
  for wt, _pr_url in to_remove:
1510
1512
  success, error = worktree.remove_worktree(
1511
1513
  wt.path,
1512
- force=False,
1514
+ force=force,
1513
1515
  delete_branch=True,
1514
1516
  repo_path=repo_root,
1515
1517
  )
@@ -1523,6 +1525,8 @@ def _clean_no_commits_worktrees(
1523
1525
  repo_root: Path,
1524
1526
  dry_run: bool,
1525
1527
  yes: bool,
1528
+ *,
1529
+ force: bool = False,
1526
1530
  ) -> None:
1527
1531
  """Remove worktrees with no commits ahead of the default branch."""
1528
1532
  _info("Checking for worktrees with no commits...")
@@ -1546,7 +1550,7 @@ def _clean_no_commits_worktrees(
1546
1550
  for wt in to_remove:
1547
1551
  success, error = worktree.remove_worktree(
1548
1552
  wt.path,
1549
- force=False,
1553
+ force=force,
1550
1554
  delete_branch=True,
1551
1555
  repo_path=repo_root,
1552
1556
  )
@@ -1584,6 +1588,14 @@ def clean(
1584
1588
  bool,
1585
1589
  typer.Option("--yes", "-y", help="Skip confirmation prompts"),
1586
1590
  ] = False,
1591
+ force: Annotated[
1592
+ bool,
1593
+ typer.Option(
1594
+ "--force",
1595
+ "-f",
1596
+ help="Force removal of worktrees with modified or untracked files",
1597
+ ),
1598
+ ] = False,
1587
1599
  ) -> None:
1588
1600
  """Clean up stale worktrees and empty directories.
1589
1601
 
@@ -1601,6 +1613,7 @@ def clean(
1601
1613
  - `dev clean` — Basic cleanup
1602
1614
  - `dev clean --merged` — Remove worktrees with merged PRs
1603
1615
  - `dev clean --merged --dry-run` — Preview what would be removed
1616
+ - `dev clean --no-commits --force` — Force remove abandoned worktrees with local changes
1604
1617
  """
1605
1618
  repo_root = _ensure_git_repo()
1606
1619
 
@@ -1635,11 +1648,11 @@ def clean(
1635
1648
 
1636
1649
  # --merged mode: remove worktrees with merged PRs
1637
1650
  if merged:
1638
- _clean_merged_worktrees(repo_root, dry_run, yes)
1651
+ _clean_merged_worktrees(repo_root, dry_run, yes, force=force)
1639
1652
 
1640
1653
  # --no-commits mode: remove worktrees with no commits ahead of default branch
1641
1654
  if no_commits:
1642
- _clean_no_commits_worktrees(repo_root, dry_run, yes)
1655
+ _clean_no_commits_worktrees(repo_root, dry_run, yes, force=force)
1643
1656
 
1644
1657
 
1645
1658
  @app.command("doctor")
@@ -47,15 +47,9 @@ echo "⏳ This may take a few minutes depending on your internet connection..."
47
47
  sleep 2 # Give Ollama service time to start
48
48
  ollama pull gemma3:4b
49
49
 
50
- # Install wyoming-mlx-whisper as a launchd service (Apple Silicon only)
51
- if [ "$(uname -m)" = "arm64" ]; then
52
- echo "🎤 Installing wyoming-mlx-whisper as a background service..."
53
- echo " This will run speech-to-text on Apple Silicon using MLX"
54
- curl -fsSL https://raw.githubusercontent.com/basnijholt/wyoming-mlx-whisper/main/scripts/install_service.sh | bash
55
- echo "✅ wyoming-mlx-whisper installed as launchd service"
56
- else
57
- echo "ℹ️ Skipping wyoming-mlx-whisper service (Intel Mac - use Linux-style setup)"
58
- fi
50
+ # Install whisper and tts as launchd daemons
51
+ echo "🎤 Installing whisper and tts-kokoro as background daemons..."
52
+ agent-cli daemon install whisper tts-kokoro -y
59
53
 
60
54
  echo ""
61
55
  echo "✅ Setup complete! You can now run the services:"
@@ -65,12 +59,8 @@ echo " ./start-all-services.sh"
65
59
  echo ""
66
60
  echo "Option 2 - Run services individually:"
67
61
  echo " 1. Ollama: running as brew service (brew services start ollama)"
68
- if [ "$(uname -m)" = "arm64" ]; then
69
- echo " 2. Whisper: running as launchd service (wyoming-mlx-whisper)"
70
- else
71
- echo " 2. Whisper: agent-cli server whisper"
72
- fi
73
- echo " 3. Piper: agent-cli server tts --backend piper"
62
+ echo " 2. Whisper: running as launchd daemon (agent-cli daemon status whisper)"
63
+ echo " 3. TTS: running as launchd daemon (agent-cli daemon status tts-kokoro)"
74
64
  echo " 4. OpenWakeWord: ./run-openwakeword.sh"
75
65
  echo ""
76
66
  echo "🎉 agent-cli has been installed and is ready to use!"
@@ -1,4 +1,4 @@
1
- """Piper TTS backend using piper-tts library."""
1
+ """Piper TTS backend using piper-tts library with subprocess isolation."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -7,10 +7,14 @@ import io
7
7
  import logging
8
8
  import time
9
9
  import wave
10
+ from concurrent.futures import ProcessPoolExecutor
11
+ from dataclasses import dataclass
12
+ from multiprocessing import get_context
10
13
  from pathlib import Path
11
- from typing import TYPE_CHECKING, Any, NoReturn
14
+ from typing import Any, NoReturn
12
15
 
13
16
  from agent_cli import constants
17
+ from agent_cli.core.process import set_process_title
14
18
  from agent_cli.server.tts.backends.base import (
15
19
  BackendConfig,
16
20
  InvalidTextError,
@@ -18,29 +22,45 @@ from agent_cli.server.tts.backends.base import (
18
22
  get_backend_cache_dir,
19
23
  )
20
24
 
21
- if TYPE_CHECKING:
22
- from piper import PiperVoice
23
-
24
25
  logger = logging.getLogger(__name__)
25
26
 
26
27
 
27
- def _load_model_sync(
28
+ # --- Subprocess state (only used within subprocess worker) ---
29
+ # This state persists across function calls within the subprocess because:
30
+ # 1. Model loading is expensive and must be reused across synthesis calls
31
+ # 2. The subprocess is long-lived (ProcessPoolExecutor reuses workers)
32
+
33
+
34
+ @dataclass
35
+ class _SubprocessState:
36
+ """Container for subprocess-local state. Not shared with main process."""
37
+
38
+ voice: Any = None
39
+ sample_rate: int = constants.PIPER_DEFAULT_SAMPLE_RATE
40
+
41
+
42
+ _state = _SubprocessState()
43
+
44
+
45
+ def _load_model_in_subprocess(
28
46
  model_name: str,
29
47
  cache_dir: str | None,
30
- ) -> tuple[Any, int]:
31
- """Load Piper model synchronously (for use in process pool).
48
+ ) -> int:
49
+ """Load Piper model in subprocess. Returns sample rate.
32
50
 
33
51
  Args:
34
52
  model_name: Model name (e.g., 'en_US-lessac-medium') or path to .onnx file.
35
53
  cache_dir: Optional cache directory for downloaded models.
36
54
 
37
55
  Returns:
38
- Tuple of (PiperVoice, sample_rate).
56
+ Sample rate of loaded model.
39
57
 
40
58
  """
41
59
  from piper import PiperVoice # noqa: PLC0415
42
60
  from piper.download_voices import download_voice # noqa: PLC0415
43
61
 
62
+ set_process_title("tts-piper")
63
+
44
64
  # Use default cache dir if not specified
45
65
  download_dir = Path(cache_dir) if cache_dir else get_backend_cache_dir("piper")
46
66
  download_dir.mkdir(parents=True, exist_ok=True)
@@ -50,7 +70,9 @@ def _load_model_sync(
50
70
  if model_path.exists() and model_path.suffix == ".onnx":
51
71
  # Direct path to model file
52
72
  voice = PiperVoice.load(str(model_path), use_cuda=False)
53
- return voice, voice.config.sample_rate
73
+ _state.voice = voice
74
+ _state.sample_rate = voice.config.sample_rate
75
+ return _state.sample_rate
54
76
 
55
77
  # Otherwise, treat as a voice name and download if needed
56
78
  voice_code = model_name.strip()
@@ -60,24 +82,22 @@ def _load_model_sync(
60
82
  logger.info("Downloading Piper voice: %s", voice_code)
61
83
  download_voice(voice_code, download_dir)
62
84
 
63
- # Load the voice
85
+ # Load the voice and store in subprocess state
64
86
  voice = PiperVoice.load(str(expected_model_path), use_cuda=False)
87
+ _state.voice = voice
88
+ _state.sample_rate = voice.config.sample_rate
65
89
 
66
- return voice, voice.config.sample_rate
90
+ return _state.sample_rate
67
91
 
68
92
 
69
- def _synthesize_sync(
70
- voice: PiperVoice,
93
+ def _synthesize_in_subprocess(
71
94
  text: str,
72
- sample_rate: int,
73
95
  length_scale: float,
74
96
  ) -> tuple[bytes, float]:
75
- """Synthesize text to audio synchronously.
97
+ """Synthesize text to audio in subprocess. Uses model from _state.
76
98
 
77
99
  Args:
78
- voice: Loaded PiperVoice instance.
79
100
  text: Text to synthesize.
80
- sample_rate: Sample rate from model config.
81
101
  length_scale: Length scale (inverse of speed).
82
102
 
83
103
  Returns:
@@ -86,6 +106,10 @@ def _synthesize_sync(
86
106
  """
87
107
  from piper import SynthesisConfig # noqa: PLC0415
88
108
 
109
+ if _state.voice is None:
110
+ msg = "Model not loaded in subprocess. Call _load_model_in_subprocess first."
111
+ raise RuntimeError(msg)
112
+
89
113
  # Create synthesis config with speed adjustment
90
114
  syn_config = SynthesisConfig(length_scale=length_scale)
91
115
 
@@ -94,91 +118,83 @@ def _synthesize_sync(
94
118
  with wave.open(buffer, "wb") as wav_file:
95
119
  wav_file.setnchannels(1)
96
120
  wav_file.setsampwidth(2) # 16-bit
97
- wav_file.setframerate(sample_rate)
121
+ wav_file.setframerate(_state.sample_rate)
98
122
 
99
123
  # Synthesize and write audio chunks
100
- for audio_chunk in voice.synthesize(text, syn_config):
124
+ for audio_chunk in _state.voice.synthesize(text, syn_config):
101
125
  wav_file.writeframes(audio_chunk.audio_int16_bytes)
102
126
 
103
127
  audio_data = buffer.getvalue()
104
128
 
105
129
  # Calculate duration: PCM data size / (sample_rate * channels * bytes_per_sample)
106
130
  data_size = len(audio_data) - constants.WAV_HEADER_SIZE
107
- duration = data_size / (sample_rate * 1 * 2)
131
+ duration = data_size / (_state.sample_rate * 1 * 2)
108
132
 
109
133
  return audio_data, duration
110
134
 
111
135
 
112
136
  class PiperBackend:
113
- """Piper TTS backend using ONNX-based synthesis.
137
+ """Piper TTS backend with subprocess isolation.
114
138
 
115
- This backend uses the piper-tts library for fast, CPU-friendly TTS.
116
- Models are downloaded from HuggingFace on first use.
139
+ Uses subprocess isolation: when unloaded, the subprocess terminates
140
+ and all memory is freed by the OS. This ensures clean memory management.
117
141
  """
118
142
 
119
143
  def __init__(self, config: BackendConfig) -> None:
120
- """Initialize the Piper backend.
121
-
122
- Args:
123
- config: Backend configuration.
124
-
125
- """
144
+ """Initialize the Piper backend."""
126
145
  self._config = config
127
- self._voice: PiperVoice | None = None
146
+ self._executor: ProcessPoolExecutor | None = None
128
147
  self._sample_rate: int = constants.PIPER_DEFAULT_SAMPLE_RATE # Updated on load
129
148
  self._device: str | None = None
130
149
 
131
150
  @property
132
151
  def is_loaded(self) -> bool:
133
- """Check if the model is currently loaded."""
134
- return self._voice is not None
152
+ """Check if the model is loaded."""
153
+ return self._executor is not None
135
154
 
136
155
  @property
137
156
  def device(self) -> str | None:
138
- """Get the device the model is loaded on, or None if not loaded."""
157
+ """Get the device the model is on."""
139
158
  return self._device
140
159
 
141
160
  async def load(self) -> float:
142
- """Load the model into memory.
143
-
144
- Returns:
145
- Load duration in seconds.
146
-
147
- """
148
- if self._voice is not None:
161
+ """Start subprocess and load model."""
162
+ if self._executor is not None:
149
163
  return 0.0
150
164
 
151
165
  start_time = time.time()
152
166
 
153
- # Load synchronously since Piper is fast and CPU-only
167
+ # Subprocess isolation: spawn context for clean state
168
+ ctx = get_context("spawn")
169
+ self._executor = ProcessPoolExecutor(max_workers=1, mp_context=ctx)
170
+
154
171
  loop = asyncio.get_running_loop()
155
- voice, sample_rate = await loop.run_in_executor(
156
- None,
157
- _load_model_sync,
172
+ self._sample_rate = await loop.run_in_executor(
173
+ self._executor,
174
+ _load_model_in_subprocess,
158
175
  self._config.model_name,
159
176
  str(self._config.cache_dir) if self._config.cache_dir else None,
160
177
  )
161
178
 
162
- self._voice = voice
163
- self._sample_rate = sample_rate
164
179
  self._device = "cpu" # Piper is CPU-only
165
180
 
166
181
  load_duration = time.time() - start_time
167
182
  logger.info(
168
- "Loaded Piper model %s in %.2fs (sample_rate=%d)",
183
+ "Loaded Piper model %s on %s in %.2fs",
169
184
  self._config.model_name,
185
+ self._device,
170
186
  load_duration,
171
- self._sample_rate,
172
187
  )
173
-
174
188
  return load_duration
175
189
 
176
190
  async def unload(self) -> None:
177
- """Unload the model and free memory."""
178
- if self._voice is not None:
179
- logger.info("Unloading Piper model %s", self._config.model_name)
180
- self._voice = None
181
- self._device = None
191
+ """Shutdown subprocess, releasing all memory."""
192
+ if self._executor is None:
193
+ return
194
+ self._executor.shutdown(wait=False, cancel_futures=True)
195
+ self._executor = None
196
+ self._device = None
197
+ logger.info("Piper model %s unloaded (subprocess terminated)", self._config.model_name)
182
198
 
183
199
  async def synthesize(
184
200
  self,
@@ -187,23 +203,9 @@ class PiperBackend:
187
203
  voice: str | None = None, # noqa: ARG002
188
204
  speed: float = 1.0,
189
205
  ) -> SynthesisResult:
190
- """Synthesize text to audio.
191
-
192
- Args:
193
- text: Text to synthesize.
194
- voice: Voice to use (not used for Piper - voice is the model).
195
- speed: Speech speed multiplier (0.25 to 4.0).
196
-
197
- Returns:
198
- SynthesisResult with audio data and metadata.
199
-
200
- Raises:
201
- InvalidTextError: If the text is empty or invalid.
202
- RuntimeError: If the model is not loaded.
203
-
204
- """
205
- if self._voice is None:
206
- msg = "Model not loaded"
206
+ """Synthesize text to audio."""
207
+ if self._executor is None:
208
+ msg = "Model not loaded. Call load() first."
207
209
  raise RuntimeError(msg)
208
210
 
209
211
  if not text or not text.strip():
@@ -211,20 +213,14 @@ class PiperBackend:
211
213
  raise InvalidTextError(msg)
212
214
 
213
215
  # Convert speed to length_scale (inverse relationship)
214
- # Speed is already validated/clamped by the API layer
215
216
  # length_scale < 1.0 = faster, > 1.0 = slower
216
217
  length_scale = 1.0 / speed
217
218
 
218
- # Run synthesis in executor to avoid blocking.
219
- # Thread-safe: ONNX Runtime InferenceSession.run() is thread-safe since v1.10+,
220
- # so concurrent requests can share the same PiperVoice instance safely.
221
219
  loop = asyncio.get_running_loop()
222
220
  audio_data, duration = await loop.run_in_executor(
223
- None,
224
- _synthesize_sync,
225
- self._voice,
221
+ self._executor,
222
+ _synthesize_in_subprocess,
226
223
  text,
227
- self._sample_rate,
228
224
  length_scale,
229
225
  )
230
226
 
@@ -333,6 +333,7 @@ agent-cli dev clean [OPTIONS]
333
333
  | `--no-commits` | `false` | Also remove worktrees with 0 commits ahead of default branch (abandoned branches) |
334
334
  | `--dry-run, -n` | `false` | Preview what would be removed without actually removing |
335
335
  | `--yes, -y` | `false` | Skip confirmation prompts |
336
+ | `--force, -f` | `false` | Force removal of worktrees with modified or untracked files |
336
337
 
337
338
 
338
339
  <!-- OUTPUT:END -->
@@ -52,19 +52,19 @@ The `setup-macos.sh` script:
52
52
  - ✅ Installs `uv` if needed
53
53
  - ✅ Installs/checks Ollama (native macOS app)
54
54
  - ✅ Installs Zellij for session management
55
- - ✅ Prepares Wyoming service runners
55
+ - ✅ Installs Whisper and TTS as launchd daemons via `agent-cli daemon install`
56
56
 
57
57
  ## Services Overview
58
58
 
59
- | Service | Implementation | Port | GPU Support |
60
- | ---------------- | ---------------------- | ----- | -------------------- |
61
- | **Ollama** | Native macOS app | 11434 | ✅ Metal GPU |
62
- | **Whisper** | Wyoming MLX Whisper | 10300 | ✅ Apple Silicon MLX |
63
- | **Piper** | Wyoming Piper (via uv) | 10200 | N/A |
64
- | **OpenWakeWord** | Wyoming OpenWakeWord | 10400 | N/A |
59
+ | Service | Implementation | Port | GPU Support |
60
+ | ---------------- | ----------------------- | ----- | -------------------- |
61
+ | **Ollama** | Native macOS app | 11434 | ✅ Metal GPU |
62
+ | **Whisper** | MLX Whisper (via daemon)| 10300 | ✅ Apple Silicon MLX |
63
+ | **TTS (Kokoro)** | Kokoro TTS (via daemon) | 10200 | ✅ Metal GPU (MPS) |
64
+ | **OpenWakeWord** | Wyoming OpenWakeWord | 10400 | N/A |
65
65
 
66
66
  > [!NOTE]
67
- > Whisper uses [wyoming-mlx-whisper](https://github.com/basnijholt/wyoming-mlx-whisper) with `whisper-large-v3-turbo` for near real-time transcription on Apple Silicon.
67
+ > Whisper and TTS run as launchd daemons via `agent-cli daemon install`, using MLX and Metal for GPU acceleration on Apple Silicon.
68
68
 
69
69
  ## Session Management with Zellij
70
70
 
@@ -95,13 +95,14 @@ brew services start ollama
95
95
  # Or run in foreground:
96
96
  ollama serve
97
97
 
98
- # Whisper (Apple Silicon: launchd service or manual)
99
- launchctl list com.wyoming_mlx_whisper
100
- # Or run in foreground:
101
- agent-cli server whisper
98
+ # Whisper and TTS are installed as launchd daemons
99
+ agent-cli daemon status # Check all daemon status
100
+ agent-cli daemon install whisper # Install whisper daemon
101
+ agent-cli daemon install tts-kokoro # Install TTS daemon
102
102
 
103
- # Piper
104
- agent-cli server tts --backend piper
103
+ # Or run in foreground (without daemon):
104
+ agent-cli server whisper
105
+ agent-cli server tts --backend kokoro
105
106
 
106
107
  # OpenWakeWord
107
108
  scripts/run-openwakeword.sh
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes