agent-cli 0.105.2__tar.gz → 0.106.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 (460) hide show
  1. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/workflows/docker.yml +4 -4
  2. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/workflows/pytest.yml +1 -1
  3. {agent_cli-0.105.2 → agent_cli-0.106.0}/PKG-INFO +1 -1
  4. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/transcribe.py +24 -0
  5. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/AgentCommandRunner.swift +6 -1
  6. agent_cli-0.106.0/macos/AgentCLI/Sources/AgentCLI/CommandResult.swift +17 -0
  7. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/VoiceLevelOverlay.swift +85 -28
  8. agent_cli-0.106.0/macos/AgentCLI/Tests/AgentCLITests/TranscriptionResultTests.swift +23 -0
  9. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Tests/AgentCLITests/VoiceLevelMeterTests.swift +89 -0
  10. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/appcast.xml +19 -15
  11. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_transcribe.py +2 -0
  12. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_transcribe_agent.py +61 -0
  13. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_transcribe_recovery.py +5 -1
  14. agent_cli-0.105.2/macos/AgentCLI/Sources/AgentCLI/CommandResult.swift +0 -6
  15. {agent_cli-0.105.2 → agent_cli-0.106.0}/.claude/skills/agent-cli-dev/SKILL.md +0 -0
  16. {agent_cli-0.105.2 → agent_cli-0.106.0}/.claude/skills/agent-cli-dev/examples.md +0 -0
  17. {agent_cli-0.105.2 → agent_cli-0.106.0}/.claude-plugin/README.md +0 -0
  18. {agent_cli-0.105.2 → agent_cli-0.106.0}/.claude-plugin/marketplace.json +0 -0
  19. {agent_cli-0.105.2 → agent_cli-0.106.0}/.claude-plugin/plugin.json +0 -0
  20. {agent_cli-0.105.2 → agent_cli-0.106.0}/.claude-plugin/skills/agent-cli-dev/SKILL.md +0 -0
  21. {agent_cli-0.105.2 → agent_cli-0.106.0}/.claude-plugin/skills/agent-cli-dev/examples.md +0 -0
  22. {agent_cli-0.105.2 → agent_cli-0.106.0}/.cursorrules +0 -0
  23. {agent_cli-0.105.2 → agent_cli-0.106.0}/.dockerignore +0 -0
  24. {agent_cli-0.105.2 → agent_cli-0.106.0}/.env.example +0 -0
  25. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/logo.svg +0 -0
  26. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/release-drafter.yml +0 -0
  27. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/renovate.json +0 -0
  28. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/scripts/check_extras_sync.py +0 -0
  29. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/scripts/check_plugin_skill_sync.py +0 -0
  30. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/scripts/normalize_appcast.py +0 -0
  31. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/scripts/sync_extras.py +0 -0
  32. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/scripts/sync_requirements.py +0 -0
  33. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/workflows/automerge.yml +0 -0
  34. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/workflows/docs.yml +0 -0
  35. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/workflows/markdown-code-runner.yml +0 -0
  36. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/workflows/release-drafter.yml +0 -0
  37. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/workflows/release.yml +0 -0
  38. {agent_cli-0.105.2 → agent_cli-0.106.0}/.github/workflows/toc.yaml +0 -0
  39. {agent_cli-0.105.2 → agent_cli-0.106.0}/.gitignore +0 -0
  40. {agent_cli-0.105.2 → agent_cli-0.106.0}/.jscpd.json +0 -0
  41. {agent_cli-0.105.2 → agent_cli-0.106.0}/.pre-commit-config.yaml +0 -0
  42. {agent_cli-0.105.2 → agent_cli-0.106.0}/.prompts/docs-review.md +0 -0
  43. {agent_cli-0.105.2 → agent_cli-0.106.0}/.prompts/pr-review.md +0 -0
  44. {agent_cli-0.105.2 → agent_cli-0.106.0}/CLAUDE.md +0 -0
  45. {agent_cli-0.105.2 → agent_cli-0.106.0}/LICENSE +0 -0
  46. {agent_cli-0.105.2 → agent_cli-0.106.0}/LLAMA_SERVER_USAGE.md +0 -0
  47. {agent_cli-0.105.2 → agent_cli-0.106.0}/README.md +0 -0
  48. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/__init__.py +0 -0
  49. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/__main__.py +0 -0
  50. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_extras.json +0 -0
  51. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_overrides/nemo-whisper.txt +0 -0
  52. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/.gitkeep +0 -0
  53. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/audio.txt +0 -0
  54. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/diarization.txt +0 -0
  55. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/faster-whisper.txt +0 -0
  56. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/kokoro.txt +0 -0
  57. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/llm.txt +0 -0
  58. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/memory.txt +0 -0
  59. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/mlx-whisper.txt +0 -0
  60. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/nemo-whisper.txt +0 -0
  61. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/piper.txt +0 -0
  62. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/rag.txt +0 -0
  63. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/server.txt +0 -0
  64. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/speed.txt +0 -0
  65. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/vad.txt +0 -0
  66. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/vectordb.txt +0 -0
  67. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/whisper-transformers.txt +0 -0
  68. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_requirements/wyoming.txt +0 -0
  69. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/_tools.py +0 -0
  70. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/__init__.py +0 -0
  71. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/_voice_agent_common.py +0 -0
  72. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/assistant.py +0 -0
  73. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/autocorrect.py +0 -0
  74. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/chat.py +0 -0
  75. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/diarize_live_session.py +0 -0
  76. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/memory/__init__.py +0 -0
  77. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/memory/add.py +0 -0
  78. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/memory/proxy.py +0 -0
  79. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/rag_proxy.py +0 -0
  80. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/speak.py +0 -0
  81. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/speakers.py +0 -0
  82. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/transcribe_live.py +0 -0
  83. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/agents/voice_edit.py +0 -0
  84. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/api.py +0 -0
  85. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/cli.py +0 -0
  86. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/config.py +0 -0
  87. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/config_cmd.py +0 -0
  88. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/constants.py +0 -0
  89. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/__init__.py +0 -0
  90. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/alignment.py +0 -0
  91. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/audio.py +0 -0
  92. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/audio_format.py +0 -0
  93. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/chroma.py +0 -0
  94. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/deps.py +0 -0
  95. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/diarization.py +0 -0
  96. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/openai_proxy.py +0 -0
  97. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/process.py +0 -0
  98. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/reranker.py +0 -0
  99. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/speaker_identity.py +0 -0
  100. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/sse.py +0 -0
  101. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/transcription_logger.py +0 -0
  102. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/utils.py +0 -0
  103. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/vad.py +0 -0
  104. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/core/watch.py +0 -0
  105. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/daemon/__init__.py +0 -0
  106. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/daemon/cli.py +0 -0
  107. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/__init__.py +0 -0
  108. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/_branch_name.py +0 -0
  109. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/_config.py +0 -0
  110. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/_output.py +0 -0
  111. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/cleanup.py +0 -0
  112. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/cli.py +0 -0
  113. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/__init__.py +0 -0
  114. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/aider.py +0 -0
  115. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/base.py +0 -0
  116. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/claude.py +0 -0
  117. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/codex.py +0 -0
  118. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/continue_dev.py +0 -0
  119. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/copilot.py +0 -0
  120. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/cursor_agent.py +0 -0
  121. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/gemini.py +0 -0
  122. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/opencode.py +0 -0
  123. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/coding_agents/registry.py +0 -0
  124. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/__init__.py +0 -0
  125. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/base.py +0 -0
  126. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/cursor.py +0 -0
  127. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/emacs.py +0 -0
  128. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/jetbrains.py +0 -0
  129. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/nano.py +0 -0
  130. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/neovim.py +0 -0
  131. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/registry.py +0 -0
  132. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/sublime.py +0 -0
  133. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/vim.py +0 -0
  134. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/vscode.py +0 -0
  135. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/editors/zed.py +0 -0
  136. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/hooks.py +0 -0
  137. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/launch.py +0 -0
  138. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/project.py +0 -0
  139. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/registry.py +0 -0
  140. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/skill/SKILL.md +0 -0
  141. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/skill/examples.md +0 -0
  142. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/__init__.py +0 -0
  143. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/apple_terminal.py +0 -0
  144. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/base.py +0 -0
  145. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/cmux.py +0 -0
  146. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/gnome.py +0 -0
  147. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/iterm2.py +0 -0
  148. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/kitty.py +0 -0
  149. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/registry.py +0 -0
  150. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/tmux.py +0 -0
  151. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/warp.py +0 -0
  152. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/terminals/zellij.py +0 -0
  153. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/dev/worktree.py +0 -0
  154. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/docs_gen.py +0 -0
  155. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/example-config.toml +0 -0
  156. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/install/__init__.py +0 -0
  157. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/install/common.py +0 -0
  158. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/install/extras.py +0 -0
  159. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/install/hotkeys.py +0 -0
  160. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/install/launchd.py +0 -0
  161. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/install/service_config.py +0 -0
  162. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/install/services.py +0 -0
  163. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/install/systemd.py +0 -0
  164. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/__init__.py +0 -0
  165. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_files.py +0 -0
  166. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_filters.py +0 -0
  167. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_git.py +0 -0
  168. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_indexer.py +0 -0
  169. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_ingest.py +0 -0
  170. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_persistence.py +0 -0
  171. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_prompt.py +0 -0
  172. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_retrieval.py +0 -0
  173. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_store.py +0 -0
  174. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_streaming.py +0 -0
  175. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/_tasks.py +0 -0
  176. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/api.py +0 -0
  177. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/client.py +0 -0
  178. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/engine.py +0 -0
  179. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/entities.py +0 -0
  180. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/memory/models.py +0 -0
  181. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/opts.py +0 -0
  182. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/py.typed +0 -0
  183. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/__init__.py +0 -0
  184. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/_indexer.py +0 -0
  185. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/_indexing.py +0 -0
  186. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/_prompt.py +0 -0
  187. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/_retriever.py +0 -0
  188. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/_store.py +0 -0
  189. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/_utils.py +0 -0
  190. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/api.py +0 -0
  191. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/client.py +0 -0
  192. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/engine.py +0 -0
  193. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/rag/models.py +0 -0
  194. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/.runtime/.gitkeep +0 -0
  195. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/__init__.py +0 -0
  196. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/linux-hotkeys/README.md +0 -0
  197. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/linux-hotkeys/toggle-autocorrect.sh +0 -0
  198. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/linux-hotkeys/toggle-transcription.sh +0 -0
  199. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/linux-hotkeys/toggle-voice-edit.sh +0 -0
  200. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/macos-hotkeys/README.md +0 -0
  201. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/macos-hotkeys/skhd-config-example +0 -0
  202. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/macos-hotkeys/toggle-autocorrect.sh +0 -0
  203. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/macos-hotkeys/toggle-transcription.sh +0 -0
  204. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/macos-hotkeys/toggle-voice-edit.sh +0 -0
  205. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/nvidia-asr-server/README.md +0 -0
  206. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/nvidia-asr-server/pyproject.toml +0 -0
  207. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/nvidia-asr-server/server.py +0 -0
  208. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/nvidia-asr-server/shell.nix +0 -0
  209. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/nvidia-asr-server/uv.lock +0 -0
  210. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/run-openwakeword.sh +0 -0
  211. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/setup-linux-hotkeys.sh +0 -0
  212. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/setup-linux.sh +0 -0
  213. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/setup-macos-hotkeys.sh +0 -0
  214. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/setup-macos.sh +0 -0
  215. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/setup-windows.ps1 +0 -0
  216. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/start-all-services-windows.ps1 +0 -0
  217. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/scripts/start-all-services.sh +0 -0
  218. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/__init__.py +0 -0
  219. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/cli.py +0 -0
  220. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/common.py +0 -0
  221. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/model_manager.py +0 -0
  222. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/model_registry.py +0 -0
  223. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/proxy/__init__.py +0 -0
  224. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/proxy/api.py +0 -0
  225. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/proxy/diarization.py +0 -0
  226. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/streaming.py +0 -0
  227. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/tts/__init__.py +0 -0
  228. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/tts/api.py +0 -0
  229. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/tts/backends/__init__.py +0 -0
  230. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/tts/backends/base.py +0 -0
  231. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/tts/backends/kokoro.py +0 -0
  232. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/tts/backends/piper.py +0 -0
  233. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/tts/model_manager.py +0 -0
  234. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/tts/model_registry.py +0 -0
  235. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/tts/wyoming_handler.py +0 -0
  236. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/__init__.py +0 -0
  237. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/api.py +0 -0
  238. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/backends/__init__.py +0 -0
  239. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/backends/audio.py +0 -0
  240. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/backends/base.py +0 -0
  241. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/backends/faster_whisper.py +0 -0
  242. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/backends/mlx.py +0 -0
  243. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/backends/nemo.py +0 -0
  244. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/backends/transformers.py +0 -0
  245. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/languages.py +0 -0
  246. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/model_manager.py +0 -0
  247. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/model_registry.py +0 -0
  248. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/server/whisper/wyoming_handler.py +0 -0
  249. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/services/__init__.py +0 -0
  250. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/services/_wyoming_utils.py +0 -0
  251. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/services/asr.py +0 -0
  252. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/services/llm.py +0 -0
  253. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/services/tts.py +0 -0
  254. {agent_cli-0.105.2 → agent_cli-0.106.0}/agent_cli/services/wake_word.py +0 -0
  255. {agent_cli-0.105.2 → agent_cli-0.106.0}/docker/diarization.Dockerfile +0 -0
  256. {agent_cli-0.105.2 → agent_cli-0.106.0}/docker/docker-compose.yml +0 -0
  257. {agent_cli-0.105.2 → agent_cli-0.106.0}/docker/memory-proxy.Dockerfile +0 -0
  258. {agent_cli-0.105.2 → agent_cli-0.106.0}/docker/rag-proxy.Dockerfile +0 -0
  259. {agent_cli-0.105.2 → agent_cli-0.106.0}/docker/transcribe-proxy.Dockerfile +0 -0
  260. {agent_cli-0.105.2 → agent_cli-0.106.0}/docker/tts.Dockerfile +0 -0
  261. {agent_cli-0.105.2 → agent_cli-0.106.0}/docker/whisper.Dockerfile +0 -0
  262. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/CNAME +0 -0
  263. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/architecture/index.md +0 -0
  264. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/architecture/memory.md +0 -0
  265. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/architecture/rag.md +0 -0
  266. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/assistant.md +0 -0
  267. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/autocorrect.md +0 -0
  268. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/chat.md +0 -0
  269. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/config.md +0 -0
  270. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/daemon.md +0 -0
  271. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/dev.md +0 -0
  272. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/diarize-live-session.md +0 -0
  273. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/index.md +0 -0
  274. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/install-extras.md +0 -0
  275. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/install-hotkeys.md +0 -0
  276. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/install-services.md +0 -0
  277. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/memory.md +0 -0
  278. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/rag-proxy.md +0 -0
  279. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/server/index.md +0 -0
  280. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/server/transcribe-proxy.md +0 -0
  281. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/server/tts.md +0 -0
  282. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/server/whisper.md +0 -0
  283. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/speak.md +0 -0
  284. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/speakers.md +0 -0
  285. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/start-services.md +0 -0
  286. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/transcribe-live.md +0 -0
  287. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/transcribe.md +0 -0
  288. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/commands/voice-edit.md +0 -0
  289. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/configuration.md +0 -0
  290. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/getting-started.md +0 -0
  291. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/iOS_Shortcut_Guide.md +0 -0
  292. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/index.md +0 -0
  293. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/installation/docker.md +0 -0
  294. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/installation/index.md +0 -0
  295. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/installation/linux.md +0 -0
  296. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/installation/macos-app.md +0 -0
  297. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/installation/macos.md +0 -0
  298. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/installation/nixos.md +0 -0
  299. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/installation/windows.md +0 -0
  300. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/logo-avatar.svg +0 -0
  301. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/logo-clean.svg +0 -0
  302. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/overrides/partials/integrations/analytics/custom.html +0 -0
  303. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/run_markdown_code_runner.py +0 -0
  304. {agent_cli-0.105.2 → agent_cli-0.106.0}/docs/system-integration.md +0 -0
  305. {agent_cli-0.105.2 → agent_cli-0.106.0}/example.agent-cli-config.toml +0 -0
  306. {agent_cli-0.105.2 → agent_cli-0.106.0}/justfile +0 -0
  307. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Package.resolved +0 -0
  308. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Package.swift +0 -0
  309. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/README.md +0 -0
  310. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Resources/AgentCLI.entitlements +0 -0
  311. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Resources/Info.plist +0 -0
  312. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Resources/dmg-background.svg +0 -0
  313. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/AgentCLIApp.swift +0 -0
  314. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/AgentCommand.swift +0 -0
  315. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/AgentRuntime.swift +0 -0
  316. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/AppDelegate.swift +0 -0
  317. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/AppMetadata.swift +0 -0
  318. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/AppUpdater.swift +0 -0
  319. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/BootstrapState.swift +0 -0
  320. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/ConfigurableHotkeyController.swift +0 -0
  321. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/FocusedTextTarget.swift +0 -0
  322. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/LiveTranscriptionPreview.swift +0 -0
  323. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/LoginItemController.swift +0 -0
  324. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/MenuActivityStatus.swift +0 -0
  325. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/MenuActivityStatusRow.swift +0 -0
  326. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/MenuActivityTracker.swift +0 -0
  327. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/MenuBarIcon.swift +0 -0
  328. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/RecentTranscriptionReader.swift +0 -0
  329. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/RecordingIndicatorController.swift +0 -0
  330. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/RecordingSoundSettings.swift +0 -0
  331. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/RuntimeSettings.swift +0 -0
  332. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/SettingsWindowController.swift +0 -0
  333. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/Shortcuts.swift +0 -0
  334. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/StatusMenuController.swift +0 -0
  335. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/TranscriptPasteController.swift +0 -0
  336. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Sources/AgentCLI/TranscriptionSettings.swift +0 -0
  337. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Tests/AgentCLITests/AgentCommandTests.swift +0 -0
  338. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Tests/AgentCLITests/ConfigurableHotkeyControllerTests.swift +0 -0
  339. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Tests/AgentCLITests/LivePreviewSwiftTestingTests.swift +0 -0
  340. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Tests/AgentCLITests/LiveTranscriptionPreviewTests.swift +0 -0
  341. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Tests/AgentCLITests/LoginItemControllerTests.swift +0 -0
  342. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Tests/AgentCLITests/RecentTranscriptionReaderTests.swift +0 -0
  343. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Tests/AgentCLITests/RecordingIndicatorControllerTests.swift +0 -0
  344. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/AgentCLI/Tests/AgentCLITests/ShortcutDefaultsTests.swift +0 -0
  345. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/build-macos-app.sh +0 -0
  346. {agent_cli-0.105.2 → agent_cli-0.106.0}/macos/test-macos-app-e2e.sh +0 -0
  347. {agent_cli-0.105.2 → agent_cli-0.106.0}/pyproject.toml +0 -0
  348. {agent_cli-0.105.2 → agent_cli-0.106.0}/reddit.md +0 -0
  349. {agent_cli-0.105.2 → agent_cli-0.106.0}/shell.nix +0 -0
  350. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/__init__.py +0 -0
  351. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/__init__.py +0 -0
  352. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_fix_my_text.py +0 -0
  353. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_interactive.py +0 -0
  354. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_interactive_extra.py +0 -0
  355. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_memory_add.py +0 -0
  356. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_speak.py +0 -0
  357. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_speak_e2e.py +0 -0
  358. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_speakers.py +0 -0
  359. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_transcribe_e2e.py +0 -0
  360. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_transcribe_live.py +0 -0
  361. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_tts_common.py +0 -0
  362. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_tts_common_extra.py +0 -0
  363. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_voice_agent_common.py +0 -0
  364. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_voice_edit.py +0 -0
  365. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_voice_edit_e2e.py +0 -0
  366. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/agents/test_wake_word_assistant.py +0 -0
  367. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/conftest.py +0 -0
  368. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/core/__init__.py +0 -0
  369. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/core/test_audio.py +0 -0
  370. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/core/test_audio_format.py +0 -0
  371. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/core/test_audio_levels.py +0 -0
  372. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/core/test_chroma.py +0 -0
  373. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/core/test_sse.py +0 -0
  374. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/core/test_vad.py +0 -0
  375. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/core/test_watch.py +0 -0
  376. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/__init__.py +0 -0
  377. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/test_cleanup.py +0 -0
  378. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/test_cli.py +0 -0
  379. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/test_coding_agents.py +0 -0
  380. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/test_editors.py +0 -0
  381. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/test_hooks.py +0 -0
  382. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/test_launch.py +0 -0
  383. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/test_project.py +0 -0
  384. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/test_terminals.py +0 -0
  385. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/test_verification.py +0 -0
  386. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/dev/test_worktree.py +0 -0
  387. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/install/__init__.py +0 -0
  388. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/install/test_extras.py +0 -0
  389. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/install/test_launchd.py +0 -0
  390. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/__init__.py +0 -0
  391. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_api_health.py +0 -0
  392. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_api_integration_liveish.py +0 -0
  393. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_client.py +0 -0
  394. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_engine.py +0 -0
  395. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_files.py +0 -0
  396. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_filters.py +0 -0
  397. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_git_integration.py +0 -0
  398. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_indexer.py +0 -0
  399. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_memory_integration.py +0 -0
  400. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_proxy_passthrough.py +0 -0
  401. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_store.py +0 -0
  402. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/memory/test_utils.py +0 -0
  403. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/mocks/__init__.py +0 -0
  404. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/mocks/audio.py +0 -0
  405. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/mocks/llm.py +0 -0
  406. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/mocks/wyoming.py +0 -0
  407. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/__init__.py +0 -0
  408. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_api.py +0 -0
  409. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_engine.py +0 -0
  410. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_history.py +0 -0
  411. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_indexer.py +0 -0
  412. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_indexing.py +0 -0
  413. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_rag_client.py +0 -0
  414. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_rag_integration_liveish.py +0 -0
  415. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_rag_proxy_passthrough.py +0 -0
  416. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_retriever.py +0 -0
  417. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_store.py +0 -0
  418. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/rag/test_utils.py +0 -0
  419. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_alignment.py +0 -0
  420. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_api.py +0 -0
  421. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_api_integration.py +0 -0
  422. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_asr.py +0 -0
  423. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_asr_recovery.py +0 -0
  424. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_audio_e2e.py +0 -0
  425. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_cli.py +0 -0
  426. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_config.py +0 -0
  427. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_config_cmd.py +0 -0
  428. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_daemon.py +0 -0
  429. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_diarization.py +0 -0
  430. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_diarize_live_session.py +0 -0
  431. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_docs_gen.py +0 -0
  432. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_env_vars.py +0 -0
  433. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_faster_whisper_backend.py +0 -0
  434. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_json_output.py +0 -0
  435. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_llm.py +0 -0
  436. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_llm_gemini.py +0 -0
  437. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_macos_app.py +0 -0
  438. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_memory_tools.py +0 -0
  439. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_mlx_backend.py +0 -0
  440. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_nemo_backend.py +0 -0
  441. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_normalize_appcast.py +0 -0
  442. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_process_manager.py +0 -0
  443. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_proxy_diarization.py +0 -0
  444. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_requires_extras.py +0 -0
  445. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_server_streaming.py +0 -0
  446. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_server_tts.py +0 -0
  447. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_server_tts_wyoming.py +0 -0
  448. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_server_whisper.py +0 -0
  449. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_server_whisper_wyoming.py +0 -0
  450. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_services.py +0 -0
  451. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_speaker_identity.py +0 -0
  452. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_tools.py +0 -0
  453. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_transformers_backend.py +0 -0
  454. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_tts.py +0 -0
  455. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_utils.py +0 -0
  456. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_wake_word.py +0 -0
  457. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_whisper_backend_audio.py +0 -0
  458. {agent_cli-0.105.2 → agent_cli-0.106.0}/tests/test_wyoming_utils.py +0 -0
  459. {agent_cli-0.105.2 → agent_cli-0.106.0}/uv.lock +0 -0
  460. {agent_cli-0.105.2 → agent_cli-0.106.0}/zensical.toml +0 -0
@@ -49,7 +49,7 @@ jobs:
49
49
  fetch-depth: 0 # Full history for version detection
50
50
 
51
51
  - name: Set up Docker Buildx
52
- uses: docker/setup-buildx-action@v4.3.0
52
+ uses: docker/setup-buildx-action@v4.4.1
53
53
 
54
54
  - name: Log in to Container Registry
55
55
  uses: docker/login-action@v4.5.1
@@ -79,7 +79,7 @@ jobs:
79
79
  type=sha,suffix=-${{ matrix.suffix }}
80
80
 
81
81
  - name: Build and push
82
- uses: docker/build-push-action@v7.3.0
82
+ uses: docker/build-push-action@v7.4.0
83
83
  with:
84
84
  context: .
85
85
  file: ${{ matrix.dockerfile }}
@@ -122,7 +122,7 @@ jobs:
122
122
  fetch-depth: 0 # Full history for version detection
123
123
 
124
124
  - name: Set up Docker Buildx
125
- uses: docker/setup-buildx-action@v4.3.0
125
+ uses: docker/setup-buildx-action@v4.4.1
126
126
 
127
127
  - name: Log in to Container Registry
128
128
  uses: docker/login-action@v4.5.1
@@ -152,7 +152,7 @@ jobs:
152
152
  type=sha
153
153
 
154
154
  - name: Build and push
155
- uses: docker/build-push-action@v7.3.0
155
+ uses: docker/build-push-action@v7.4.0
156
156
  with:
157
157
  context: .
158
158
  file: ${{ matrix.dockerfile }}
@@ -43,6 +43,6 @@ jobs:
43
43
  run: uv run --extra audio --extra diarization --extra llm --extra rag --extra memory --extra vad --extra faster-whisper --extra piper --extra kokoro --extra server --extra speed --extra test pytest -vvv
44
44
  - name: Upload coverage reports to Codecov
45
45
  if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
46
- uses: codecov/codecov-action@v7.1.0
46
+ uses: codecov/codecov-action@v7.1.1
47
47
  env:
48
48
  CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agent-cli
3
- Version: 0.105.2
3
+ Version: 0.106.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>
@@ -477,6 +477,9 @@ async def _async_main( # noqa: PLR0912, PLR0915, C901
477
477
  live_preview_config=live_preview_config,
478
478
  )
479
479
 
480
+ if transcript and not transcript.strip():
481
+ transcript = None
482
+
480
483
  elapsed = time.monotonic() - start_time
481
484
 
482
485
  # Apply diarization if enabled
@@ -554,6 +557,9 @@ async def _async_main( # noqa: PLR0912, PLR0915, C901
554
557
  live=live,
555
558
  context=combined_context,
556
559
  )
560
+ if general_cfg.clipboard and not (processed_transcript or "").strip():
561
+ # Keep the raw speech recoverable if cleanup overwrote it with blank text.
562
+ pyperclip.copy(transcript)
557
563
 
558
564
  # Log transcription if requested
559
565
  if transcription_log:
@@ -615,6 +621,21 @@ async def _async_main( # noqa: PLR0912, PLR0915, C901
615
621
  )
616
622
 
617
623
 
624
+ def _require_transcript(result: TranscriptResult, provider: str) -> None:
625
+ """Do not report successful dictation when the backend produced no text."""
626
+ if not (result.get("transcript") or "").strip():
627
+ if result.get("raw_transcript"):
628
+ message = "LLM cleanup returned no text. Retry with --no-llm to use the raw transcript."
629
+ else:
630
+ message = f"No transcript returned by {provider}. Check the microphone and ASR server."
631
+ typer.echo(
632
+ f"{message} "
633
+ "If a recording was saved, retry with agent-cli transcribe --last-recording.",
634
+ err=True,
635
+ )
636
+ raise typer.Exit(1)
637
+
638
+
618
639
  @app.command("transcribe", rich_help_panel="Voice Commands")
619
640
  @requires_extras("audio", "llm", process_name="transcribe")
620
641
  def transcribe( # noqa: PLR0912, PLR0911, PLR0915, C901
@@ -896,6 +917,7 @@ def transcribe( # noqa: PLR0912, PLR0911, PLR0915, C901
896
917
  LOGGER.exception("Diarization failed")
897
918
  _print_diarization_error(exc)
898
919
  raise typer.Exit(1) from None
920
+ _require_transcript(result, asr_provider)
899
921
  if json_output:
900
922
  print(json.dumps(result))
901
923
  return
@@ -937,6 +959,7 @@ def transcribe( # noqa: PLR0912, PLR0911, PLR0915, C901
937
959
  ):
938
960
  return
939
961
 
962
+ result = TranscriptResult(raw_transcript=None, transcript=None, llm_enabled=False)
940
963
  # Use context manager before audio setup so --stop can target startup reliably.
941
964
  try:
942
965
  with process.pid_file_context(process_name), suppress(KeyboardInterrupt):
@@ -992,5 +1015,6 @@ def transcribe( # noqa: PLR0912, PLR0911, PLR0915, C901
992
1015
  LOGGER.exception("Diarization failed")
993
1016
  _print_diarization_error(exc)
994
1017
  raise typer.Exit(1) from None
1018
+ _require_transcript(result, asr_provider)
995
1019
  if json_output:
996
1020
  print(json.dumps(result))
@@ -252,7 +252,12 @@ final class AgentCommandRunner: ObservableObject {
252
252
  }
253
253
  }
254
254
 
255
- let result = AgentRuntime.shared.runAgentCLI(arguments: commandArguments)
255
+ let commandResult = AgentRuntime.shared.runAgentCLI(arguments: commandArguments)
256
+ // A stop acknowledgement may be empty; a completed recording must contain text.
257
+ // Validate here too because user-installed CLIs can predate the CLI-side check.
258
+ let result = shouldStartRecording && command.identifier == AgentCommand.toggleTranscription.identifier
259
+ ? commandResult.requiringTranscript()
260
+ : commandResult
256
261
  let message = Self.statusMessage(for: command, result: result)
257
262
  let notificationTitle = Self.notificationTitle(for: command, result: result)
258
263
  let notificationBody = Self.notificationBody(for: command, result: result, statusMessage: message)
@@ -0,0 +1,17 @@
1
+ import Foundation
2
+
3
+ struct CommandResult {
4
+ let exitCode: Int32
5
+ let output: String
6
+
7
+ func requiringTranscript() -> CommandResult {
8
+ guard exitCode == 0, output.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
9
+ return self
10
+ }
11
+ return CommandResult(
12
+ exitCode: 1,
13
+ output: "No transcript returned. Check the microphone and ASR server, then try again. "
14
+ + "If a recording was saved, recover it with agent-cli transcribe --last-recording."
15
+ )
16
+ }
17
+ }
@@ -3,7 +3,7 @@ import Foundation
3
3
  import SwiftUI
4
4
 
5
5
  enum VoiceLevelOverlayLayout {
6
- static let pillSize = CGSize(width: 147, height: 38)
6
+ static let pillSize = CGSize(width: 190, height: 38)
7
7
  static let textWidth = CGFloat(420)
8
8
  static let textHeight = CGFloat(86)
9
9
  static let shadowRadius = CGFloat(13)
@@ -72,41 +72,57 @@ struct VoiceLevelOverlayView: View {
72
72
  height: VoiceLevelOverlayLayout.panelSize(showsPreviewSpace: showsPreviewSpace).height,
73
73
  alignment: .bottom
74
74
  )
75
- .accessibilityLabel(Text("Voice level"))
75
+ .accessibilityElement(children: .ignore)
76
+ .accessibilityLabel(Text(meter.captureState == .recording
77
+ ? "Recording \(meter.recordingDuration)"
78
+ : meter.captureState.label))
79
+ .accessibilityValue(Text(showsPreviewSpace ? preview.text : ""))
76
80
  }
77
81
 
78
82
  private var levelMeter: some View {
79
- HStack(alignment: .center, spacing: 3.5) {
83
+ HStack(spacing: 8) {
84
+ if meter.captureState == .recording {
85
+ Text(meter.recordingDuration)
86
+ .font(.system(size: 12, weight: .semibold))
87
+ .monospacedDigit()
88
+ waveform
89
+ } else {
90
+ ProgressView()
91
+ .controlSize(.small)
92
+ Text(meter.captureState.label)
93
+ .font(.system(size: 12, weight: .semibold))
94
+ }
95
+ }
96
+ .foregroundStyle(statusColor)
97
+ .frame(width: VoiceLevelOverlayLayout.pillSize.width, height: VoiceLevelOverlayLayout.pillSize.height)
98
+ .background(Capsule().fill(statusColor.opacity(isLightMode ? 0.10 : 0.14)))
99
+ .background(Capsule().fill(backgroundColor))
100
+ .overlay(Capsule().stroke(statusColor.opacity(0.55), lineWidth: 1))
101
+ .shadow(
102
+ color: shadowColor,
103
+ radius: VoiceLevelOverlayLayout.shadowRadius,
104
+ y: VoiceLevelOverlayLayout.shadowYOffset
105
+ )
106
+ }
107
+
108
+ private var waveform: some View {
109
+ HStack(alignment: .center, spacing: 2) {
80
110
  ForEach(Array(meter.amplitudes.enumerated()), id: \.offset) { _, amplitude in
81
111
  Capsule()
82
112
  .fill(
83
113
  LinearGradient(
84
114
  colors: [
85
- barGradientStart,
86
- barGradientEnd
115
+ statusColor.opacity(0.65),
116
+ statusColor
87
117
  ],
88
118
  startPoint: .bottom,
89
119
  endPoint: .top
90
120
  )
91
121
  )
92
- .frame(width: 3.5, height: max(5, 25 * amplitude))
122
+ .frame(width: 2, height: max(5, 25 * amplitude))
93
123
  .animation(.easeOut(duration: 0.11), value: amplitude)
94
124
  }
95
125
  }
96
- .frame(width: VoiceLevelOverlayLayout.pillSize.width, height: VoiceLevelOverlayLayout.pillSize.height)
97
- .background(
98
- Capsule()
99
- .fill(backgroundColor)
100
- )
101
- .overlay(
102
- Capsule()
103
- .stroke(borderColor, lineWidth: 1)
104
- )
105
- .shadow(
106
- color: shadowColor,
107
- radius: VoiceLevelOverlayLayout.shadowRadius,
108
- y: VoiceLevelOverlayLayout.shadowYOffset
109
- )
110
126
  }
111
127
 
112
128
  private var isLightMode: Bool {
@@ -133,12 +149,15 @@ struct VoiceLevelOverlayView: View {
133
149
  Color.black.opacity(isLightMode ? 0.16 : 0.24)
134
150
  }
135
151
 
136
- private var barGradientStart: Color {
137
- isLightMode ? Color(red: 0.04, green: 0.45, blue: 0.95) : Color(red: 0.18, green: 0.82, blue: 0.92)
138
- }
139
-
140
- private var barGradientEnd: Color {
141
- isLightMode ? Color(red: 0.07, green: 0.72, blue: 0.68) : Color(red: 0.64, green: 0.96, blue: 0.58)
152
+ private var statusColor: Color {
153
+ if meter.captureState == .recording {
154
+ return isLightMode
155
+ ? Color(red: 0.04, green: 0.40, blue: 0.18)
156
+ : Color(red: 0.42, green: 0.91, blue: 0.58)
157
+ }
158
+ return isLightMode
159
+ ? Color(red: 0.62, green: 0.34, blue: 0.0)
160
+ : Color(red: 1.0, green: 0.74, blue: 0.25)
142
161
  }
143
162
  }
144
163
 
@@ -306,10 +325,28 @@ enum VoiceLevelLog {
306
325
  }()
307
326
  }
308
327
 
328
+ enum VoiceCaptureState {
329
+ case idle
330
+ case connecting
331
+ case recording
332
+ case waitingForAudio
333
+
334
+ var label: String {
335
+ switch self {
336
+ case .idle: return "Ready"
337
+ case .connecting: return "Connecting…"
338
+ case .recording: return "Recording"
339
+ case .waitingForAudio: return "Waiting for audio…"
340
+ }
341
+ }
342
+ }
343
+
309
344
  final class VoiceLevelMeter: ObservableObject {
310
345
  static let shared = VoiceLevelMeter()
311
346
 
312
347
  @Published private(set) var amplitudes = VoiceLevelMeter.idleAmplitudes
348
+ @Published private(set) var captureState = VoiceCaptureState.idle
349
+ @Published private(set) var recordingDuration = "00:00"
313
350
 
314
351
  private static let barCount = 16
315
352
  private static let idleAmplitudes = Array(repeating: CGFloat(0.16), count: barCount)
@@ -319,6 +356,7 @@ final class VoiceLevelMeter: ObservableObject {
319
356
  private let levelLogURL: URL
320
357
  private let now: () -> Date
321
358
  private var timer: Timer?
359
+ private var recordingStartedAt: Date?
322
360
  private var phase = 0.0
323
361
  private var smoothedLevel = CGFloat(0.16)
324
362
 
@@ -330,6 +368,9 @@ final class VoiceLevelMeter: ObservableObject {
330
368
  func start() {
331
369
  guard timer == nil else { return }
332
370
  VoiceLevelLog.reset(levelLogURL)
371
+ captureState = .connecting
372
+ recordingStartedAt = nil
373
+ recordingDuration = "00:00"
333
374
  phase = 0
334
375
  smoothedLevel = Self.idleLevel
335
376
  amplitudes = Self.idleAmplitudes
@@ -345,13 +386,29 @@ final class VoiceLevelMeter: ObservableObject {
345
386
  func stop() {
346
387
  timer?.invalidate()
347
388
  timer = nil
389
+ captureState = .idle
390
+ recordingStartedAt = nil
391
+ recordingDuration = "00:00"
348
392
  phase = 0
349
393
  smoothedLevel = Self.idleLevel
350
394
  amplitudes = Self.idleAmplitudes
351
395
  }
352
396
 
353
- private func pollLevel() {
354
- let level = VoiceLevelLog.latestLevel(from: levelLogURL, now: now()) ?? Self.idleLevel
397
+ func pollLevel() {
398
+ guard timer != nil else { return }
399
+ let now = now()
400
+ guard let level = VoiceLevelLog.latestLevel(from: levelLogURL, now: now) else {
401
+ if captureState == .recording {
402
+ captureState = .waitingForAudio
403
+ }
404
+ amplitudes = Self.idleAmplitudes
405
+ return
406
+ }
407
+ captureState = .recording
408
+ let startedAt = recordingStartedAt ?? now
409
+ recordingStartedAt = startedAt
410
+ let elapsedSeconds = max(0, Int(now.timeIntervalSince(startedAt)))
411
+ recordingDuration = String(format: "%02d:%02d", elapsedSeconds / 60, elapsedSeconds % 60)
355
412
  updateDisplay(level: level)
356
413
  }
357
414
 
@@ -0,0 +1,23 @@
1
+ #if canImport(XCTest)
2
+ import XCTest
3
+ @testable import AgentCLI
4
+
5
+ final class TranscriptionResultTests: XCTestCase {
6
+ func testEmptySuccessfulRecordingBecomesFailure() {
7
+ for output in ["", " \n\t"] {
8
+ let result = CommandResult(exitCode: 0, output: output).requiringTranscript()
9
+ XCTAssertNotEqual(result.exitCode, 0)
10
+ XCTAssertTrue(result.output.contains("No transcript"))
11
+ }
12
+ }
13
+
14
+ func testTranscriptAndBackendFailureArePreserved() {
15
+ let success = CommandResult(exitCode: 0, output: "Hello world").requiringTranscript()
16
+ XCTAssertEqual(success.exitCode, 0)
17
+ XCTAssertEqual(success.output, "Hello world")
18
+ let failure = CommandResult(exitCode: 7, output: "Connection lost").requiringTranscript()
19
+ XCTAssertEqual(failure.exitCode, 7)
20
+ XCTAssertEqual(failure.output, "Connection lost")
21
+ }
22
+ }
23
+ #endif
@@ -4,6 +4,95 @@ import XCTest
4
4
  @testable import AgentCLI
5
5
 
6
6
  final class VoiceLevelMeterTests: XCTestCase {
7
+ func testRecordingTimerExcludesStartupAndResetsBetweenRecordings() throws {
8
+ let logURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
9
+ var now = try XCTUnwrap(Self.iso8601.date(from: "2026-06-04T12:00:00Z"))
10
+ let meter = VoiceLevelMeter(levelLogURL: logURL, now: { now })
11
+ defer {
12
+ meter.stop()
13
+ try? FileManager.default.removeItem(at: logURL)
14
+ }
15
+ meter.start()
16
+ now = now.addingTimeInterval(10)
17
+ meter.pollLevel()
18
+ XCTAssertEqual(meter.recordingDuration, "00:00")
19
+
20
+ func publishAudio() throws {
21
+ try "{\"timestamp\":\"\(Self.iso8601.string(from: now))\",\"level\":0}"
22
+ .write(to: logURL, atomically: true, encoding: .utf8)
23
+ meter.pollLevel()
24
+ }
25
+ try publishAudio()
26
+ XCTAssertEqual(meter.recordingDuration, "00:00")
27
+ now = now.addingTimeInterval(9)
28
+ try publishAudio()
29
+ XCTAssertEqual(meter.recordingDuration, "00:09")
30
+ now = now.addingTimeInterval(56)
31
+ try publishAudio()
32
+ XCTAssertEqual(meter.recordingDuration, "01:05")
33
+ now = now.addingTimeInterval(3600)
34
+ try publishAudio()
35
+ XCTAssertEqual(meter.recordingDuration, "61:05")
36
+
37
+ meter.stop()
38
+ XCTAssertEqual(meter.recordingDuration, "00:00")
39
+ meter.start()
40
+ try publishAudio()
41
+ XCTAssertEqual(meter.recordingDuration, "00:00")
42
+ }
43
+
44
+ func testRecordingReadinessFollowsFreshAudioIncludingSilence() throws {
45
+ let logURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
46
+ var now = try XCTUnwrap(Self.iso8601.date(from: "2026-06-04T12:00:00Z"))
47
+ let meter = VoiceLevelMeter(levelLogURL: logURL, now: { now })
48
+ defer {
49
+ meter.stop()
50
+ try? FileManager.default.removeItem(at: logURL)
51
+ }
52
+
53
+ // A previous recording must not make a new request look ready.
54
+ try #"{"timestamp":"2026-06-04T12:00:00Z","level":0.9}"#
55
+ .write(to: logURL, atomically: true, encoding: .utf8)
56
+ meter.start()
57
+ XCTAssertEqual(meter.captureState, .connecting)
58
+
59
+ try #"{"timestamp":"2026-06-04T12:00:00Z","level":0}"#
60
+ .write(to: logURL, atomically: true, encoding: .utf8)
61
+ meter.pollLevel()
62
+ XCTAssertEqual(meter.captureState, .recording, "Silent audio still proves capture is running.")
63
+
64
+ now = now.addingTimeInterval(2)
65
+ meter.pollLevel()
66
+ XCTAssertEqual(meter.captureState, .waitingForAudio)
67
+
68
+ try #"{"timestamp":"2026-06-04T12:00:02Z","level":0.6}"#
69
+ .write(to: logURL, atomically: true, encoding: .utf8)
70
+ meter.pollLevel()
71
+ XCTAssertEqual(meter.captureState, .recording)
72
+
73
+ meter.stop()
74
+ meter.pollLevel()
75
+ XCTAssertEqual(meter.captureState, .idle, "Late polling must not revive a released overlay.")
76
+ meter.start()
77
+ XCTAssertEqual(meter.captureState, .connecting)
78
+ }
79
+
80
+ func testConnectingDoesNotAnimateFakeMicrophoneActivity() throws {
81
+ let logURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
82
+ let meter = VoiceLevelMeter(levelLogURL: logURL)
83
+ defer {
84
+ meter.stop()
85
+ try? FileManager.default.removeItem(at: logURL)
86
+ }
87
+ meter.start()
88
+ let initialAmplitudes = meter.amplitudes
89
+ meter.pollLevel()
90
+ XCTAssertEqual(meter.captureState, .connecting)
91
+ XCTAssertEqual(meter.amplitudes, initialAmplitudes)
92
+ meter.stop()
93
+ XCTAssertEqual(meter.captureState, .idle)
94
+ }
95
+
7
96
  func testDisplayAmplitudesUseSineWaveShape() {
8
97
  let amplitudes = VoiceLevelMeter.displayAmplitudes(level: 0.6, phase: 0.22)
9
98
 
@@ -4,6 +4,25 @@
4
4
  <title>Agent CLI Updates</title>
5
5
  <link>https://github.com/basnijholt/agent-cli</link>
6
6
  <description>Signed Agent CLI macOS app updates.</description>
7
+ <item>
8
+ <title>0.105.2</title>
9
+ <pubDate>Tue, 15 Sep 2026 07:58:55 +0000</pubDate>
10
+ <link>https://github.com/basnijholt/agent-cli</link>
11
+ <sparkle:version>206</sparkle:version>
12
+ <sparkle:shortVersionString>0.105.2</sparkle:shortVersionString>
13
+ <sparkle:minimumSystemVersion>13.0</sparkle:minimumSystemVersion>
14
+ <sparkle:hardwareRequirements>arm64</sparkle:hardwareRequirements>
15
+ <description sparkle:format="markdown"><![CDATA[## Bug fixes
16
+
17
+ - Accept M4A, OGG, MP3, and other FFmpeg-supported uploads in the Transformers ASR backend. Transformers and NeMo now share audio preparation, with invalid input reported as HTTP 400. (#644)
18
+ - Normalize stereo, non-16-bit, and non-16 kHz WAV uploads before WAV-only ASR backends read them, preventing incorrect sample interpretation. Standard 16 kHz mono 16-bit WAV uploads pass through unchanged. (#644)
19
+ - Stop FFmpeg conversions when requests are cancelled or conversion times out, then clean up temporary files. Faster-whisper retains native compressed-audio decoding without a system FFmpeg dependency. (#644)
20
+
21
+ **Full changelog:** https://github.com/basnijholt/agent-cli/compare/v0.105.1...v0.105.2
22
+
23
+ ]]></description>
24
+ <enclosure url="https://github.com/basnijholt/agent-cli/releases/download/v0.105.2/AgentCLI.zip" length="18490908" type="application/octet-stream" sparkle:edSignature="DQiGmgOiPGeI4S/4tQdoA7mgsAlgN3qHh2Z4SyLpN70Tv/qr7MjBNM1r+FPn6gYdRYhaaK/XcKfWaX01H8F0Bw=="/>
25
+ </item>
7
26
  <item>
8
27
  <title>0.105.1</title>
9
28
  <pubDate>Tue, 08 Sep 2026 13:10:30 +0000</pubDate>
@@ -193,20 +212,5 @@
193
212
  ]]></description>
194
213
  <enclosure url="https://github.com/basnijholt/agent-cli/releases/download/v0.102.0/AgentCLI.zip" length="24388215" type="application/octet-stream" sparkle:edSignature="1b3tpgDf/VolJ9MLr0R5N9gPmOkYG7Uf6ZyXQTNLPTfiMeo2malwMj5kzTFcCp7xQr/jijUB7/nRNoSzZiBnCg=="/>
195
214
  </item>
196
- <item>
197
- <title>0.101.0</title>
198
- <pubDate>Wed, 10 Jun 2026 18:21:45 +0000</pubDate>
199
- <link>https://github.com/basnijholt/agent-cli</link>
200
- <sparkle:version>196</sparkle:version>
201
- <sparkle:shortVersionString>0.101.0</sparkle:shortVersionString>
202
- <sparkle:minimumSystemVersion>13.0</sparkle:minimumSystemVersion>
203
- <sparkle:hardwareRequirements>arm64</sparkle:hardwareRequirements>
204
- <description sparkle:format="markdown"><![CDATA[## What’s Changed
205
-
206
- * Add zellij multiplexer support to agent-cli dev (#590) @basnijholt
207
-
208
- ]]></description>
209
- <enclosure url="https://github.com/basnijholt/agent-cli/releases/download/v0.101.0/AgentCLI.zip" length="22912290" type="application/octet-stream" sparkle:edSignature="9re7kqubAoQgSpsmDvAT/LCWy8/tI1RzR2uGkb+BCwGJbtfvuzDU2ETm/JD+lpQt3Ayik6ULAOv+/5S6JSmdBA=="/>
210
- </item>
211
215
  </channel>
212
216
  </rss>
@@ -36,6 +36,7 @@ async def test_transcribe_main_llm_enabled(
36
36
  caplog: pytest.LogCaptureFixture,
37
37
  ) -> None:
38
38
  """Test the main function of the transcribe agent with LLM enabled."""
39
+ mock_process_and_update_clipboard.return_value = "Hello world."
39
40
  # Mock audio stream
40
41
  mock_stream = MagicMock()
41
42
  mock_stream.read.return_value = (MagicMock(tobytes=lambda: b"\0" * 1024), False)
@@ -515,6 +516,7 @@ async def test_transcribe_includes_clipboard_context(
515
516
  mock_signal_handling_context: MagicMock,
516
517
  ) -> None:
517
518
  """Ensure clipboard content is forwarded to the LLM context."""
519
+ mock_process_and_update_clipboard.return_value = "Hello world."
518
520
  # Mock audio stream
519
521
  mock_stream = MagicMock()
520
522
  mock_stream.read.return_value = (MagicMock(tobytes=lambda: b"\0" * 1024), False)
@@ -213,3 +213,64 @@ def test_transcribe_stop_json_cleans_stale_pid(
213
213
  assert payload["was_running"] is False
214
214
  assert payload["stale_cleaned"] is True
215
215
  assert not pid_file.exists()
216
+
217
+
218
+ def test_quiet_empty_transcription_fails_without_touching_clipboard() -> None:
219
+ """An empty ASR result must not look like successful dictation to the app."""
220
+ with (
221
+ patch("agent_cli.agents.transcribe.asr.create_transcriber") as create_transcriber,
222
+ patch("agent_cli.agents.transcribe.process.pid_file_context"),
223
+ patch("agent_cli.agents.transcribe.setup_devices", return_value=(0, "mic", None)),
224
+ patch("pyperclip.copy") as copy,
225
+ ):
226
+ create_transcriber.return_value = AsyncMock(return_value=None)
227
+ result = runner.invoke(app, ["transcribe", "--quiet", "--no-llm", "--no-clipboard"])
228
+ assert result.exit_code != 0
229
+ assert "No transcript" in result.output
230
+ copy.assert_not_called()
231
+
232
+
233
+ def test_quiet_whitespace_transcription_preserves_clipboard() -> None:
234
+ """Whitespace from ASR is not dictation and must not erase clipboard text."""
235
+ with (
236
+ patch("agent_cli.agents.transcribe.asr.create_transcriber") as create_transcriber,
237
+ patch("agent_cli.agents.transcribe.process.pid_file_context"),
238
+ patch("agent_cli.agents.transcribe.setup_devices", return_value=(0, "mic", None)),
239
+ patch("pyperclip.copy") as copy,
240
+ ):
241
+ create_transcriber.return_value = AsyncMock(return_value=" \n\t")
242
+ result = runner.invoke(app, ["transcribe", "--quiet", "--no-llm", "--clipboard"])
243
+ assert result.exit_code != 0
244
+ assert "No transcript" in result.output
245
+ copy.assert_not_called()
246
+
247
+
248
+ def test_empty_file_transcription_fails(tmp_path: Path) -> None:
249
+ """Recovery must fail visibly too when a saved recording yields no text."""
250
+ recording = tmp_path / "recording.wav"
251
+ recording.touch()
252
+ with patch("agent_cli.agents.transcribe._async_main", new_callable=AsyncMock) as transcribe:
253
+ transcribe.return_value = {"raw_transcript": None, "transcript": None, "llm_enabled": False}
254
+ result = runner.invoke(app, ["transcribe", "--from-file", str(recording), "--quiet"])
255
+ assert result.exit_code != 0
256
+ assert "No transcript" in result.output
257
+
258
+
259
+ def test_empty_llm_cleanup_retains_raw_transcript() -> None:
260
+ """Failed cleanup must leave recoverable speech, not blank the clipboard."""
261
+ clipboard = ["previous clipboard"]
262
+ agent = MagicMock()
263
+ agent.run = AsyncMock(return_value=MagicMock(output=" \n"))
264
+ with (
265
+ patch("agent_cli.agents.transcribe.asr.create_transcriber") as create_transcriber,
266
+ patch("agent_cli.agents.transcribe.process.pid_file_context"),
267
+ patch("agent_cli.agents.transcribe.setup_devices", return_value=(0, "mic", None)),
268
+ patch("agent_cli.services.llm.create_llm_agent", return_value=agent),
269
+ patch("pyperclip.paste", side_effect=lambda: clipboard[0]),
270
+ patch("pyperclip.copy", side_effect=lambda text: clipboard.__setitem__(0, text)),
271
+ ):
272
+ create_transcriber.return_value = AsyncMock(return_value="recognized speech")
273
+ result = runner.invoke(app, ["transcribe", "--quiet", "--llm", "--clipboard"])
274
+ assert result.exit_code != 0
275
+ assert "LLM" in result.output
276
+ assert clipboard[0] == "recognized speech"
@@ -751,7 +751,11 @@ def test_transcribe_command_last_recording_disabled(
751
751
  patch("agent_cli.agents.transcribe._async_main", new_callable=AsyncMock) as mock_async_main,
752
752
  patch("agent_cli.core.process.pid_file_context") as mock_pid_context,
753
753
  ):
754
- mock_async_main.return_value = {}
754
+ mock_async_main.return_value = {
755
+ "raw_transcript": "hello",
756
+ "transcript": "hello",
757
+ "llm_enabled": False,
758
+ }
755
759
 
756
760
  # Call transcribe with --last-recording disabled (0)
757
761
  transcribe.transcribe(
@@ -1,6 +0,0 @@
1
- import Foundation
2
-
3
- struct CommandResult {
4
- let exitCode: Int32
5
- let output: String
6
- }
File without changes
File without changes
File without changes