agent-cli 0.105.2__tar.gz → 0.107.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 (461) hide show
  1. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/workflows/docker.yml +4 -4
  2. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/workflows/pytest.yml +1 -1
  3. {agent_cli-0.105.2 → agent_cli-0.107.0}/PKG-INFO +1 -1
  4. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/transcribe.py +24 -0
  5. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/AgentCommandRunner.swift +9 -2
  6. agent_cli-0.107.0/macos/AgentCLI/Sources/AgentCLI/CommandResult.swift +17 -0
  7. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/RecordingIndicatorController.swift +2 -1
  8. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/VoiceLevelOverlay.swift +187 -35
  9. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Tests/AgentCLITests/RecordingIndicatorControllerTests.swift +13 -0
  10. agent_cli-0.107.0/macos/AgentCLI/Tests/AgentCLITests/TranscriptionResultTests.swift +23 -0
  11. agent_cli-0.107.0/macos/AgentCLI/Tests/AgentCLITests/VoiceLevelMeterTests.swift +279 -0
  12. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/appcast.xml +46 -48
  13. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_transcribe.py +2 -0
  14. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_transcribe_agent.py +61 -0
  15. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_transcribe_recovery.py +5 -1
  16. agent_cli-0.105.2/macos/AgentCLI/Sources/AgentCLI/CommandResult.swift +0 -6
  17. agent_cli-0.105.2/macos/AgentCLI/Tests/AgentCLITests/VoiceLevelMeterTests.swift +0 -98
  18. {agent_cli-0.105.2 → agent_cli-0.107.0}/.claude/skills/agent-cli-dev/SKILL.md +0 -0
  19. {agent_cli-0.105.2 → agent_cli-0.107.0}/.claude/skills/agent-cli-dev/examples.md +0 -0
  20. {agent_cli-0.105.2 → agent_cli-0.107.0}/.claude-plugin/README.md +0 -0
  21. {agent_cli-0.105.2 → agent_cli-0.107.0}/.claude-plugin/marketplace.json +0 -0
  22. {agent_cli-0.105.2 → agent_cli-0.107.0}/.claude-plugin/plugin.json +0 -0
  23. {agent_cli-0.105.2 → agent_cli-0.107.0}/.claude-plugin/skills/agent-cli-dev/SKILL.md +0 -0
  24. {agent_cli-0.105.2 → agent_cli-0.107.0}/.claude-plugin/skills/agent-cli-dev/examples.md +0 -0
  25. {agent_cli-0.105.2 → agent_cli-0.107.0}/.cursorrules +0 -0
  26. {agent_cli-0.105.2 → agent_cli-0.107.0}/.dockerignore +0 -0
  27. {agent_cli-0.105.2 → agent_cli-0.107.0}/.env.example +0 -0
  28. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/logo.svg +0 -0
  29. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/release-drafter.yml +0 -0
  30. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/renovate.json +0 -0
  31. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/scripts/check_extras_sync.py +0 -0
  32. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/scripts/check_plugin_skill_sync.py +0 -0
  33. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/scripts/normalize_appcast.py +0 -0
  34. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/scripts/sync_extras.py +0 -0
  35. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/scripts/sync_requirements.py +0 -0
  36. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/workflows/automerge.yml +0 -0
  37. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/workflows/docs.yml +0 -0
  38. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/workflows/markdown-code-runner.yml +0 -0
  39. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/workflows/release-drafter.yml +0 -0
  40. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/workflows/release.yml +0 -0
  41. {agent_cli-0.105.2 → agent_cli-0.107.0}/.github/workflows/toc.yaml +0 -0
  42. {agent_cli-0.105.2 → agent_cli-0.107.0}/.gitignore +0 -0
  43. {agent_cli-0.105.2 → agent_cli-0.107.0}/.jscpd.json +0 -0
  44. {agent_cli-0.105.2 → agent_cli-0.107.0}/.pre-commit-config.yaml +0 -0
  45. {agent_cli-0.105.2 → agent_cli-0.107.0}/.prompts/docs-review.md +0 -0
  46. {agent_cli-0.105.2 → agent_cli-0.107.0}/.prompts/pr-review.md +0 -0
  47. {agent_cli-0.105.2 → agent_cli-0.107.0}/CLAUDE.md +0 -0
  48. {agent_cli-0.105.2 → agent_cli-0.107.0}/LICENSE +0 -0
  49. {agent_cli-0.105.2 → agent_cli-0.107.0}/LLAMA_SERVER_USAGE.md +0 -0
  50. {agent_cli-0.105.2 → agent_cli-0.107.0}/README.md +0 -0
  51. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/__init__.py +0 -0
  52. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/__main__.py +0 -0
  53. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_extras.json +0 -0
  54. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_overrides/nemo-whisper.txt +0 -0
  55. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/.gitkeep +0 -0
  56. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/audio.txt +0 -0
  57. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/diarization.txt +0 -0
  58. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/faster-whisper.txt +0 -0
  59. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/kokoro.txt +0 -0
  60. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/llm.txt +0 -0
  61. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/memory.txt +0 -0
  62. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/mlx-whisper.txt +0 -0
  63. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/nemo-whisper.txt +0 -0
  64. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/piper.txt +0 -0
  65. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/rag.txt +0 -0
  66. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/server.txt +0 -0
  67. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/speed.txt +0 -0
  68. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/vad.txt +0 -0
  69. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/vectordb.txt +0 -0
  70. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/whisper-transformers.txt +0 -0
  71. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_requirements/wyoming.txt +0 -0
  72. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/_tools.py +0 -0
  73. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/__init__.py +0 -0
  74. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/_voice_agent_common.py +0 -0
  75. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/assistant.py +0 -0
  76. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/autocorrect.py +0 -0
  77. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/chat.py +0 -0
  78. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/diarize_live_session.py +0 -0
  79. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/memory/__init__.py +0 -0
  80. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/memory/add.py +0 -0
  81. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/memory/proxy.py +0 -0
  82. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/rag_proxy.py +0 -0
  83. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/speak.py +0 -0
  84. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/speakers.py +0 -0
  85. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/transcribe_live.py +0 -0
  86. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/agents/voice_edit.py +0 -0
  87. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/api.py +0 -0
  88. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/cli.py +0 -0
  89. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/config.py +0 -0
  90. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/config_cmd.py +0 -0
  91. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/constants.py +0 -0
  92. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/__init__.py +0 -0
  93. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/alignment.py +0 -0
  94. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/audio.py +0 -0
  95. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/audio_format.py +0 -0
  96. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/chroma.py +0 -0
  97. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/deps.py +0 -0
  98. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/diarization.py +0 -0
  99. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/openai_proxy.py +0 -0
  100. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/process.py +0 -0
  101. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/reranker.py +0 -0
  102. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/speaker_identity.py +0 -0
  103. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/sse.py +0 -0
  104. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/transcription_logger.py +0 -0
  105. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/utils.py +0 -0
  106. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/vad.py +0 -0
  107. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/core/watch.py +0 -0
  108. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/daemon/__init__.py +0 -0
  109. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/daemon/cli.py +0 -0
  110. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/__init__.py +0 -0
  111. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/_branch_name.py +0 -0
  112. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/_config.py +0 -0
  113. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/_output.py +0 -0
  114. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/cleanup.py +0 -0
  115. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/cli.py +0 -0
  116. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/__init__.py +0 -0
  117. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/aider.py +0 -0
  118. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/base.py +0 -0
  119. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/claude.py +0 -0
  120. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/codex.py +0 -0
  121. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/continue_dev.py +0 -0
  122. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/copilot.py +0 -0
  123. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/cursor_agent.py +0 -0
  124. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/gemini.py +0 -0
  125. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/opencode.py +0 -0
  126. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/coding_agents/registry.py +0 -0
  127. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/__init__.py +0 -0
  128. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/base.py +0 -0
  129. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/cursor.py +0 -0
  130. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/emacs.py +0 -0
  131. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/jetbrains.py +0 -0
  132. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/nano.py +0 -0
  133. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/neovim.py +0 -0
  134. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/registry.py +0 -0
  135. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/sublime.py +0 -0
  136. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/vim.py +0 -0
  137. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/vscode.py +0 -0
  138. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/editors/zed.py +0 -0
  139. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/hooks.py +0 -0
  140. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/launch.py +0 -0
  141. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/project.py +0 -0
  142. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/registry.py +0 -0
  143. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/skill/SKILL.md +0 -0
  144. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/skill/examples.md +0 -0
  145. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/__init__.py +0 -0
  146. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/apple_terminal.py +0 -0
  147. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/base.py +0 -0
  148. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/cmux.py +0 -0
  149. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/gnome.py +0 -0
  150. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/iterm2.py +0 -0
  151. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/kitty.py +0 -0
  152. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/registry.py +0 -0
  153. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/tmux.py +0 -0
  154. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/warp.py +0 -0
  155. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/terminals/zellij.py +0 -0
  156. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/dev/worktree.py +0 -0
  157. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/docs_gen.py +0 -0
  158. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/example-config.toml +0 -0
  159. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/install/__init__.py +0 -0
  160. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/install/common.py +0 -0
  161. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/install/extras.py +0 -0
  162. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/install/hotkeys.py +0 -0
  163. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/install/launchd.py +0 -0
  164. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/install/service_config.py +0 -0
  165. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/install/services.py +0 -0
  166. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/install/systemd.py +0 -0
  167. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/__init__.py +0 -0
  168. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_files.py +0 -0
  169. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_filters.py +0 -0
  170. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_git.py +0 -0
  171. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_indexer.py +0 -0
  172. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_ingest.py +0 -0
  173. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_persistence.py +0 -0
  174. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_prompt.py +0 -0
  175. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_retrieval.py +0 -0
  176. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_store.py +0 -0
  177. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_streaming.py +0 -0
  178. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/_tasks.py +0 -0
  179. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/api.py +0 -0
  180. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/client.py +0 -0
  181. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/engine.py +0 -0
  182. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/entities.py +0 -0
  183. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/memory/models.py +0 -0
  184. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/opts.py +0 -0
  185. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/py.typed +0 -0
  186. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/__init__.py +0 -0
  187. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/_indexer.py +0 -0
  188. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/_indexing.py +0 -0
  189. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/_prompt.py +0 -0
  190. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/_retriever.py +0 -0
  191. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/_store.py +0 -0
  192. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/_utils.py +0 -0
  193. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/api.py +0 -0
  194. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/client.py +0 -0
  195. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/engine.py +0 -0
  196. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/rag/models.py +0 -0
  197. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/.runtime/.gitkeep +0 -0
  198. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/__init__.py +0 -0
  199. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/linux-hotkeys/README.md +0 -0
  200. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/linux-hotkeys/toggle-autocorrect.sh +0 -0
  201. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/linux-hotkeys/toggle-transcription.sh +0 -0
  202. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/linux-hotkeys/toggle-voice-edit.sh +0 -0
  203. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/macos-hotkeys/README.md +0 -0
  204. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/macos-hotkeys/skhd-config-example +0 -0
  205. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/macos-hotkeys/toggle-autocorrect.sh +0 -0
  206. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/macos-hotkeys/toggle-transcription.sh +0 -0
  207. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/macos-hotkeys/toggle-voice-edit.sh +0 -0
  208. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/nvidia-asr-server/README.md +0 -0
  209. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/nvidia-asr-server/pyproject.toml +0 -0
  210. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/nvidia-asr-server/server.py +0 -0
  211. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/nvidia-asr-server/shell.nix +0 -0
  212. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/nvidia-asr-server/uv.lock +0 -0
  213. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/run-openwakeword.sh +0 -0
  214. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/setup-linux-hotkeys.sh +0 -0
  215. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/setup-linux.sh +0 -0
  216. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/setup-macos-hotkeys.sh +0 -0
  217. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/setup-macos.sh +0 -0
  218. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/setup-windows.ps1 +0 -0
  219. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/start-all-services-windows.ps1 +0 -0
  220. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/scripts/start-all-services.sh +0 -0
  221. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/__init__.py +0 -0
  222. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/cli.py +0 -0
  223. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/common.py +0 -0
  224. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/model_manager.py +0 -0
  225. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/model_registry.py +0 -0
  226. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/proxy/__init__.py +0 -0
  227. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/proxy/api.py +0 -0
  228. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/proxy/diarization.py +0 -0
  229. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/streaming.py +0 -0
  230. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/tts/__init__.py +0 -0
  231. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/tts/api.py +0 -0
  232. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/tts/backends/__init__.py +0 -0
  233. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/tts/backends/base.py +0 -0
  234. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/tts/backends/kokoro.py +0 -0
  235. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/tts/backends/piper.py +0 -0
  236. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/tts/model_manager.py +0 -0
  237. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/tts/model_registry.py +0 -0
  238. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/tts/wyoming_handler.py +0 -0
  239. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/__init__.py +0 -0
  240. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/api.py +0 -0
  241. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/backends/__init__.py +0 -0
  242. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/backends/audio.py +0 -0
  243. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/backends/base.py +0 -0
  244. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/backends/faster_whisper.py +0 -0
  245. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/backends/mlx.py +0 -0
  246. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/backends/nemo.py +0 -0
  247. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/backends/transformers.py +0 -0
  248. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/languages.py +0 -0
  249. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/model_manager.py +0 -0
  250. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/model_registry.py +0 -0
  251. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/server/whisper/wyoming_handler.py +0 -0
  252. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/services/__init__.py +0 -0
  253. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/services/_wyoming_utils.py +0 -0
  254. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/services/asr.py +0 -0
  255. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/services/llm.py +0 -0
  256. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/services/tts.py +0 -0
  257. {agent_cli-0.105.2 → agent_cli-0.107.0}/agent_cli/services/wake_word.py +0 -0
  258. {agent_cli-0.105.2 → agent_cli-0.107.0}/docker/diarization.Dockerfile +0 -0
  259. {agent_cli-0.105.2 → agent_cli-0.107.0}/docker/docker-compose.yml +0 -0
  260. {agent_cli-0.105.2 → agent_cli-0.107.0}/docker/memory-proxy.Dockerfile +0 -0
  261. {agent_cli-0.105.2 → agent_cli-0.107.0}/docker/rag-proxy.Dockerfile +0 -0
  262. {agent_cli-0.105.2 → agent_cli-0.107.0}/docker/transcribe-proxy.Dockerfile +0 -0
  263. {agent_cli-0.105.2 → agent_cli-0.107.0}/docker/tts.Dockerfile +0 -0
  264. {agent_cli-0.105.2 → agent_cli-0.107.0}/docker/whisper.Dockerfile +0 -0
  265. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/CNAME +0 -0
  266. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/architecture/index.md +0 -0
  267. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/architecture/memory.md +0 -0
  268. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/architecture/rag.md +0 -0
  269. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/assistant.md +0 -0
  270. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/autocorrect.md +0 -0
  271. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/chat.md +0 -0
  272. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/config.md +0 -0
  273. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/daemon.md +0 -0
  274. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/dev.md +0 -0
  275. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/diarize-live-session.md +0 -0
  276. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/index.md +0 -0
  277. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/install-extras.md +0 -0
  278. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/install-hotkeys.md +0 -0
  279. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/install-services.md +0 -0
  280. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/memory.md +0 -0
  281. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/rag-proxy.md +0 -0
  282. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/server/index.md +0 -0
  283. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/server/transcribe-proxy.md +0 -0
  284. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/server/tts.md +0 -0
  285. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/server/whisper.md +0 -0
  286. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/speak.md +0 -0
  287. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/speakers.md +0 -0
  288. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/start-services.md +0 -0
  289. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/transcribe-live.md +0 -0
  290. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/transcribe.md +0 -0
  291. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/commands/voice-edit.md +0 -0
  292. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/configuration.md +0 -0
  293. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/getting-started.md +0 -0
  294. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/iOS_Shortcut_Guide.md +0 -0
  295. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/index.md +0 -0
  296. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/installation/docker.md +0 -0
  297. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/installation/index.md +0 -0
  298. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/installation/linux.md +0 -0
  299. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/installation/macos-app.md +0 -0
  300. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/installation/macos.md +0 -0
  301. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/installation/nixos.md +0 -0
  302. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/installation/windows.md +0 -0
  303. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/logo-avatar.svg +0 -0
  304. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/logo-clean.svg +0 -0
  305. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/overrides/partials/integrations/analytics/custom.html +0 -0
  306. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/run_markdown_code_runner.py +0 -0
  307. {agent_cli-0.105.2 → agent_cli-0.107.0}/docs/system-integration.md +0 -0
  308. {agent_cli-0.105.2 → agent_cli-0.107.0}/example.agent-cli-config.toml +0 -0
  309. {agent_cli-0.105.2 → agent_cli-0.107.0}/justfile +0 -0
  310. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Package.resolved +0 -0
  311. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Package.swift +0 -0
  312. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/README.md +0 -0
  313. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Resources/AgentCLI.entitlements +0 -0
  314. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Resources/Info.plist +0 -0
  315. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Resources/dmg-background.svg +0 -0
  316. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/AgentCLIApp.swift +0 -0
  317. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/AgentCommand.swift +0 -0
  318. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/AgentRuntime.swift +0 -0
  319. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/AppDelegate.swift +0 -0
  320. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/AppMetadata.swift +0 -0
  321. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/AppUpdater.swift +0 -0
  322. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/BootstrapState.swift +0 -0
  323. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/ConfigurableHotkeyController.swift +0 -0
  324. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/FocusedTextTarget.swift +0 -0
  325. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/LiveTranscriptionPreview.swift +0 -0
  326. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/LoginItemController.swift +0 -0
  327. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/MenuActivityStatus.swift +0 -0
  328. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/MenuActivityStatusRow.swift +0 -0
  329. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/MenuActivityTracker.swift +0 -0
  330. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/MenuBarIcon.swift +0 -0
  331. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/RecentTranscriptionReader.swift +0 -0
  332. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/RecordingSoundSettings.swift +0 -0
  333. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/RuntimeSettings.swift +0 -0
  334. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/SettingsWindowController.swift +0 -0
  335. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/Shortcuts.swift +0 -0
  336. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/StatusMenuController.swift +0 -0
  337. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/TranscriptPasteController.swift +0 -0
  338. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Sources/AgentCLI/TranscriptionSettings.swift +0 -0
  339. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Tests/AgentCLITests/AgentCommandTests.swift +0 -0
  340. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Tests/AgentCLITests/ConfigurableHotkeyControllerTests.swift +0 -0
  341. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Tests/AgentCLITests/LivePreviewSwiftTestingTests.swift +0 -0
  342. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Tests/AgentCLITests/LiveTranscriptionPreviewTests.swift +0 -0
  343. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Tests/AgentCLITests/LoginItemControllerTests.swift +0 -0
  344. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Tests/AgentCLITests/RecentTranscriptionReaderTests.swift +0 -0
  345. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/AgentCLI/Tests/AgentCLITests/ShortcutDefaultsTests.swift +0 -0
  346. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/build-macos-app.sh +0 -0
  347. {agent_cli-0.105.2 → agent_cli-0.107.0}/macos/test-macos-app-e2e.sh +0 -0
  348. {agent_cli-0.105.2 → agent_cli-0.107.0}/pyproject.toml +0 -0
  349. {agent_cli-0.105.2 → agent_cli-0.107.0}/reddit.md +0 -0
  350. {agent_cli-0.105.2 → agent_cli-0.107.0}/shell.nix +0 -0
  351. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/__init__.py +0 -0
  352. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/__init__.py +0 -0
  353. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_fix_my_text.py +0 -0
  354. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_interactive.py +0 -0
  355. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_interactive_extra.py +0 -0
  356. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_memory_add.py +0 -0
  357. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_speak.py +0 -0
  358. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_speak_e2e.py +0 -0
  359. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_speakers.py +0 -0
  360. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_transcribe_e2e.py +0 -0
  361. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_transcribe_live.py +0 -0
  362. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_tts_common.py +0 -0
  363. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_tts_common_extra.py +0 -0
  364. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_voice_agent_common.py +0 -0
  365. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_voice_edit.py +0 -0
  366. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_voice_edit_e2e.py +0 -0
  367. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/agents/test_wake_word_assistant.py +0 -0
  368. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/conftest.py +0 -0
  369. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/core/__init__.py +0 -0
  370. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/core/test_audio.py +0 -0
  371. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/core/test_audio_format.py +0 -0
  372. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/core/test_audio_levels.py +0 -0
  373. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/core/test_chroma.py +0 -0
  374. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/core/test_sse.py +0 -0
  375. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/core/test_vad.py +0 -0
  376. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/core/test_watch.py +0 -0
  377. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/__init__.py +0 -0
  378. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/test_cleanup.py +0 -0
  379. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/test_cli.py +0 -0
  380. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/test_coding_agents.py +0 -0
  381. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/test_editors.py +0 -0
  382. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/test_hooks.py +0 -0
  383. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/test_launch.py +0 -0
  384. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/test_project.py +0 -0
  385. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/test_terminals.py +0 -0
  386. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/test_verification.py +0 -0
  387. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/dev/test_worktree.py +0 -0
  388. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/install/__init__.py +0 -0
  389. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/install/test_extras.py +0 -0
  390. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/install/test_launchd.py +0 -0
  391. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/__init__.py +0 -0
  392. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_api_health.py +0 -0
  393. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_api_integration_liveish.py +0 -0
  394. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_client.py +0 -0
  395. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_engine.py +0 -0
  396. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_files.py +0 -0
  397. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_filters.py +0 -0
  398. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_git_integration.py +0 -0
  399. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_indexer.py +0 -0
  400. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_memory_integration.py +0 -0
  401. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_proxy_passthrough.py +0 -0
  402. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_store.py +0 -0
  403. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/memory/test_utils.py +0 -0
  404. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/mocks/__init__.py +0 -0
  405. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/mocks/audio.py +0 -0
  406. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/mocks/llm.py +0 -0
  407. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/mocks/wyoming.py +0 -0
  408. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/__init__.py +0 -0
  409. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_api.py +0 -0
  410. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_engine.py +0 -0
  411. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_history.py +0 -0
  412. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_indexer.py +0 -0
  413. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_indexing.py +0 -0
  414. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_rag_client.py +0 -0
  415. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_rag_integration_liveish.py +0 -0
  416. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_rag_proxy_passthrough.py +0 -0
  417. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_retriever.py +0 -0
  418. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_store.py +0 -0
  419. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/rag/test_utils.py +0 -0
  420. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_alignment.py +0 -0
  421. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_api.py +0 -0
  422. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_api_integration.py +0 -0
  423. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_asr.py +0 -0
  424. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_asr_recovery.py +0 -0
  425. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_audio_e2e.py +0 -0
  426. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_cli.py +0 -0
  427. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_config.py +0 -0
  428. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_config_cmd.py +0 -0
  429. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_daemon.py +0 -0
  430. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_diarization.py +0 -0
  431. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_diarize_live_session.py +0 -0
  432. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_docs_gen.py +0 -0
  433. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_env_vars.py +0 -0
  434. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_faster_whisper_backend.py +0 -0
  435. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_json_output.py +0 -0
  436. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_llm.py +0 -0
  437. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_llm_gemini.py +0 -0
  438. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_macos_app.py +0 -0
  439. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_memory_tools.py +0 -0
  440. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_mlx_backend.py +0 -0
  441. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_nemo_backend.py +0 -0
  442. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_normalize_appcast.py +0 -0
  443. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_process_manager.py +0 -0
  444. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_proxy_diarization.py +0 -0
  445. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_requires_extras.py +0 -0
  446. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_server_streaming.py +0 -0
  447. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_server_tts.py +0 -0
  448. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_server_tts_wyoming.py +0 -0
  449. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_server_whisper.py +0 -0
  450. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_server_whisper_wyoming.py +0 -0
  451. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_services.py +0 -0
  452. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_speaker_identity.py +0 -0
  453. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_tools.py +0 -0
  454. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_transformers_backend.py +0 -0
  455. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_tts.py +0 -0
  456. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_utils.py +0 -0
  457. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_wake_word.py +0 -0
  458. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_whisper_backend_audio.py +0 -0
  459. {agent_cli-0.105.2 → agent_cli-0.107.0}/tests/test_wyoming_utils.py +0 -0
  460. {agent_cli-0.105.2 → agent_cli-0.107.0}/uv.lock +0 -0
  461. {agent_cli-0.105.2 → agent_cli-0.107.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.107.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))
@@ -161,13 +161,13 @@ final class AgentCommandRunner: ObservableObject {
161
161
  holdTranscriptionState = .stopping
162
162
 
163
163
  let wasRecording = recordingIndicator.isRecordingCommand(.toggleTranscription)
164
- beginTranscribingActivity()
165
164
  if wasRecording {
166
165
  endRecordingIndicator(for: .toggleTranscription)
167
166
  statusMessage = "Transcribing..."
168
167
  } else {
169
168
  statusMessage = "Stopping transcription as soon as it starts..."
170
169
  }
170
+ beginTranscribingActivity()
171
171
  stopHeldTranscriptionWhenReady()
172
172
  }
173
173
 
@@ -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)
@@ -381,11 +386,13 @@ final class AgentCommandRunner: ObservableObject {
381
386
 
382
387
  private func beginTranscribingActivity() {
383
388
  activityTracker.beginTranscribing()
389
+ VoiceLevelOverlayController.shared.showTranscribing()
384
390
  }
385
391
 
386
392
  private func clearTranscribingActivityIfFinished() {
387
393
  if pendingStopRecordingCommands.isEmpty && !holdTranscriptionState.isFinishing {
388
394
  activityTracker.finishTranscribing()
395
+ VoiceLevelOverlayController.shared.finishTranscribing()
389
396
  }
390
397
  }
391
398
 
@@ -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
+ }
@@ -38,6 +38,7 @@ final class RecordingIndicatorController {
38
38
  }
39
39
 
40
40
  func end(for command: AgentCommand) {
41
+ guard isRecordingCommand(command) else { return }
41
42
  let wasRecording = isRecording
42
43
  let activeCommandCount = max(0, activeRecordingCommands[command.identifier, default: 0] - 1)
43
44
  if activeCommandCount > 0 {
@@ -48,7 +49,7 @@ final class RecordingIndicatorController {
48
49
  recordingCommandCount = max(0, recordingCommandCount - 1)
49
50
  if wasRecording && !isRecording {
50
51
  play(.finishedRecording)
51
- VoiceLevelOverlayController.shared.hide()
52
+ VoiceLevelOverlayController.shared.endRecording()
52
53
  }
53
54
  if command.supportsLivePreviewOverlay {
54
55
  LiveTranscriptionPreview.shared.stop()
@@ -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,69 @@ 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 == .transcribing
79
+ ? "Transcribing \(meter.transcribingDuration)"
80
+ : meter.captureState.label))
81
+ .accessibilityValue(Text(showsPreviewSpace ? preview.text : ""))
76
82
  }
77
83
 
78
84
  private var levelMeter: some View {
79
- HStack(alignment: .center, spacing: 3.5) {
85
+ HStack(spacing: 8) {
86
+ if meter.captureState == .recording {
87
+ Text(meter.recordingDuration)
88
+ .font(.system(size: 12, weight: .semibold))
89
+ .monospacedDigit()
90
+ .fixedSize()
91
+ waveform
92
+ } else {
93
+ ProgressView()
94
+ .controlSize(.small)
95
+ Text(meter.captureState.label)
96
+ .font(.system(size: 12, weight: .semibold))
97
+ if meter.captureState == .transcribing {
98
+ Text(meter.transcribingDuration)
99
+ .font(.system(size: 12, weight: .semibold))
100
+ .monospacedDigit()
101
+ .fixedSize()
102
+ }
103
+ }
104
+ }
105
+ .foregroundStyle(statusColor)
106
+ .padding(.horizontal, 14)
107
+ .frame(width: VoiceLevelOverlayLayout.pillSize.width, height: VoiceLevelOverlayLayout.pillSize.height)
108
+ .background(Capsule().fill(statusColor.opacity(isLightMode ? 0.10 : 0.14)))
109
+ .background(Capsule().fill(backgroundColor))
110
+ .overlay(Capsule().stroke(statusColor.opacity(0.55), lineWidth: 1))
111
+ .shadow(
112
+ color: shadowColor,
113
+ radius: VoiceLevelOverlayLayout.shadowRadius,
114
+ y: VoiceLevelOverlayLayout.shadowYOffset
115
+ )
116
+ }
117
+
118
+ private var waveform: some View {
119
+ HStack(alignment: .center, spacing: 2) {
80
120
  ForEach(Array(meter.amplitudes.enumerated()), id: \.offset) { _, amplitude in
81
121
  Capsule()
82
122
  .fill(
83
123
  LinearGradient(
84
124
  colors: [
85
- barGradientStart,
86
- barGradientEnd
125
+ statusColor.opacity(0.65),
126
+ statusColor
87
127
  ],
88
128
  startPoint: .bottom,
89
129
  endPoint: .top
90
130
  )
91
131
  )
92
- .frame(width: 3.5, height: max(5, 25 * amplitude))
132
+ .frame(maxWidth: .infinity)
133
+ .frame(height: max(6, 30 * amplitude))
93
134
  .animation(.easeOut(duration: 0.11), value: amplitude)
94
135
  }
95
136
  }
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
- )
137
+ .frame(maxWidth: .infinity)
110
138
  }
111
139
 
112
140
  private var isLightMode: Bool {
@@ -133,12 +161,20 @@ struct VoiceLevelOverlayView: View {
133
161
  Color.black.opacity(isLightMode ? 0.16 : 0.24)
134
162
  }
135
163
 
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)
164
+ private var statusColor: Color {
165
+ if meter.captureState == .transcribing {
166
+ return isLightMode
167
+ ? Color(red: 0.10, green: 0.32, blue: 0.70)
168
+ : Color(red: 0.45, green: 0.72, blue: 1.0)
169
+ }
170
+ if meter.captureState == .recording {
171
+ return isLightMode
172
+ ? Color(red: 0.04, green: 0.40, blue: 0.18)
173
+ : Color(red: 0.42, green: 0.91, blue: 0.58)
174
+ }
175
+ return isLightMode
176
+ ? Color(red: 0.62, green: 0.34, blue: 0.0)
177
+ : Color(red: 1.0, green: 0.74, blue: 0.25)
142
178
  }
143
179
  }
144
180
 
@@ -147,27 +183,63 @@ final class VoiceLevelOverlayController {
147
183
 
148
184
  private var panel: NSPanel?
149
185
  private var showsPreviewSpace = false
186
+ private var recordingShowsPreviewSpace = false
187
+ private var isRecording = false
188
+ private var isTranscribing = false
150
189
 
151
190
  private init() {}
152
191
 
153
192
  func show(showsPreviewSpace: Bool = false) {
193
+ isRecording = true
194
+ recordingShowsPreviewSpace = showsPreviewSpace
154
195
  let panel = panel ?? makePanel()
155
196
  self.panel = panel
156
- if self.showsPreviewSpace != showsPreviewSpace {
157
- self.showsPreviewSpace = showsPreviewSpace
158
- updatePanelContent(panel)
159
- }
160
- panel.setContentSize(VoiceLevelOverlayLayout.panelSize(showsPreviewSpace: showsPreviewSpace))
161
- position(panel)
197
+ setPreviewSpace(showsPreviewSpace, for: panel)
162
198
  VoiceLevelMeter.shared.start()
163
199
  panel.orderFrontRegardless()
164
200
  }
165
201
 
166
202
  func hide() {
203
+ isRecording = false
204
+ isTranscribing = false
167
205
  VoiceLevelMeter.shared.stop()
168
206
  panel?.orderOut(nil)
169
207
  }
170
208
 
209
+ func showTranscribing() {
210
+ isTranscribing = true
211
+ let panel = panel ?? makePanel()
212
+ self.panel = panel
213
+ VoiceLevelMeter.shared.beginTranscribing()
214
+ setPreviewSpace(false, for: panel)
215
+ panel.orderFrontRegardless()
216
+ }
217
+
218
+ func finishTranscribing() {
219
+ guard isTranscribing else { return }
220
+ isTranscribing = false
221
+ if isRecording {
222
+ if let panel {
223
+ setPreviewSpace(recordingShowsPreviewSpace, for: panel)
224
+ }
225
+ VoiceLevelMeter.shared.resumeRecording()
226
+ } else {
227
+ hide()
228
+ }
229
+ }
230
+
231
+ func endRecording() {
232
+ isRecording = false
233
+ if isTranscribing {
234
+ VoiceLevelMeter.shared.beginTranscribing()
235
+ if let panel {
236
+ setPreviewSpace(false, for: panel)
237
+ }
238
+ } else {
239
+ hide()
240
+ }
241
+ }
242
+
171
243
  private func makePanel() -> NSPanel {
172
244
  let panel = NSPanel(
173
245
  contentRect: NSRect(
@@ -189,6 +261,15 @@ final class VoiceLevelOverlayController {
189
261
  return panel
190
262
  }
191
263
 
264
+ private func setPreviewSpace(_ showsPreviewSpace: Bool, for panel: NSPanel) {
265
+ if self.showsPreviewSpace != showsPreviewSpace {
266
+ self.showsPreviewSpace = showsPreviewSpace
267
+ updatePanelContent(panel)
268
+ }
269
+ panel.setContentSize(VoiceLevelOverlayLayout.panelSize(showsPreviewSpace: showsPreviewSpace))
270
+ position(panel)
271
+ }
272
+
192
273
  private func updatePanelContent(_ panel: NSPanel) {
193
274
  panel.contentView = NSHostingView(rootView: VoiceLevelOverlayView(
194
275
  meter: VoiceLevelMeter.shared,
@@ -306,10 +387,31 @@ enum VoiceLevelLog {
306
387
  }()
307
388
  }
308
389
 
390
+ enum VoiceCaptureState {
391
+ case idle
392
+ case connecting
393
+ case recording
394
+ case waitingForAudio
395
+ case transcribing
396
+
397
+ var label: String {
398
+ switch self {
399
+ case .idle: return "Ready"
400
+ case .connecting: return "Connecting…"
401
+ case .recording: return "Recording"
402
+ case .waitingForAudio: return "Waiting for audio…"
403
+ case .transcribing: return "Transcribing…"
404
+ }
405
+ }
406
+ }
407
+
309
408
  final class VoiceLevelMeter: ObservableObject {
310
409
  static let shared = VoiceLevelMeter()
311
410
 
312
411
  @Published private(set) var amplitudes = VoiceLevelMeter.idleAmplitudes
412
+ @Published private(set) var captureState = VoiceCaptureState.idle
413
+ @Published private(set) var recordingDuration = "00:00"
414
+ @Published private(set) var transcribingDuration = "00:00"
313
415
 
314
416
  private static let barCount = 16
315
417
  private static let idleAmplitudes = Array(repeating: CGFloat(0.16), count: barCount)
@@ -319,6 +421,8 @@ final class VoiceLevelMeter: ObservableObject {
319
421
  private let levelLogURL: URL
320
422
  private let now: () -> Date
321
423
  private var timer: Timer?
424
+ private var recordingStartedAt: Date?
425
+ private var transcribingStartedAt: Date?
322
426
  private var phase = 0.0
323
427
  private var smoothedLevel = CGFloat(0.16)
324
428
 
@@ -328,12 +432,21 @@ final class VoiceLevelMeter: ObservableObject {
328
432
  }
329
433
 
330
434
  func start() {
331
- guard timer == nil else { return }
435
+ guard timer == nil || captureState == .transcribing else { return }
332
436
  VoiceLevelLog.reset(levelLogURL)
437
+ captureState = .connecting
438
+ recordingStartedAt = nil
439
+ recordingDuration = "00:00"
440
+ transcribingStartedAt = nil
441
+ transcribingDuration = "00:00"
333
442
  phase = 0
334
443
  smoothedLevel = Self.idleLevel
335
444
  amplitudes = Self.idleAmplitudes
445
+ startPolling()
446
+ }
336
447
 
448
+ private func startPolling() {
449
+ timer?.invalidate()
337
450
  let timer = Timer(timeInterval: Self.pollInterval, repeats: true) { [weak self] _ in
338
451
  self?.pollLevel()
339
452
  }
@@ -342,16 +455,55 @@ final class VoiceLevelMeter: ObservableObject {
342
455
  pollLevel()
343
456
  }
344
457
 
458
+ func resumeRecording() {
459
+ guard captureState == .transcribing else { return }
460
+ transcribingStartedAt = nil
461
+ captureState = recordingStartedAt == nil ? .connecting : .waitingForAudio
462
+ startPolling()
463
+ }
464
+
345
465
  func stop() {
346
466
  timer?.invalidate()
347
467
  timer = nil
468
+ captureState = .idle
469
+ transcribingStartedAt = nil
470
+ transcribingDuration = "00:00"
471
+ recordingStartedAt = nil
472
+ recordingDuration = "00:00"
348
473
  phase = 0
349
474
  smoothedLevel = Self.idleLevel
350
475
  amplitudes = Self.idleAmplitudes
351
476
  }
352
477
 
353
- private func pollLevel() {
354
- let level = VoiceLevelLog.latestLevel(from: levelLogURL, now: now()) ?? Self.idleLevel
478
+ func beginTranscribing() {
479
+ guard captureState != .transcribing else { return }
480
+ transcribingStartedAt = now()
481
+ transcribingDuration = "00:00"
482
+ captureState = .transcribing
483
+ amplitudes = Self.idleAmplitudes
484
+ startPolling()
485
+ }
486
+
487
+ func pollLevel() {
488
+ guard timer != nil else { return }
489
+ let now = now()
490
+ if captureState == .transcribing {
491
+ let elapsed = max(0, Int(now.timeIntervalSince(transcribingStartedAt ?? now)))
492
+ transcribingDuration = String(format: "%02d:%02d", elapsed / 60, elapsed % 60)
493
+ return
494
+ }
495
+ guard let level = VoiceLevelLog.latestLevel(from: levelLogURL, now: now) else {
496
+ if captureState == .recording {
497
+ captureState = .waitingForAudio
498
+ }
499
+ amplitudes = Self.idleAmplitudes
500
+ return
501
+ }
502
+ captureState = .recording
503
+ let startedAt = recordingStartedAt ?? now
504
+ recordingStartedAt = startedAt
505
+ let elapsedSeconds = max(0, Int(now.timeIntervalSince(startedAt)))
506
+ recordingDuration = String(format: "%02d:%02d", elapsedSeconds / 60, elapsedSeconds % 60)
355
507
  updateDisplay(level: level)
356
508
  }
357
509
 
@@ -4,6 +4,19 @@ import XCTest
4
4
  @testable import AgentCLI
5
5
 
6
6
  final class RecordingIndicatorControllerTests: XCTestCase {
7
+ func testRepeatedEndDoesNotStopAnotherRecording() {
8
+ let defaults = UserDefaults(suiteName: "AgentCLITests.recording-repeated-end")!
9
+ defaults.removePersistentDomain(forName: "AgentCLITests.recording-repeated-end")
10
+ let controller = RecordingIndicatorController(defaults: defaults, audioCuePlayer: RecordingCuePlayerSpy())
11
+ defer { controller.end(for: .voiceEdit) }
12
+ controller.begin(for: .toggleTranscription)
13
+ controller.begin(for: .voiceEdit)
14
+ controller.end(for: .toggleTranscription)
15
+ controller.end(for: .toggleTranscription)
16
+ XCTAssertTrue(controller.isRecording)
17
+ XCTAssertTrue(controller.isRecordingCommand(.voiceEdit))
18
+ }
19
+
7
20
  func testRecordingSoundsAreDisabledByDefault() {
8
21
  let defaults = UserDefaults(suiteName: "AgentCLITests.recording-sounds-default")!
9
22
  defaults.removePersistentDomain(forName: "AgentCLITests.recording-sounds-default")
@@ -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