agent-cli 0.96.2__tar.gz → 0.96.4__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 (446) hide show
  1. {agent_cli-0.96.2 → agent_cli-0.96.4}/Casks/agent-cli.rb +2 -2
  2. {agent_cli-0.96.2 → agent_cli-0.96.4}/PKG-INFO +1 -1
  3. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/AgentCommand.swift +4 -0
  4. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/AgentCommandRunner.swift +54 -26
  5. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/AgentRuntime.swift +23 -1
  6. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/BootstrapState.swift +6 -7
  7. agent_cli-0.96.4/macos/AgentCLI/Sources/AgentCLI/MenuActivityStatus.swift +29 -0
  8. agent_cli-0.96.4/macos/AgentCLI/Sources/AgentCLI/MenuActivityStatusRow.swift +26 -0
  9. agent_cli-0.96.4/macos/AgentCLI/Sources/AgentCLI/MenuActivityTracker.swift +64 -0
  10. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/StatusMenuController.swift +24 -1
  11. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/VoiceLevelOverlay.swift +41 -18
  12. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Tests/AgentCLITests/AgentCommandTests.swift +119 -0
  13. agent_cli-0.96.4/macos/AgentCLI/Tests/AgentCLITests/VoiceLevelMeterTests.swift +39 -0
  14. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/appcast.xml +31 -0
  15. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_macos_app.py +3 -0
  16. agent_cli-0.96.2/macos/AgentCLI/Sources/AgentCLI/VoiceSpectrumAnalyzer.swift +0 -144
  17. agent_cli-0.96.2/macos/AgentCLI/Tests/AgentCLITests/VoiceSpectrumAnalyzerTests.swift +0 -61
  18. {agent_cli-0.96.2 → agent_cli-0.96.4}/.claude/skills/agent-cli-dev/SKILL.md +0 -0
  19. {agent_cli-0.96.2 → agent_cli-0.96.4}/.claude/skills/agent-cli-dev/examples.md +0 -0
  20. {agent_cli-0.96.2 → agent_cli-0.96.4}/.claude-plugin/README.md +0 -0
  21. {agent_cli-0.96.2 → agent_cli-0.96.4}/.claude-plugin/marketplace.json +0 -0
  22. {agent_cli-0.96.2 → agent_cli-0.96.4}/.claude-plugin/plugin.json +0 -0
  23. {agent_cli-0.96.2 → agent_cli-0.96.4}/.claude-plugin/skills/agent-cli-dev/SKILL.md +0 -0
  24. {agent_cli-0.96.2 → agent_cli-0.96.4}/.claude-plugin/skills/agent-cli-dev/examples.md +0 -0
  25. {agent_cli-0.96.2 → agent_cli-0.96.4}/.cursorrules +0 -0
  26. {agent_cli-0.96.2 → agent_cli-0.96.4}/.dockerignore +0 -0
  27. {agent_cli-0.96.2 → agent_cli-0.96.4}/.env.example +0 -0
  28. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/logo.svg +0 -0
  29. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/release-drafter.yml +0 -0
  30. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/renovate.json +0 -0
  31. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/scripts/check_extras_sync.py +0 -0
  32. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/scripts/check_plugin_skill_sync.py +0 -0
  33. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/scripts/normalize_appcast.py +0 -0
  34. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/scripts/sync_extras.py +0 -0
  35. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/scripts/sync_requirements.py +0 -0
  36. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/scripts/update_cask.py +0 -0
  37. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/workflows/automerge.yml +0 -0
  38. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/workflows/docker.yml +0 -0
  39. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/workflows/docs.yml +0 -0
  40. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/workflows/markdown-code-runner.yml +0 -0
  41. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/workflows/pytest.yml +0 -0
  42. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/workflows/release-drafter.yml +0 -0
  43. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/workflows/release.yml +0 -0
  44. {agent_cli-0.96.2 → agent_cli-0.96.4}/.github/workflows/toc.yaml +0 -0
  45. {agent_cli-0.96.2 → agent_cli-0.96.4}/.gitignore +0 -0
  46. {agent_cli-0.96.2 → agent_cli-0.96.4}/.jscpd.json +0 -0
  47. {agent_cli-0.96.2 → agent_cli-0.96.4}/.pre-commit-config.yaml +0 -0
  48. {agent_cli-0.96.2 → agent_cli-0.96.4}/.prompts/docs-review.md +0 -0
  49. {agent_cli-0.96.2 → agent_cli-0.96.4}/.prompts/pr-review.md +0 -0
  50. {agent_cli-0.96.2 → agent_cli-0.96.4}/CLAUDE.md +0 -0
  51. {agent_cli-0.96.2 → agent_cli-0.96.4}/LICENSE +0 -0
  52. {agent_cli-0.96.2 → agent_cli-0.96.4}/LLAMA_SERVER_USAGE.md +0 -0
  53. {agent_cli-0.96.2 → agent_cli-0.96.4}/README.md +0 -0
  54. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/__init__.py +0 -0
  55. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/__main__.py +0 -0
  56. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_extras.json +0 -0
  57. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/.gitkeep +0 -0
  58. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/audio.txt +0 -0
  59. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/diarization.txt +0 -0
  60. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/faster-whisper.txt +0 -0
  61. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/kokoro.txt +0 -0
  62. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/llm.txt +0 -0
  63. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/memory.txt +0 -0
  64. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/mlx-whisper.txt +0 -0
  65. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/piper.txt +0 -0
  66. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/rag.txt +0 -0
  67. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/server.txt +0 -0
  68. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/speed.txt +0 -0
  69. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/vad.txt +0 -0
  70. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/vectordb.txt +0 -0
  71. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/whisper-transformers.txt +0 -0
  72. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_requirements/wyoming.txt +0 -0
  73. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/_tools.py +0 -0
  74. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/__init__.py +0 -0
  75. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/_voice_agent_common.py +0 -0
  76. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/assistant.py +0 -0
  77. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/autocorrect.py +0 -0
  78. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/chat.py +0 -0
  79. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/diarize_live_session.py +0 -0
  80. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/memory/__init__.py +0 -0
  81. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/memory/add.py +0 -0
  82. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/memory/proxy.py +0 -0
  83. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/rag_proxy.py +0 -0
  84. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/speak.py +0 -0
  85. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/speakers.py +0 -0
  86. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/transcribe.py +0 -0
  87. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/transcribe_live.py +0 -0
  88. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/agents/voice_edit.py +0 -0
  89. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/api.py +0 -0
  90. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/cli.py +0 -0
  91. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/config.py +0 -0
  92. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/config_cmd.py +0 -0
  93. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/constants.py +0 -0
  94. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/__init__.py +0 -0
  95. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/alignment.py +0 -0
  96. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/audio.py +0 -0
  97. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/audio_format.py +0 -0
  98. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/chroma.py +0 -0
  99. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/deps.py +0 -0
  100. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/diarization.py +0 -0
  101. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/openai_proxy.py +0 -0
  102. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/process.py +0 -0
  103. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/reranker.py +0 -0
  104. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/speaker_identity.py +0 -0
  105. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/sse.py +0 -0
  106. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/transcription_logger.py +0 -0
  107. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/utils.py +0 -0
  108. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/vad.py +0 -0
  109. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/core/watch.py +0 -0
  110. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/daemon/__init__.py +0 -0
  111. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/daemon/cli.py +0 -0
  112. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/__init__.py +0 -0
  113. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/_branch_name.py +0 -0
  114. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/_config.py +0 -0
  115. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/_output.py +0 -0
  116. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/cleanup.py +0 -0
  117. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/cli.py +0 -0
  118. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/__init__.py +0 -0
  119. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/aider.py +0 -0
  120. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/base.py +0 -0
  121. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/claude.py +0 -0
  122. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/codex.py +0 -0
  123. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/continue_dev.py +0 -0
  124. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/copilot.py +0 -0
  125. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/cursor_agent.py +0 -0
  126. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/gemini.py +0 -0
  127. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/opencode.py +0 -0
  128. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/coding_agents/registry.py +0 -0
  129. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/__init__.py +0 -0
  130. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/base.py +0 -0
  131. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/cursor.py +0 -0
  132. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/emacs.py +0 -0
  133. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/jetbrains.py +0 -0
  134. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/nano.py +0 -0
  135. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/neovim.py +0 -0
  136. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/registry.py +0 -0
  137. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/sublime.py +0 -0
  138. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/vim.py +0 -0
  139. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/vscode.py +0 -0
  140. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/editors/zed.py +0 -0
  141. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/hooks.py +0 -0
  142. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/launch.py +0 -0
  143. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/project.py +0 -0
  144. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/registry.py +0 -0
  145. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/skill/SKILL.md +0 -0
  146. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/skill/examples.md +0 -0
  147. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/terminals/__init__.py +0 -0
  148. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/terminals/apple_terminal.py +0 -0
  149. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/terminals/base.py +0 -0
  150. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/terminals/gnome.py +0 -0
  151. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/terminals/iterm2.py +0 -0
  152. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/terminals/kitty.py +0 -0
  153. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/terminals/registry.py +0 -0
  154. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/terminals/tmux.py +0 -0
  155. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/terminals/warp.py +0 -0
  156. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/terminals/zellij.py +0 -0
  157. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/dev/worktree.py +0 -0
  158. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/docs_gen.py +0 -0
  159. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/example-config.toml +0 -0
  160. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/install/__init__.py +0 -0
  161. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/install/common.py +0 -0
  162. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/install/extras.py +0 -0
  163. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/install/hotkeys.py +0 -0
  164. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/install/launchd.py +0 -0
  165. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/install/service_config.py +0 -0
  166. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/install/services.py +0 -0
  167. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/install/systemd.py +0 -0
  168. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/__init__.py +0 -0
  169. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_files.py +0 -0
  170. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_filters.py +0 -0
  171. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_git.py +0 -0
  172. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_indexer.py +0 -0
  173. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_ingest.py +0 -0
  174. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_persistence.py +0 -0
  175. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_prompt.py +0 -0
  176. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_retrieval.py +0 -0
  177. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_store.py +0 -0
  178. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_streaming.py +0 -0
  179. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/_tasks.py +0 -0
  180. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/api.py +0 -0
  181. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/client.py +0 -0
  182. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/engine.py +0 -0
  183. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/entities.py +0 -0
  184. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/memory/models.py +0 -0
  185. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/opts.py +0 -0
  186. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/py.typed +0 -0
  187. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/__init__.py +0 -0
  188. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/_indexer.py +0 -0
  189. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/_indexing.py +0 -0
  190. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/_prompt.py +0 -0
  191. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/_retriever.py +0 -0
  192. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/_store.py +0 -0
  193. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/_utils.py +0 -0
  194. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/api.py +0 -0
  195. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/client.py +0 -0
  196. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/engine.py +0 -0
  197. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/rag/models.py +0 -0
  198. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/.runtime/.gitkeep +0 -0
  199. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/__init__.py +0 -0
  200. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/linux-hotkeys/README.md +0 -0
  201. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/linux-hotkeys/toggle-autocorrect.sh +0 -0
  202. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/linux-hotkeys/toggle-transcription.sh +0 -0
  203. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/linux-hotkeys/toggle-voice-edit.sh +0 -0
  204. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/macos-hotkeys/README.md +0 -0
  205. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/macos-hotkeys/skhd-config-example +0 -0
  206. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/macos-hotkeys/toggle-autocorrect.sh +0 -0
  207. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/macos-hotkeys/toggle-transcription.sh +0 -0
  208. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/macos-hotkeys/toggle-voice-edit.sh +0 -0
  209. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/nvidia-asr-server/README.md +0 -0
  210. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/nvidia-asr-server/pyproject.toml +0 -0
  211. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/nvidia-asr-server/server.py +0 -0
  212. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/nvidia-asr-server/shell.nix +0 -0
  213. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/nvidia-asr-server/uv.lock +0 -0
  214. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/run-openwakeword.sh +0 -0
  215. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/setup-linux-hotkeys.sh +0 -0
  216. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/setup-linux.sh +0 -0
  217. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/setup-macos-hotkeys.sh +0 -0
  218. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/setup-macos.sh +0 -0
  219. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/setup-windows.ps1 +0 -0
  220. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/start-all-services-windows.ps1 +0 -0
  221. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/scripts/start-all-services.sh +0 -0
  222. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/__init__.py +0 -0
  223. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/cli.py +0 -0
  224. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/common.py +0 -0
  225. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/model_manager.py +0 -0
  226. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/model_registry.py +0 -0
  227. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/proxy/__init__.py +0 -0
  228. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/proxy/api.py +0 -0
  229. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/streaming.py +0 -0
  230. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/tts/__init__.py +0 -0
  231. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/tts/api.py +0 -0
  232. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/tts/backends/__init__.py +0 -0
  233. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/tts/backends/base.py +0 -0
  234. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/tts/backends/kokoro.py +0 -0
  235. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/tts/backends/piper.py +0 -0
  236. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/tts/model_manager.py +0 -0
  237. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/tts/model_registry.py +0 -0
  238. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/tts/wyoming_handler.py +0 -0
  239. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/__init__.py +0 -0
  240. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/api.py +0 -0
  241. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/backends/__init__.py +0 -0
  242. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/backends/base.py +0 -0
  243. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/backends/faster_whisper.py +0 -0
  244. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/backends/mlx.py +0 -0
  245. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/backends/transformers.py +0 -0
  246. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/languages.py +0 -0
  247. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/model_manager.py +0 -0
  248. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/model_registry.py +0 -0
  249. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/server/whisper/wyoming_handler.py +0 -0
  250. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/services/__init__.py +0 -0
  251. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/services/_wyoming_utils.py +0 -0
  252. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/services/asr.py +0 -0
  253. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/services/llm.py +0 -0
  254. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/services/tts.py +0 -0
  255. {agent_cli-0.96.2 → agent_cli-0.96.4}/agent_cli/services/wake_word.py +0 -0
  256. {agent_cli-0.96.2 → agent_cli-0.96.4}/docker/docker-compose.yml +0 -0
  257. {agent_cli-0.96.2 → agent_cli-0.96.4}/docker/memory-proxy.Dockerfile +0 -0
  258. {agent_cli-0.96.2 → agent_cli-0.96.4}/docker/rag-proxy.Dockerfile +0 -0
  259. {agent_cli-0.96.2 → agent_cli-0.96.4}/docker/transcribe-proxy.Dockerfile +0 -0
  260. {agent_cli-0.96.2 → agent_cli-0.96.4}/docker/tts.Dockerfile +0 -0
  261. {agent_cli-0.96.2 → agent_cli-0.96.4}/docker/whisper.Dockerfile +0 -0
  262. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/CNAME +0 -0
  263. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/architecture/index.md +0 -0
  264. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/architecture/memory.md +0 -0
  265. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/architecture/rag.md +0 -0
  266. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/assistant.md +0 -0
  267. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/autocorrect.md +0 -0
  268. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/chat.md +0 -0
  269. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/config.md +0 -0
  270. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/daemon.md +0 -0
  271. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/dev.md +0 -0
  272. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/diarize-live-session.md +0 -0
  273. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/index.md +0 -0
  274. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/install-extras.md +0 -0
  275. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/install-hotkeys.md +0 -0
  276. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/install-services.md +0 -0
  277. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/memory.md +0 -0
  278. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/rag-proxy.md +0 -0
  279. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/server/index.md +0 -0
  280. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/server/transcribe-proxy.md +0 -0
  281. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/server/tts.md +0 -0
  282. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/server/whisper.md +0 -0
  283. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/speak.md +0 -0
  284. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/speakers.md +0 -0
  285. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/start-services.md +0 -0
  286. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/transcribe-live.md +0 -0
  287. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/transcribe.md +0 -0
  288. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/commands/voice-edit.md +0 -0
  289. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/configuration.md +0 -0
  290. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/getting-started.md +0 -0
  291. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/iOS_Shortcut_Guide.md +0 -0
  292. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/index.md +0 -0
  293. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/installation/docker.md +0 -0
  294. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/installation/index.md +0 -0
  295. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/installation/linux.md +0 -0
  296. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/installation/macos-app.md +0 -0
  297. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/installation/macos.md +0 -0
  298. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/installation/nixos.md +0 -0
  299. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/installation/windows.md +0 -0
  300. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/logo-avatar.svg +0 -0
  301. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/logo-clean.svg +0 -0
  302. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/overrides/partials/integrations/analytics/custom.html +0 -0
  303. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/run_markdown_code_runner.py +0 -0
  304. {agent_cli-0.96.2 → agent_cli-0.96.4}/docs/system-integration.md +0 -0
  305. {agent_cli-0.96.2 → agent_cli-0.96.4}/example.agent-cli-config.toml +0 -0
  306. {agent_cli-0.96.2 → agent_cli-0.96.4}/justfile +0 -0
  307. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Package.resolved +0 -0
  308. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Package.swift +0 -0
  309. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/README.md +0 -0
  310. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Resources/AgentCLI.entitlements +0 -0
  311. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Resources/Info.plist +0 -0
  312. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Resources/dmg-background.svg +0 -0
  313. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/AgentCLIApp.swift +0 -0
  314. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/AppDelegate.swift +0 -0
  315. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/AppMetadata.swift +0 -0
  316. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/AppUpdater.swift +0 -0
  317. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/CommandResult.swift +0 -0
  318. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/ConfigurableHotkeyController.swift +0 -0
  319. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/FocusedTextTarget.swift +0 -0
  320. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/LoginItemController.swift +0 -0
  321. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/MenuBarIcon.swift +0 -0
  322. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/RecentTranscriptionReader.swift +0 -0
  323. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/RecordingIndicatorController.swift +0 -0
  324. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/RecordingSoundSettings.swift +0 -0
  325. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/RuntimeSettings.swift +0 -0
  326. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/SettingsWindowController.swift +0 -0
  327. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/Shortcuts.swift +0 -0
  328. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/TranscriptPasteController.swift +0 -0
  329. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Sources/AgentCLI/TranscriptionSettings.swift +0 -0
  330. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Tests/AgentCLITests/LoginItemControllerTests.swift +0 -0
  331. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Tests/AgentCLITests/RecentTranscriptionReaderTests.swift +0 -0
  332. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Tests/AgentCLITests/RecordingIndicatorControllerTests.swift +0 -0
  333. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/AgentCLI/Tests/AgentCLITests/ShortcutDefaultsTests.swift +0 -0
  334. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/build-macos-app.sh +0 -0
  335. {agent_cli-0.96.2 → agent_cli-0.96.4}/macos/test-macos-app-e2e.sh +0 -0
  336. {agent_cli-0.96.2 → agent_cli-0.96.4}/pyproject.toml +0 -0
  337. {agent_cli-0.96.2 → agent_cli-0.96.4}/reddit.md +0 -0
  338. {agent_cli-0.96.2 → agent_cli-0.96.4}/shell.nix +0 -0
  339. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/__init__.py +0 -0
  340. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/__init__.py +0 -0
  341. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_fix_my_text.py +0 -0
  342. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_interactive.py +0 -0
  343. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_interactive_extra.py +0 -0
  344. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_memory_add.py +0 -0
  345. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_speak.py +0 -0
  346. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_speak_e2e.py +0 -0
  347. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_speakers.py +0 -0
  348. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_transcribe.py +0 -0
  349. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_transcribe_agent.py +0 -0
  350. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_transcribe_e2e.py +0 -0
  351. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_transcribe_live.py +0 -0
  352. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_transcribe_recovery.py +0 -0
  353. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_tts_common.py +0 -0
  354. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_tts_common_extra.py +0 -0
  355. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_voice_agent_common.py +0 -0
  356. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_voice_edit.py +0 -0
  357. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_voice_edit_e2e.py +0 -0
  358. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/agents/test_wake_word_assistant.py +0 -0
  359. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/conftest.py +0 -0
  360. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/core/__init__.py +0 -0
  361. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/core/test_audio.py +0 -0
  362. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/core/test_audio_format.py +0 -0
  363. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/core/test_chroma.py +0 -0
  364. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/core/test_sse.py +0 -0
  365. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/core/test_vad.py +0 -0
  366. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/core/test_watch.py +0 -0
  367. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/__init__.py +0 -0
  368. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/test_cleanup.py +0 -0
  369. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/test_cli.py +0 -0
  370. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/test_coding_agents.py +0 -0
  371. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/test_editors.py +0 -0
  372. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/test_hooks.py +0 -0
  373. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/test_launch.py +0 -0
  374. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/test_project.py +0 -0
  375. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/test_terminals.py +0 -0
  376. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/test_verification.py +0 -0
  377. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/dev/test_worktree.py +0 -0
  378. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/install/__init__.py +0 -0
  379. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/install/test_extras.py +0 -0
  380. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/install/test_launchd.py +0 -0
  381. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/__init__.py +0 -0
  382. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_api_health.py +0 -0
  383. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_api_integration_liveish.py +0 -0
  384. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_client.py +0 -0
  385. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_engine.py +0 -0
  386. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_files.py +0 -0
  387. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_filters.py +0 -0
  388. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_git_integration.py +0 -0
  389. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_indexer.py +0 -0
  390. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_memory_integration.py +0 -0
  391. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_proxy_passthrough.py +0 -0
  392. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_store.py +0 -0
  393. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/memory/test_utils.py +0 -0
  394. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/mocks/__init__.py +0 -0
  395. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/mocks/audio.py +0 -0
  396. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/mocks/llm.py +0 -0
  397. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/mocks/wyoming.py +0 -0
  398. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/__init__.py +0 -0
  399. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_api.py +0 -0
  400. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_engine.py +0 -0
  401. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_history.py +0 -0
  402. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_indexer.py +0 -0
  403. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_indexing.py +0 -0
  404. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_rag_client.py +0 -0
  405. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_rag_integration_liveish.py +0 -0
  406. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_rag_proxy_passthrough.py +0 -0
  407. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_retriever.py +0 -0
  408. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_store.py +0 -0
  409. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/rag/test_utils.py +0 -0
  410. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_alignment.py +0 -0
  411. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_api.py +0 -0
  412. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_api_integration.py +0 -0
  413. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_asr.py +0 -0
  414. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_asr_recovery.py +0 -0
  415. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_audio_e2e.py +0 -0
  416. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_cli.py +0 -0
  417. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_config.py +0 -0
  418. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_config_cmd.py +0 -0
  419. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_daemon.py +0 -0
  420. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_diarization.py +0 -0
  421. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_diarize_live_session.py +0 -0
  422. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_docs_gen.py +0 -0
  423. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_env_vars.py +0 -0
  424. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_faster_whisper_backend.py +0 -0
  425. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_json_output.py +0 -0
  426. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_llm.py +0 -0
  427. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_llm_gemini.py +0 -0
  428. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_memory_tools.py +0 -0
  429. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_mlx_backend.py +0 -0
  430. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_normalize_appcast.py +0 -0
  431. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_process_manager.py +0 -0
  432. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_requires_extras.py +0 -0
  433. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_server_streaming.py +0 -0
  434. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_server_tts.py +0 -0
  435. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_server_whisper.py +0 -0
  436. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_services.py +0 -0
  437. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_speaker_identity.py +0 -0
  438. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_tools.py +0 -0
  439. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_transformers_backend.py +0 -0
  440. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_tts.py +0 -0
  441. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_update_cask.py +0 -0
  442. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_utils.py +0 -0
  443. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_wake_word.py +0 -0
  444. {agent_cli-0.96.2 → agent_cli-0.96.4}/tests/test_wyoming_utils.py +0 -0
  445. {agent_cli-0.96.2 → agent_cli-0.96.4}/uv.lock +0 -0
  446. {agent_cli-0.96.2 → agent_cli-0.96.4}/zensical.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  cask "agent-cli" do
2
- version "0.96.1"
3
- sha256 "eef32008aa3d60a114eac824bc32c12385de07c7656bae5edcde24487fc3d72d"
2
+ version "0.96.3"
3
+ sha256 "6346b0f335005094152ceb987b5e7d44fb08d817a07ca3433a05fba3fa85ec2f"
4
4
 
5
5
  url "https://github.com/basnijholt/agent-cli/releases/download/v#{version}/AgentCLI.dmg"
6
6
  name "Agent CLI"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-cli
3
- Version: 0.96.2
3
+ Version: 0.96.4
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>
@@ -55,6 +55,10 @@ struct AgentCommand {
55
55
  return arguments + ["--extra-instructions", trimmedInstructions]
56
56
  }
57
57
 
58
+ var menuActivityTitle: String {
59
+ title
60
+ }
61
+
58
62
  static let toggleTranscription = AgentCommand(
59
63
  identifier: "transcribe",
60
64
  title: "Toggle Transcription",
@@ -31,7 +31,7 @@ final class AgentCommandRunner: ObservableObject {
31
31
  private var recordingIndicator = RecordingIndicatorController()
32
32
  private let pasteController: TranscriptPasteController
33
33
  private let bootstrap: AgentBootstrap
34
- private var bootstrapPhaseStartedAt: Date?
34
+ private var activityTracker = MenuActivityTracker()
35
35
  private var pendingStopRecordingCommands: Set<String> = []
36
36
  private var holdTranscriptionState: HoldTranscriptionState = .idle
37
37
  private var holdToTranscribePasteTarget: FocusedTextTarget?
@@ -43,22 +43,24 @@ final class AgentCommandRunner: ObservableObject {
43
43
  }
44
44
 
45
45
  var menuStatusMessage: String {
46
- if isRecording {
47
- return "Recording"
48
- }
49
- if bootstrapPhase.isPreparing {
50
- return bootstrapPhase.statusMessage(
51
- animationTick: bootstrapAnimationTick(now: Date()),
52
- elapsedSeconds: bootstrapElapsedSeconds(now: Date())
53
- )
54
- }
55
- if holdTranscriptionState.isFinishing {
56
- return "Transcribing..."
57
- }
46
+ menuActivityStatus.message
47
+ }
48
+
49
+ var menuActivityStatus: MenuActivityStatus {
50
+ menuActivityStatus(now: Date())
51
+ }
52
+
53
+ func menuActivityStatus(now: Date) -> MenuActivityStatus {
58
54
  if hasLastError && statusMessage.localizedCaseInsensitiveContains("failed") {
59
- return "Last command failed"
55
+ return activityTracker.status(
56
+ now: now,
57
+ fallback: MenuActivityStatus.inactive(message: "Last command failed")
58
+ )
60
59
  }
61
- return Self.compactMenuStatus(statusMessage)
60
+ return activityTracker.status(
61
+ now: now,
62
+ fallback: MenuActivityStatus.completed(title: Self.compactMenuStatus(statusMessage))
63
+ )
62
64
  }
63
65
 
64
66
  var menuBarIconState: MenuBarIconState {
@@ -125,10 +127,10 @@ final class AgentCommandRunner: ObservableObject {
125
127
  bootstrapPhase = phase
126
128
  if phase.isPreparing {
127
129
  if !wasPreparing || phaseChanged {
128
- bootstrapPhaseStartedAt = Date()
130
+ activityTracker.beginBootstrap(title: phase.activityTitle)
129
131
  }
130
132
  } else {
131
- bootstrapPhaseStartedAt = nil
133
+ activityTracker.finishBootstrap()
132
134
  }
133
135
  }
134
136
 
@@ -140,15 +142,6 @@ final class AgentCommandRunner: ObservableObject {
140
142
  }
141
143
  }
142
144
 
143
- private func bootstrapAnimationTick(now: Date) -> Int {
144
- bootstrapElapsedSeconds(now: now) % 4
145
- }
146
-
147
- private func bootstrapElapsedSeconds(now: Date) -> Int {
148
- guard let startedAt = bootstrapPhaseStartedAt else { return 0 }
149
- return max(0, Int(now.timeIntervalSince(startedAt)))
150
- }
151
-
152
145
  @discardableResult
153
146
  func beginHoldToTranscribe() -> Bool {
154
147
  guard holdTranscriptionState == .idle else {
@@ -174,6 +167,7 @@ final class AgentCommandRunner: ObservableObject {
174
167
  holdTranscriptionState = .stopping
175
168
 
176
169
  let wasRecording = recordingIndicator.isRecordingCommand(.toggleTranscription)
170
+ beginTranscribingActivity()
177
171
  if wasRecording {
178
172
  endRecordingIndicator(for: .toggleTranscription)
179
173
  statusMessage = "Transcribing..."
@@ -206,9 +200,11 @@ final class AgentCommandRunner: ObservableObject {
206
200
 
207
201
  if isStopRequest {
208
202
  markStopRequested(for: command)
203
+ beginTranscribingActivity()
209
204
  }
210
205
 
211
206
  activeCommandCount += 1
207
+ beginCommandActivity(for: command)
212
208
  if !self.bootstrapPhase.isPreparing {
213
209
  statusMessage = isStopRequest
214
210
  ? "Stopping \(command.title)..."
@@ -233,6 +229,8 @@ final class AgentCommandRunner: ObservableObject {
233
229
  self.clearPasteAfterRecording(for: command)
234
230
  }
235
231
  self.clearHoldTranscriptionState(for: command)
232
+ self.clearTranscribingActivityIfFinished()
233
+ self.finishCommandActivity(for: command)
236
234
  self.activeCommandCount = max(0, self.activeCommandCount - 1)
237
235
  self.lastOutput = bootstrapResult.output
238
236
  self.recordFailure(command: command, result: bootstrapResult)
@@ -272,7 +270,9 @@ final class AgentCommandRunner: ObservableObject {
272
270
  }
273
271
  }
274
272
  self.clearPasteAfterRecording(for: command)
273
+ self.clearTranscribingActivityIfFinished()
275
274
  }
275
+ self.finishCommandActivity(for: command)
276
276
  self.activeCommandCount = max(0, self.activeCommandCount - 1)
277
277
 
278
278
  if isStopRequest && result.exitCode == 0 {
@@ -285,6 +285,7 @@ final class AgentCommandRunner: ObservableObject {
285
285
 
286
286
  if isStopRequest {
287
287
  self.clearStopRequested(for: command)
288
+ self.clearTranscribingActivityIfFinished()
288
289
  }
289
290
  self.lastOutput = result.output
290
291
  if result.exitCode != 0 {
@@ -319,6 +320,7 @@ final class AgentCommandRunner: ObservableObject {
319
320
  Task { @MainActor in
320
321
  self.reportBootstrapPhase(.failed)
321
322
  self.holdTranscriptionState = .idle
323
+ self.clearTranscribingActivityIfFinished()
322
324
  self.lastOutput = bootstrapResult.output
323
325
  self.recordFailure(command: AgentCommand.stopTranscription, result: bootstrapResult)
324
326
  self.statusMessage = message
@@ -345,6 +347,7 @@ final class AgentCommandRunner: ObservableObject {
345
347
  }
346
348
 
347
349
  self.holdTranscriptionState = .idle
350
+ self.clearTranscribingActivityIfFinished()
348
351
  let message = result.output.isEmpty
349
352
  ? "Toggle Transcription stop failed with exit code \(result.exitCode)"
350
353
  : "Toggle Transcription stop failed: \(result.output)"
@@ -368,6 +371,24 @@ final class AgentCommandRunner: ObservableObject {
368
371
  pendingStopRecordingCommands.remove(command.identifier)
369
372
  }
370
373
 
374
+ private func beginCommandActivity(for command: AgentCommand) {
375
+ activityTracker.beginCommand(identifier: command.identifier, title: command.menuActivityTitle)
376
+ }
377
+
378
+ private func finishCommandActivity(for command: AgentCommand) {
379
+ activityTracker.finishCommand(identifier: command.identifier)
380
+ }
381
+
382
+ private func beginTranscribingActivity() {
383
+ activityTracker.beginTranscribing()
384
+ }
385
+
386
+ private func clearTranscribingActivityIfFinished() {
387
+ if pendingStopRecordingCommands.isEmpty && !holdTranscriptionState.isFinishing {
388
+ activityTracker.finishTranscribing()
389
+ }
390
+ }
391
+
371
392
  private func shouldPasteAfterRecording(for command: AgentCommand) -> Bool {
372
393
  pasteAfterRecordingCommands.contains(command.identifier)
373
394
  }
@@ -390,14 +411,21 @@ final class AgentCommandRunner: ObservableObject {
390
411
  return false
391
412
  }
392
413
 
414
+ let wasRecording = isRecording
393
415
  recordingIndicator.begin(for: command)
394
416
  isRecording = recordingIndicator.isRecording
417
+ if !wasRecording && isRecording {
418
+ activityTracker.beginRecording()
419
+ }
395
420
  return true
396
421
  }
397
422
 
398
423
  private func endRecordingIndicator(for command: AgentCommand) {
399
424
  recordingIndicator.end(for: command)
400
425
  isRecording = recordingIndicator.isRecording
426
+ if !isRecording {
427
+ activityTracker.finishRecording()
428
+ }
401
429
  }
402
430
 
403
431
  func copyLastOutput() {
@@ -12,6 +12,21 @@ private enum AgentCLIRuntimeMode: Equatable {
12
12
  }
13
13
  }
14
14
 
15
+ private final class UserInstalledCLICheckCache {
16
+ private let lock = NSLock()
17
+ private var isAvailable = false
18
+
19
+ func hasSuccessfulCheck() -> Bool {
20
+ lock.withLock { isAvailable }
21
+ }
22
+
23
+ func update(with result: CommandResult) {
24
+ lock.withLock {
25
+ isAvailable = result.exitCode == 0
26
+ }
27
+ }
28
+ }
29
+
15
30
  typealias AgentProcessRunner = (URL, [String], [String: String]) -> CommandResult
16
31
  typealias LocalhostConnector = (UInt16) -> Bool
17
32
 
@@ -42,6 +57,7 @@ struct AgentRuntime {
42
57
  private let userDefaults: UserDefaults
43
58
  private let processRunner: AgentProcessRunner
44
59
  private let localhostConnector: LocalhostConnector
60
+ private let userInstalledCLICheckCache: UserInstalledCLICheckCache
45
61
  private let whisperReadyTimeout: TimeInterval
46
62
  let appSupportURL: URL
47
63
  let bundledUVURL: URL
@@ -73,6 +89,7 @@ struct AgentRuntime {
73
89
  self.userDefaults = userDefaults
74
90
  self.processRunner = processRunner
75
91
  self.localhostConnector = localhostConnector
92
+ self.userInstalledCLICheckCache = UserInstalledCLICheckCache()
76
93
  self.whisperReadyTimeout = whisperReadyTimeout
77
94
 
78
95
  if let override = environment["AGENTCLI_APP_SUPPORT_DIR"], !override.isEmpty {
@@ -196,8 +213,13 @@ struct AgentRuntime {
196
213
  }
197
214
 
198
215
  if mode == .userInstalled {
216
+ if !force, userInstalledCLICheckCache.hasSuccessfulCheck() {
217
+ return CommandResult(exitCode: 0, output: "")
218
+ }
199
219
  progress(.checkingRuntime)
200
- return ensureUserInstalledCLIAvailable()
220
+ let result = ensureUserInstalledCLIAvailable()
221
+ userInstalledCLICheckCache.update(with: result)
222
+ return result
201
223
  }
202
224
 
203
225
  if !force,
@@ -46,18 +46,17 @@ enum BootstrapPhase: Equatable {
46
46
  func statusMessage(animationTick: Int, elapsedSeconds: Int) -> String {
47
47
  switch self {
48
48
  case .checkingRuntime, .installingRuntime, .installingVoiceService, .waitingForVoiceService, .warmingWhisperModel:
49
- let spinnerFrames = ["◐", "◓", "◑", "◒"]
50
- let spinner = spinnerFrames[animationTick % spinnerFrames.count]
51
- let minutes = elapsedSeconds / 60
52
- let seconds = elapsedSeconds % 60
53
- let elapsedTime = String(format: "%02d:%02d", minutes, seconds)
54
- return "\(animatedStatusMessage) \(spinner) (\(elapsedTime))"
49
+ return MenuActivityStatus.active(
50
+ title: activityTitle,
51
+ animationTick: animationTick,
52
+ elapsedSeconds: elapsedSeconds
53
+ ).message
55
54
  case .idle, .failed:
56
55
  return statusMessage
57
56
  }
58
57
  }
59
58
 
60
- private var animatedStatusMessage: String {
59
+ var activityTitle: String {
61
60
  switch self {
62
61
  case .checkingRuntime:
63
62
  return "Checking CLI runtime"
@@ -0,0 +1,29 @@
1
+ import Foundation
2
+
3
+ struct MenuActivityStatus: Equatable {
4
+ let message: String
5
+ let isActive: Bool
6
+
7
+ static func active(title: String, startedAt: Date, now: Date) -> MenuActivityStatus {
8
+ let elapsedSeconds = max(0, Int(now.timeIntervalSince(startedAt)))
9
+ return active(title: title, animationTick: elapsedSeconds % spinnerFrames.count, elapsedSeconds: elapsedSeconds)
10
+ }
11
+
12
+ static func active(title: String, animationTick: Int, elapsedSeconds: Int) -> MenuActivityStatus {
13
+ let spinner = spinnerFrames[animationTick % spinnerFrames.count]
14
+ let minutes = elapsedSeconds / 60
15
+ let seconds = elapsedSeconds % 60
16
+ let elapsedTime = String(format: "%02d:%02d", minutes, seconds)
17
+ return MenuActivityStatus(message: "\(title) \(spinner) (\(elapsedTime))", isActive: true)
18
+ }
19
+
20
+ static func completed(title: String) -> MenuActivityStatus {
21
+ MenuActivityStatus(message: "\(title) ✓", isActive: false)
22
+ }
23
+
24
+ static func inactive(message: String) -> MenuActivityStatus {
25
+ MenuActivityStatus(message: message, isActive: false)
26
+ }
27
+
28
+ private static let spinnerFrames = ["◐", "◓", "◑", "◒"]
29
+ }
@@ -0,0 +1,26 @@
1
+ import AppKit
2
+
3
+ @MainActor
4
+ final class MenuActivityStatusRow {
5
+ private let prefix: String
6
+ private let item: NSMenuItem
7
+ private let separator: NSMenuItem
8
+
9
+ init(prefix: String) {
10
+ self.prefix = prefix
11
+ item = NSMenuItem(title: "", action: nil, keyEquivalent: "")
12
+ item.isEnabled = false
13
+ separator = .separator()
14
+ }
15
+
16
+ func add(to menu: NSMenu) {
17
+ menu.addItem(item)
18
+ menu.addItem(separator)
19
+ }
20
+
21
+ func update(_ activityStatus: MenuActivityStatus) {
22
+ item.title = "\(prefix)\(activityStatus.message)"
23
+ item.isHidden = !activityStatus.isActive
24
+ separator.isHidden = !activityStatus.isActive
25
+ }
26
+ }
@@ -0,0 +1,64 @@
1
+ import Foundation
2
+
3
+ struct MenuActivityTracker {
4
+ private struct Activity {
5
+ let title: String
6
+ let startedAt: Date
7
+ }
8
+
9
+ private var bootstrapActivity: Activity?
10
+ private var recordingActivity: Activity?
11
+ private var transcribingActivity: Activity?
12
+ private var commandActivities: [String: Activity] = [:]
13
+ private var commandActivityOrder: [String] = []
14
+
15
+ mutating func beginBootstrap(title: String, at startedAt: Date = Date()) {
16
+ bootstrapActivity = Activity(title: title, startedAt: startedAt)
17
+ }
18
+
19
+ mutating func finishBootstrap() {
20
+ bootstrapActivity = nil
21
+ }
22
+
23
+ mutating func beginRecording(at startedAt: Date = Date()) {
24
+ guard recordingActivity == nil else { return }
25
+ recordingActivity = Activity(title: "Recording", startedAt: startedAt)
26
+ }
27
+
28
+ mutating func finishRecording() {
29
+ recordingActivity = nil
30
+ }
31
+
32
+ mutating func beginTranscribing(at startedAt: Date = Date()) {
33
+ guard transcribingActivity == nil else { return }
34
+ transcribingActivity = Activity(title: "Transcribing", startedAt: startedAt)
35
+ }
36
+
37
+ mutating func finishTranscribing() {
38
+ transcribingActivity = nil
39
+ }
40
+
41
+ mutating func beginCommand(identifier: String, title: String, at startedAt: Date = Date()) {
42
+ if commandActivities[identifier] == nil {
43
+ commandActivityOrder.append(identifier)
44
+ }
45
+ commandActivities[identifier] = Activity(title: title, startedAt: startedAt)
46
+ }
47
+
48
+ mutating func finishCommand(identifier: String) {
49
+ commandActivities.removeValue(forKey: identifier)
50
+ commandActivityOrder.removeAll { $0 == identifier }
51
+ }
52
+
53
+ func status(now: Date = Date(), fallback: MenuActivityStatus) -> MenuActivityStatus {
54
+ guard let activity = currentActivity else { return fallback }
55
+ return MenuActivityStatus.active(title: activity.title, startedAt: activity.startedAt, now: now)
56
+ }
57
+
58
+ private var currentActivity: Activity? {
59
+ bootstrapActivity
60
+ ?? transcribingActivity
61
+ ?? recordingActivity
62
+ ?? commandActivityOrder.reversed().compactMap { commandActivities[$0] }.first
63
+ }
64
+ }
@@ -8,6 +8,7 @@ final class StatusMenuController: NSObject, NSMenuDelegate {
8
8
  private static let statusRefreshInterval: TimeInterval = 0.8
9
9
  private static let statusRefreshRunLoopModes: [RunLoop.Mode] = [.common, .eventTracking]
10
10
  private static let voiceStatusTitlePrefix = "Voice: "
11
+ private static let activityStatusTitlePrefix = "Status: "
11
12
 
12
13
  private let runner = AgentCommandRunner.shared
13
14
  private let appUpdater = AppUpdater.shared
@@ -19,6 +20,8 @@ final class StatusMenuController: NSObject, NSMenuDelegate {
19
20
  private let recentRecordingsMenu = NSMenu()
20
21
  private let troubleshootingMenu = NSMenu()
21
22
  private var voiceStatusItem: NSMenuItem?
23
+ private var recentActivityStatusRow: MenuActivityStatusRow?
24
+ private var troubleshootingActivityStatusRow: MenuActivityStatusRow?
22
25
  private var statusRefreshTimer: Timer?
23
26
 
24
27
  private override init() {
@@ -108,9 +111,12 @@ final class StatusMenuController: NSObject, NSMenuDelegate {
108
111
 
109
112
  private func rebuildRecentRecordingsMenu() {
110
113
  recentRecordingsMenu.removeAllItems()
114
+ recentActivityStatusRow = activityStatusRow(in: recentRecordingsMenu)
115
+
111
116
  let recentTranscriptions = RecentTranscriptionReader.recentTranscriptions()
112
117
  if recentTranscriptions.isEmpty {
113
118
  recentRecordingsMenu.addItem(disabledItem("No recent transcriptions"))
119
+ refreshDynamicStatus()
114
120
  return
115
121
  }
116
122
 
@@ -123,10 +129,13 @@ final class StatusMenuController: NSObject, NSMenuDelegate {
123
129
  item.representedObject = transcription.text
124
130
  recentRecordingsMenu.addItem(item)
125
131
  }
132
+ refreshDynamicStatus()
126
133
  }
127
134
 
128
135
  private func rebuildTroubleshootingMenu() {
129
136
  troubleshootingMenu.removeAllItems()
137
+ troubleshootingActivityStatusRow = activityStatusRow(in: troubleshootingMenu)
138
+
130
139
  troubleshootingMenu.addItem(actionItem(
131
140
  "Voice Service Status",
132
141
  symbolName: "waveform.path.ecg",
@@ -191,6 +200,7 @@ final class StatusMenuController: NSObject, NSMenuDelegate {
191
200
  symbolName: "arrow.counterclockwise",
192
201
  action: #selector(resetKeyboardShortcuts)
193
202
  ))
203
+ refreshDynamicStatus()
194
204
  }
195
205
 
196
206
  private func startStatusRefreshTimer() {
@@ -207,7 +217,9 @@ final class StatusMenuController: NSObject, NSMenuDelegate {
207
217
  }
208
218
 
209
219
  private func refreshDynamicStatus() {
210
- voiceStatusItem?.title = "\(Self.voiceStatusTitlePrefix)\(runner.menuStatusMessage)"
220
+ let activityStatus = runner.menuActivityStatus
221
+ voiceStatusItem?.title = "\(Self.voiceStatusTitlePrefix)\(activityStatus.message)"
222
+ updateSubmenuActivityStatus(activityStatus)
211
223
  if let button = statusItem?.button {
212
224
  button.image = MenuBarIconImage.logoImage(state: runner.menuBarIconState)
213
225
  button.imagePosition = .imageOnly
@@ -215,6 +227,17 @@ final class StatusMenuController: NSObject, NSMenuDelegate {
215
227
  }
216
228
  }
217
229
 
230
+ private func updateSubmenuActivityStatus(_ activityStatus: MenuActivityStatus) {
231
+ recentActivityStatusRow?.update(activityStatus)
232
+ troubleshootingActivityStatusRow?.update(activityStatus)
233
+ }
234
+
235
+ private func activityStatusRow(in menu: NSMenu) -> MenuActivityStatusRow {
236
+ let row = MenuActivityStatusRow(prefix: Self.activityStatusTitlePrefix)
237
+ row.add(to: menu)
238
+ return row
239
+ }
240
+
218
241
  private var usesUserInstalledAgentCLI: Bool {
219
242
  UserDefaults.standard.bool(forKey: RuntimeSettings.useUserInstalledAgentCLIKey)
220
243
  }
@@ -94,9 +94,10 @@ final class VoiceLevelMeter: NSObject, ObservableObject {
94
94
  private static let barCount = 16
95
95
  private static let idleAmplitudes = Array(repeating: CGFloat(0.16), count: barCount)
96
96
  private static let minimumDisplayAmplitude = CGFloat(0.12)
97
+ private static let minimumInputDecibels: Float = -55
97
98
  private var engine: AVAudioEngine?
98
- private var analyzer: VoiceSpectrumAnalyzer?
99
- private var smoothedAmplitudes = VoiceLevelMeter.idleAmplitudes
99
+ private var phase = 0.0
100
+ private var smoothedLevel = CGFloat(0.16)
100
101
 
101
102
  private override init() {}
102
103
 
@@ -125,13 +126,14 @@ final class VoiceLevelMeter: NSObject, ObservableObject {
125
126
  engine?.inputNode.removeTap(onBus: 0)
126
127
  engine?.stop()
127
128
  engine = nil
128
- analyzer = nil
129
- smoothedAmplitudes = Self.idleAmplitudes
129
+ phase = 0
130
+ smoothedLevel = 0.16
130
131
  amplitudes = Self.idleAmplitudes
131
132
  }
132
133
 
133
134
  private func startMetering() {
134
- smoothedAmplitudes = Self.idleAmplitudes
135
+ phase = 0
136
+ smoothedLevel = 0.16
135
137
  let engine = AVAudioEngine()
136
138
  let input = engine.inputNode
137
139
  let format = input.outputFormat(forBus: 0)
@@ -139,17 +141,12 @@ final class VoiceLevelMeter: NSObject, ObservableObject {
139
141
  amplitudes = Self.idleAmplitudes
140
142
  return
141
143
  }
142
- let analyzer = VoiceSpectrumAnalyzer(
143
- sampleRate: format.sampleRate,
144
- bandCount: Self.barCount
145
- )
146
144
 
147
145
  do {
148
146
  input.installTap(onBus: 0, bufferSize: 1_024, format: format) { [weak self] buffer, _ in
149
147
  self?.process(buffer: buffer)
150
148
  }
151
149
  try engine.start()
152
- self.analyzer = analyzer
153
150
  self.engine = engine
154
151
  } catch {
155
152
  input.removeTap(onBus: 0)
@@ -158,21 +155,47 @@ final class VoiceLevelMeter: NSObject, ObservableObject {
158
155
  }
159
156
 
160
157
  private func process(buffer: AVAudioPCMBuffer) {
161
- guard let analyzer, let samples = Self.samples(from: buffer) else { return }
162
- let rawAmplitudes = analyzer.amplitudes(from: samples)
158
+ guard let samples = Self.samples(from: buffer) else { return }
159
+ let level = Self.normalizedLevel(from: samples)
163
160
 
164
161
  DispatchQueue.main.async { [weak self] in
165
162
  guard let self, self.engine != nil else { return }
166
- self.amplitudes = self.smoothedDisplayAmplitudes(from: rawAmplitudes)
163
+ self.updateDisplay(level: level)
167
164
  }
168
165
  }
169
166
 
170
- private func smoothedDisplayAmplitudes(from rawAmplitudes: [CGFloat]) -> [CGFloat] {
171
- smoothedAmplitudes = zip(smoothedAmplitudes, rawAmplitudes).map { previous, current in
172
- let smoothed = (previous * 0.62) + (current * 0.38)
173
- return max(Self.minimumDisplayAmplitude, min(1, smoothed))
167
+ private func updateDisplay(level: CGFloat) {
168
+ phase += 0.22
169
+ smoothedLevel = (smoothedLevel * 0.55) + (level * 0.45)
170
+ let displayLevel = smoothedLevel
171
+
172
+ amplitudes = Self.displayAmplitudes(level: displayLevel, phase: phase)
173
+ }
174
+
175
+ static func displayAmplitudes(level: CGFloat, phase: Double) -> [CGFloat] {
176
+ (0..<Self.barCount).map { index in
177
+ let wave = 0.74 + 0.26 * sin(phase + Double(index) * 0.74)
178
+ return max(Self.minimumDisplayAmplitude, min(1, level * CGFloat(wave)))
174
179
  }
175
- return smoothedAmplitudes
180
+ }
181
+
182
+ static func normalizedLevel(from samples: [Float]) -> CGFloat {
183
+ guard !samples.isEmpty else { return 0.08 }
184
+
185
+ let meanSquare = samples.reduce(0.0) { partialResult, sample in
186
+ let value = Double(sample)
187
+ return partialResult + (value * value)
188
+ } / Double(samples.count)
189
+ guard meanSquare > 0 else { return 0.08 }
190
+
191
+ let rootMeanSquare = sqrt(meanSquare)
192
+ let decibels = Float(20 * log10(rootMeanSquare))
193
+ return normalizedPower(decibels, minimumPower: minimumInputDecibels)
194
+ }
195
+
196
+ private static func normalizedPower(_ power: Float, minimumPower: Float) -> CGFloat {
197
+ guard power > minimumPower else { return 0.08 }
198
+ return CGFloat((power - minimumPower) / abs(minimumPower))
176
199
  }
177
200
 
178
201
  private static func samples(from buffer: AVAudioPCMBuffer) -> [Float]? {