dictare 0.1.140rc1__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 (371) hide show
  1. dictare-0.1.140rc1/.dockerignore +22 -0
  2. dictare-0.1.140rc1/.github/ISSUE_TEMPLATE/bug_report.md +57 -0
  3. dictare-0.1.140rc1/.github/ISSUE_TEMPLATE/feature_request.md +29 -0
  4. dictare-0.1.140rc1/.github/PULL_REQUEST_TEMPLATE.md +29 -0
  5. dictare-0.1.140rc1/.github/workflows/build-launcher.yml +197 -0
  6. dictare-0.1.140rc1/.github/workflows/ci-macos.yml +25 -0
  7. dictare-0.1.140rc1/.github/workflows/ci.yml +48 -0
  8. dictare-0.1.140rc1/.github/workflows/claude-dedupe-issues.yml +45 -0
  9. dictare-0.1.140rc1/.github/workflows/claude-issue-triage.yml +49 -0
  10. dictare-0.1.140rc1/.github/workflows/claude-pr-review.yml +57 -0
  11. dictare-0.1.140rc1/.github/workflows/claude.yml +35 -0
  12. dictare-0.1.140rc1/.github/workflows/lock-closed-issues.yml +53 -0
  13. dictare-0.1.140rc1/.github/workflows/publish-pypi.yml +29 -0
  14. dictare-0.1.140rc1/.github/workflows/sweep.yml +29 -0
  15. dictare-0.1.140rc1/.gitignore +113 -0
  16. dictare-0.1.140rc1/.gitlab-ci.yml +61 -0
  17. dictare-0.1.140rc1/.python-version +1 -0
  18. dictare-0.1.140rc1/ARCHITECTURE.md +71 -0
  19. dictare-0.1.140rc1/CHANGELOG.md +1320 -0
  20. dictare-0.1.140rc1/CLAUDE.md +58 -0
  21. dictare-0.1.140rc1/CODE_OF_CONDUCT.md +38 -0
  22. dictare-0.1.140rc1/CONTRIBUTING.md +141 -0
  23. dictare-0.1.140rc1/LICENSE +21 -0
  24. dictare-0.1.140rc1/PKG-INFO +289 -0
  25. dictare-0.1.140rc1/README.md +225 -0
  26. dictare-0.1.140rc1/SECURITY.md +55 -0
  27. dictare-0.1.140rc1/TERMINAL_COMPATIBILITY.md +173 -0
  28. dictare-0.1.140rc1/assets/icon.svg +9 -0
  29. dictare-0.1.140rc1/install.sh +196 -0
  30. dictare-0.1.140rc1/openapitools.json +7 -0
  31. dictare-0.1.140rc1/packaging/deb/build-deb.sh +71 -0
  32. dictare-0.1.140rc1/packaging/deb/debian/control +10 -0
  33. dictare-0.1.140rc1/packaging/deb/debian/postinst +37 -0
  34. dictare-0.1.140rc1/packaging/deb/debian/postrm +15 -0
  35. dictare-0.1.140rc1/packaging/deb/debian/prerm +14 -0
  36. dictare-0.1.140rc1/packaging/homebrew/dictare.rb +41 -0
  37. dictare-0.1.140rc1/pyproject.toml +128 -0
  38. dictare-0.1.140rc1/remove-permissions.sh +31 -0
  39. dictare-0.1.140rc1/scripts/dev/full-install.sh +26 -0
  40. dictare-0.1.140rc1/scripts/dev/local-build-check.sh +32 -0
  41. dictare-0.1.140rc1/scripts/dev/publish.sh +203 -0
  42. dictare-0.1.140rc1/scripts/install.sh +32 -0
  43. dictare-0.1.140rc1/scripts/linux/install.sh +297 -0
  44. dictare-0.1.140rc1/scripts/linux/test-distros/Dockerfile.arch +45 -0
  45. dictare-0.1.140rc1/scripts/linux/test-distros/Dockerfile.debian +43 -0
  46. dictare-0.1.140rc1/scripts/linux/test-distros/Dockerfile.fedora +43 -0
  47. dictare-0.1.140rc1/scripts/linux/test-distros/Dockerfile.ubuntu +45 -0
  48. dictare-0.1.140rc1/scripts/linux/test-distros/README.md +33 -0
  49. dictare-0.1.140rc1/scripts/linux/test-distros/run.sh +154 -0
  50. dictare-0.1.140rc1/scripts/linux/test-distros/tests/e2e.sh +115 -0
  51. dictare-0.1.140rc1/scripts/linux/test-distros/tests/engine.sh +93 -0
  52. dictare-0.1.140rc1/scripts/linux/test-distros/tests/smoke.sh +30 -0
  53. dictare-0.1.140rc1/scripts/linux/test-distros/tests/tray.sh +48 -0
  54. dictare-0.1.140rc1/scripts/linux/uninstall.sh +138 -0
  55. dictare-0.1.140rc1/scripts/macos/install.sh +214 -0
  56. dictare-0.1.140rc1/scripts/macos/sign-launcher.sh +45 -0
  57. dictare-0.1.140rc1/scripts/macos/uninstall.sh +181 -0
  58. dictare-0.1.140rc1/scripts/test.sh +17 -0
  59. dictare-0.1.140rc1/scripts/uninstall.sh +12 -0
  60. dictare-0.1.140rc1/setup-permissions.sh +21 -0
  61. dictare-0.1.140rc1/spec/README.md +46 -0
  62. dictare-0.1.140rc1/src/dictare/__init__.py +8 -0
  63. dictare-0.1.140rc1/src/dictare/__main__.py +6 -0
  64. dictare-0.1.140rc1/src/dictare/agent/__init__.py +5 -0
  65. dictare-0.1.140rc1/src/dictare/agent/base.py +78 -0
  66. dictare-0.1.140rc1/src/dictare/agent/injection/__init__.py +1 -0
  67. dictare-0.1.140rc1/src/dictare/agent/injection/base.py +114 -0
  68. dictare-0.1.140rc1/src/dictare/agent/injection/quartz.py +254 -0
  69. dictare-0.1.140rc1/src/dictare/agent/injection/ydotool.py +260 -0
  70. dictare-0.1.140rc1/src/dictare/agent/keyboard.py +199 -0
  71. dictare-0.1.140rc1/src/dictare/agent/mux.py +846 -0
  72. dictare-0.1.140rc1/src/dictare/agent/pty_session.py +194 -0
  73. dictare-0.1.140rc1/src/dictare/agent/sse.py +35 -0
  74. dictare-0.1.140rc1/src/dictare/agent/status_bar.py +207 -0
  75. dictare-0.1.140rc1/src/dictare/app/__init__.py +12 -0
  76. dictare-0.1.140rc1/src/dictare/app/bindings.py +156 -0
  77. dictare-0.1.140rc1/src/dictare/app/controller.py +699 -0
  78. dictare-0.1.140rc1/src/dictare/audio/__init__.py +1 -0
  79. dictare-0.1.140rc1/src/dictare/audio/beep.py +556 -0
  80. dictare-0.1.140rc1/src/dictare/audio/capture.py +323 -0
  81. dictare-0.1.140rc1/src/dictare/audio/device_monitor.py +328 -0
  82. dictare-0.1.140rc1/src/dictare/audio/feedback_policy.py +117 -0
  83. dictare-0.1.140rc1/src/dictare/audio/sounds/carriage-return.wav +0 -0
  84. dictare-0.1.140rc1/src/dictare/audio/sounds/down-beep.wav +0 -0
  85. dictare-0.1.140rc1/src/dictare/audio/sounds/pencil-write-1.wav +0 -0
  86. dictare-0.1.140rc1/src/dictare/audio/sounds/pencil-write-2.wav +0 -0
  87. dictare-0.1.140rc1/src/dictare/audio/sounds/pencil-write-3.wav +0 -0
  88. dictare-0.1.140rc1/src/dictare/audio/sounds/pencil-write-4.wav +0 -0
  89. dictare-0.1.140rc1/src/dictare/audio/sounds/pencil-write-5.wav +0 -0
  90. dictare-0.1.140rc1/src/dictare/audio/sounds/pencil-write.wav +0 -0
  91. dictare-0.1.140rc1/src/dictare/audio/sounds/transcribing.wav +0 -0
  92. dictare-0.1.140rc1/src/dictare/audio/sounds/typewriter-burst.wav +0 -0
  93. dictare-0.1.140rc1/src/dictare/audio/sounds/typewriter.wav +0 -0
  94. dictare-0.1.140rc1/src/dictare/audio/sounds/up-beep.wav +0 -0
  95. dictare-0.1.140rc1/src/dictare/audio/vad.py +394 -0
  96. dictare-0.1.140rc1/src/dictare/cli/__init__.py +142 -0
  97. dictare-0.1.140rc1/src/dictare/cli/_helpers.py +19 -0
  98. dictare-0.1.140rc1/src/dictare/cli/agent.py +225 -0
  99. dictare-0.1.140rc1/src/dictare/cli/config.py +157 -0
  100. dictare-0.1.140rc1/src/dictare/cli/dependencies.py +182 -0
  101. dictare-0.1.140rc1/src/dictare/cli/logs.py +212 -0
  102. dictare-0.1.140rc1/src/dictare/cli/misc.py +60 -0
  103. dictare-0.1.140rc1/src/dictare/cli/models.py +368 -0
  104. dictare-0.1.140rc1/src/dictare/cli/panel.py +434 -0
  105. dictare-0.1.140rc1/src/dictare/cli/serve.py +223 -0
  106. dictare-0.1.140rc1/src/dictare/cli/service.py +211 -0
  107. dictare-0.1.140rc1/src/dictare/cli/setup.py +91 -0
  108. dictare-0.1.140rc1/src/dictare/cli/shortcuts.py +228 -0
  109. dictare-0.1.140rc1/src/dictare/cli/speak.py +293 -0
  110. dictare-0.1.140rc1/src/dictare/cli/status.py +242 -0
  111. dictare-0.1.140rc1/src/dictare/cli/tray.py +105 -0
  112. dictare-0.1.140rc1/src/dictare/config.py +1126 -0
  113. dictare-0.1.140rc1/src/dictare/core/__init__.py +21 -0
  114. dictare-0.1.140rc1/src/dictare/core/agent_manager.py +358 -0
  115. dictare-0.1.140rc1/src/dictare/core/audio_manager.py +646 -0
  116. dictare-0.1.140rc1/src/dictare/core/bus.py +137 -0
  117. dictare-0.1.140rc1/src/dictare/core/controller.py +436 -0
  118. dictare-0.1.140rc1/src/dictare/core/engine.py +1727 -0
  119. dictare-0.1.140rc1/src/dictare/core/events.py +45 -0
  120. dictare-0.1.140rc1/src/dictare/core/fsm.py +299 -0
  121. dictare-0.1.140rc1/src/dictare/core/http_server.py +1553 -0
  122. dictare-0.1.140rc1/src/dictare/core/openvip_messages.py +65 -0
  123. dictare-0.1.140rc1/src/dictare/core/openvip_validator.py +45 -0
  124. dictare-0.1.140rc1/src/dictare/core/toml_sections.py +531 -0
  125. dictare-0.1.140rc1/src/dictare/core/transcriber.py +157 -0
  126. dictare-0.1.140rc1/src/dictare/core/tts_manager.py +592 -0
  127. dictare-0.1.140rc1/src/dictare/credits.json +12 -0
  128. dictare-0.1.140rc1/src/dictare/cuda_setup.py +179 -0
  129. dictare-0.1.140rc1/src/dictare/daemon/__init__.py +1 -0
  130. dictare-0.1.140rc1/src/dictare/daemon/app_bundle.py +274 -0
  131. dictare-0.1.140rc1/src/dictare/daemon/launchd.py +369 -0
  132. dictare-0.1.140rc1/src/dictare/daemon/systemd.py +100 -0
  133. dictare-0.1.140rc1/src/dictare/hotkey/__init__.py +5 -0
  134. dictare-0.1.140rc1/src/dictare/hotkey/base.py +57 -0
  135. dictare-0.1.140rc1/src/dictare/hotkey/evdev_listener.py +351 -0
  136. dictare-0.1.140rc1/src/dictare/hotkey/ipc.py +288 -0
  137. dictare-0.1.140rc1/src/dictare/hotkey/pynput_listener.py +172 -0
  138. dictare-0.1.140rc1/src/dictare/hotkey/runtime_status.py +32 -0
  139. dictare-0.1.140rc1/src/dictare/hotkey/tap_detector.py +211 -0
  140. dictare-0.1.140rc1/src/dictare/input/__init__.py +6 -0
  141. dictare-0.1.140rc1/src/dictare/input/backends/__init__.py +83 -0
  142. dictare-0.1.140rc1/src/dictare/input/backends/base.py +76 -0
  143. dictare-0.1.140rc1/src/dictare/input/backends/evdev_backend.py +199 -0
  144. dictare-0.1.140rc1/src/dictare/input/backends/hidapi_backend.py +210 -0
  145. dictare-0.1.140rc1/src/dictare/input/backends/karabiner_backend.py +283 -0
  146. dictare-0.1.140rc1/src/dictare/input/base.py +57 -0
  147. dictare-0.1.140rc1/src/dictare/input/constants.py +26 -0
  148. dictare-0.1.140rc1/src/dictare/input/device.py +366 -0
  149. dictare-0.1.140rc1/src/dictare/input/keyboard.py +172 -0
  150. dictare-0.1.140rc1/src/dictare/input/manager.py +152 -0
  151. dictare-0.1.140rc1/src/dictare/logging/__init__.py +36 -0
  152. dictare-0.1.140rc1/src/dictare/logging/jsonl.py +294 -0
  153. dictare-0.1.140rc1/src/dictare/logging/setup.py +147 -0
  154. dictare-0.1.140rc1/src/dictare/models.json +59 -0
  155. dictare-0.1.140rc1/src/dictare/pipeline/__init__.py +52 -0
  156. dictare-0.1.140rc1/src/dictare/pipeline/base.py +208 -0
  157. dictare-0.1.140rc1/src/dictare/pipeline/executors/__init__.py +7 -0
  158. dictare-0.1.140rc1/src/dictare/pipeline/executors/agent_switch.py +75 -0
  159. dictare-0.1.140rc1/src/dictare/pipeline/executors/input.py +73 -0
  160. dictare-0.1.140rc1/src/dictare/pipeline/executors/mute.py +72 -0
  161. dictare-0.1.140rc1/src/dictare/pipeline/filters/__init__.py +7 -0
  162. dictare-0.1.140rc1/src/dictare/pipeline/filters/_text.py +207 -0
  163. dictare-0.1.140rc1/src/dictare/pipeline/filters/agent_filter.py +333 -0
  164. dictare-0.1.140rc1/src/dictare/pipeline/filters/input_filter.py +193 -0
  165. dictare-0.1.140rc1/src/dictare/pipeline/filters/mute_filter.py +156 -0
  166. dictare-0.1.140rc1/src/dictare/pipeline/loader.py +191 -0
  167. dictare-0.1.140rc1/src/dictare/platform/__init__.py +1 -0
  168. dictare-0.1.140rc1/src/dictare/platform/accessibility.py +163 -0
  169. dictare-0.1.140rc1/src/dictare/platform/microphone.py +82 -0
  170. dictare-0.1.140rc1/src/dictare/platform/permission_doctor.py +218 -0
  171. dictare-0.1.140rc1/src/dictare/platform/permissions.py +240 -0
  172. dictare-0.1.140rc1/src/dictare/plugins/__init__.py +166 -0
  173. dictare-0.1.140rc1/src/dictare/plugins/base.py +99 -0
  174. dictare-0.1.140rc1/src/dictare/resources/Dictare.entitlements +9 -0
  175. dictare-0.1.140rc1/src/dictare/resources/Dictare.icns +0 -0
  176. dictare-0.1.140rc1/src/dictare/resources/__init__.py +0 -0
  177. dictare-0.1.140rc1/src/dictare/resources/app_icon.svg +11 -0
  178. dictare-0.1.140rc1/src/dictare/resources/launcher.swift +623 -0
  179. dictare-0.1.140rc1/src/dictare/resources/openvip-message-v1.0.json +134 -0
  180. dictare-0.1.140rc1/src/dictare/resources/openvip-openapi.json +680 -0
  181. dictare-0.1.140rc1/src/dictare/services/__init__.py +12 -0
  182. dictare-0.1.140rc1/src/dictare/services/base.py +98 -0
  183. dictare-0.1.140rc1/src/dictare/services/stt_service.py +194 -0
  184. dictare-0.1.140rc1/src/dictare/services/tts_service.py +129 -0
  185. dictare-0.1.140rc1/src/dictare/status.py +72 -0
  186. dictare-0.1.140rc1/src/dictare/stt/__init__.py +1 -0
  187. dictare-0.1.140rc1/src/dictare/stt/base.py +70 -0
  188. dictare-0.1.140rc1/src/dictare/stt/faster_whisper.py +416 -0
  189. dictare-0.1.140rc1/src/dictare/stt/mlx_whisper.py +175 -0
  190. dictare-0.1.140rc1/src/dictare/stt/parakeet.py +149 -0
  191. dictare-0.1.140rc1/src/dictare/tray/__init__.py +6 -0
  192. dictare-0.1.140rc1/src/dictare/tray/app.py +905 -0
  193. dictare-0.1.140rc1/src/dictare/tray/icons/dictare.png +0 -0
  194. dictare-0.1.140rc1/src/dictare/tray/icons/dictare.svg +10 -0
  195. dictare-0.1.140rc1/src/dictare/tray/icons/dictare@2x.png +0 -0
  196. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_active.png +0 -0
  197. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_active.svg +10 -0
  198. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_active@2x.png +0 -0
  199. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_disconnected.png +0 -0
  200. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_disconnected.svg +12 -0
  201. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_disconnected@2x.png +0 -0
  202. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_loading.png +0 -0
  203. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_loading.svg +13 -0
  204. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_loading@2x.png +0 -0
  205. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_muted.png +0 -0
  206. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_muted.svg +12 -0
  207. dictare-0.1.140rc1/src/dictare/tray/icons/dictare_muted@2x.png +0 -0
  208. dictare-0.1.140rc1/src/dictare/tray/lifecycle.py +175 -0
  209. dictare-0.1.140rc1/src/dictare/tts/__init__.py +134 -0
  210. dictare-0.1.140rc1/src/dictare/tts/__main__.py +5 -0
  211. dictare-0.1.140rc1/src/dictare/tts/base.py +129 -0
  212. dictare-0.1.140rc1/src/dictare/tts/cache.py +64 -0
  213. dictare-0.1.140rc1/src/dictare/tts/coqui.py +165 -0
  214. dictare-0.1.140rc1/src/dictare/tts/espeak.py +139 -0
  215. dictare-0.1.140rc1/src/dictare/tts/kokoro.py +326 -0
  216. dictare-0.1.140rc1/src/dictare/tts/outetts.py +247 -0
  217. dictare-0.1.140rc1/src/dictare/tts/piper.py +219 -0
  218. dictare-0.1.140rc1/src/dictare/tts/proxy.py +122 -0
  219. dictare-0.1.140rc1/src/dictare/tts/say.py +146 -0
  220. dictare-0.1.140rc1/src/dictare/tts/venv.py +254 -0
  221. dictare-0.1.140rc1/src/dictare/tts/worker.py +232 -0
  222. dictare-0.1.140rc1/src/dictare/ui/dist/_app/env.js +1 -0
  223. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/assets/0.u29JO9q6.css +1 -0
  224. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/assets/2.ADhTY10N.css +1 -0
  225. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/chunks/B5iEOtbf.js +1 -0
  226. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/chunks/BR0tsQvA.js +1 -0
  227. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/chunks/BfcgiW2_.js +1 -0
  228. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/chunks/BqKnRztf.js +2 -0
  229. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/chunks/CFFbbuus.js +1 -0
  230. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/chunks/TwTPH6iZ.js +1 -0
  231. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/chunks/WyvEpU-T.js +3 -0
  232. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/chunks/Yvw_uC43.js +1 -0
  233. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/chunks/uOPFAhOp.js +1 -0
  234. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/entry/app.BmNgH3es.js +2 -0
  235. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/entry/start.COqxU25x.js +1 -0
  236. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/nodes/0.CJgu44HO.js +1 -0
  237. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/nodes/1.DHFV5XMT.js +1 -0
  238. dictare-0.1.140rc1/src/dictare/ui/dist/_app/immutable/nodes/2.CRPCjhHz.js +33 -0
  239. dictare-0.1.140rc1/src/dictare/ui/dist/_app/version.json +1 -0
  240. dictare-0.1.140rc1/src/dictare/ui/dist/favicon.svg +11 -0
  241. dictare-0.1.140rc1/src/dictare/ui/dist/index.html +49 -0
  242. dictare-0.1.140rc1/src/dictare/utils/__init__.py +1 -0
  243. dictare-0.1.140rc1/src/dictare/utils/hardware.py +248 -0
  244. dictare-0.1.140rc1/src/dictare/utils/hf_download.py +217 -0
  245. dictare-0.1.140rc1/src/dictare/utils/install_info.py +157 -0
  246. dictare-0.1.140rc1/src/dictare/utils/jellyfish.py +265 -0
  247. dictare-0.1.140rc1/src/dictare/utils/loading.py +128 -0
  248. dictare-0.1.140rc1/src/dictare/utils/paths.py +15 -0
  249. dictare-0.1.140rc1/src/dictare/utils/platform.py +744 -0
  250. dictare-0.1.140rc1/src/dictare/utils/state.py +102 -0
  251. dictare-0.1.140rc1/src/dictare/utils/stats.py +246 -0
  252. dictare-0.1.140rc1/tests/__init__.py +1 -0
  253. dictare-0.1.140rc1/tests/conftest.py +160 -0
  254. dictare-0.1.140rc1/tests/test_agent_template.py +375 -0
  255. dictare-0.1.140rc1/tests/test_audio_devices.py +446 -0
  256. dictare-0.1.140rc1/tests/test_claim_agent.py +241 -0
  257. dictare-0.1.140rc1/tests/test_cli.py +194 -0
  258. dictare-0.1.140rc1/tests/test_cli_status.py +109 -0
  259. dictare-0.1.140rc1/tests/test_code_quality_fixes.py +288 -0
  260. dictare-0.1.140rc1/tests/test_config.py +273 -0
  261. dictare-0.1.140rc1/tests/test_controller.py +805 -0
  262. dictare-0.1.140rc1/tests/test_device_monitor.py +692 -0
  263. dictare-0.1.140rc1/tests/test_engine.py +1765 -0
  264. dictare-0.1.140rc1/tests/test_event_bus.py +207 -0
  265. dictare-0.1.140rc1/tests/test_executor_agent_switch.py +70 -0
  266. dictare-0.1.140rc1/tests/test_executor_submit.py +87 -0
  267. dictare-0.1.140rc1/tests/test_feedback_policy.py +128 -0
  268. dictare-0.1.140rc1/tests/test_fsm.py +450 -0
  269. dictare-0.1.140rc1/tests/test_hardware.py +124 -0
  270. dictare-0.1.140rc1/tests/test_hotkey_ipc.py +55 -0
  271. dictare-0.1.140rc1/tests/test_http_server.py +324 -0
  272. dictare-0.1.140rc1/tests/test_logging.py +228 -0
  273. dictare-0.1.140rc1/tests/test_loop_audio.py +215 -0
  274. dictare-0.1.140rc1/tests/test_messages.py +63 -0
  275. dictare-0.1.140rc1/tests/test_mode_switch.py +226 -0
  276. dictare-0.1.140rc1/tests/test_model_cache.py +99 -0
  277. dictare-0.1.140rc1/tests/test_mute.py +264 -0
  278. dictare-0.1.140rc1/tests/test_mux_focus.py +71 -0
  279. dictare-0.1.140rc1/tests/test_mux_session.py +323 -0
  280. dictare-0.1.140rc1/tests/test_onnx_asr_contract.py +52 -0
  281. dictare-0.1.140rc1/tests/test_openvip_internal.py +263 -0
  282. dictare-0.1.140rc1/tests/test_openvip_protocol.py +1144 -0
  283. dictare-0.1.140rc1/tests/test_panel.py +92 -0
  284. dictare-0.1.140rc1/tests/test_parakeet_engine.py +110 -0
  285. dictare-0.1.140rc1/tests/test_permission_doctor.py +57 -0
  286. dictare-0.1.140rc1/tests/test_pipeline.py +907 -0
  287. dictare-0.1.140rc1/tests/test_pipeline_loader.py +242 -0
  288. dictare-0.1.140rc1/tests/test_race_conditions.py +367 -0
  289. dictare-0.1.140rc1/tests/test_sdk_extension_fields.py +185 -0
  290. dictare-0.1.140rc1/tests/test_service.py +443 -0
  291. dictare-0.1.140rc1/tests/test_settings_api.py +430 -0
  292. dictare-0.1.140rc1/tests/test_single_instance.py +92 -0
  293. dictare-0.1.140rc1/tests/test_sse_agent.py +651 -0
  294. dictare-0.1.140rc1/tests/test_state.py +360 -0
  295. dictare-0.1.140rc1/tests/test_stats.py +225 -0
  296. dictare-0.1.140rc1/tests/test_status.py +89 -0
  297. dictare-0.1.140rc1/tests/test_status_bar.py +245 -0
  298. dictare-0.1.140rc1/tests/test_status_health.py +132 -0
  299. dictare-0.1.140rc1/tests/test_tap_detector.py +454 -0
  300. dictare-0.1.140rc1/tests/test_toml_sections.py +345 -0
  301. dictare-0.1.140rc1/tests/test_tray.py +297 -0
  302. dictare-0.1.140rc1/tests/test_tts_cache.py +298 -0
  303. dictare-0.1.140rc1/tests/test_tts_kokoro.py +123 -0
  304. dictare-0.1.140rc1/tests/test_tts_venv.py +283 -0
  305. dictare-0.1.140rc1/tests/test_tts_worker.py +306 -0
  306. dictare-0.1.140rc1/ui/components.json +16 -0
  307. dictare-0.1.140rc1/ui/package.json +39 -0
  308. dictare-0.1.140rc1/ui/pnpm-lock.yaml +1909 -0
  309. dictare-0.1.140rc1/ui/postcss.config.js +6 -0
  310. dictare-0.1.140rc1/ui/src/app.css +60 -0
  311. dictare-0.1.140rc1/ui/src/app.d.ts +2 -0
  312. dictare-0.1.140rc1/ui/src/app.html +22 -0
  313. dictare-0.1.140rc1/ui/src/lib/api.ts +406 -0
  314. dictare-0.1.140rc1/ui/src/lib/components/dashboard/DashboardPage.svelte +282 -0
  315. dictare-0.1.140rc1/ui/src/lib/components/models/ModelsPage.svelte +337 -0
  316. dictare-0.1.140rc1/ui/src/lib/components/settings/EngineStatusBar.svelte +125 -0
  317. dictare-0.1.140rc1/ui/src/lib/components/settings/FieldRenderer.svelte +219 -0
  318. dictare-0.1.140rc1/ui/src/lib/components/settings/SaveBar.svelte +39 -0
  319. dictare-0.1.140rc1/ui/src/lib/components/settings/SettingsLayout.svelte +352 -0
  320. dictare-0.1.140rc1/ui/src/lib/components/settings/SettingsNav.svelte +143 -0
  321. dictare-0.1.140rc1/ui/src/lib/components/settings/SettingsSection.svelte +60 -0
  322. dictare-0.1.140rc1/ui/src/lib/components/settings/fields/BoolField.svelte +15 -0
  323. dictare-0.1.140rc1/ui/src/lib/components/settings/fields/ComplexField.svelte +8 -0
  324. dictare-0.1.140rc1/ui/src/lib/components/settings/fields/KeyCaptureField.svelte +241 -0
  325. dictare-0.1.140rc1/ui/src/lib/components/settings/fields/NumberField.svelte +39 -0
  326. dictare-0.1.140rc1/ui/src/lib/components/settings/fields/SelectField.svelte +112 -0
  327. dictare-0.1.140rc1/ui/src/lib/components/settings/fields/ShortcutsField.svelte +108 -0
  328. dictare-0.1.140rc1/ui/src/lib/components/settings/fields/StringField.svelte +26 -0
  329. dictare-0.1.140rc1/ui/src/lib/components/settings/fields/TomlField.svelte +171 -0
  330. dictare-0.1.140rc1/ui/src/lib/components/ui/badge/badge.svelte +50 -0
  331. dictare-0.1.140rc1/ui/src/lib/components/ui/badge/index.ts +2 -0
  332. dictare-0.1.140rc1/ui/src/lib/components/ui/button/button.svelte +74 -0
  333. dictare-0.1.140rc1/ui/src/lib/components/ui/button/index.ts +17 -0
  334. dictare-0.1.140rc1/ui/src/lib/components/ui/card/card-content.svelte +16 -0
  335. dictare-0.1.140rc1/ui/src/lib/components/ui/card/card-description.svelte +16 -0
  336. dictare-0.1.140rc1/ui/src/lib/components/ui/card/card-footer.svelte +16 -0
  337. dictare-0.1.140rc1/ui/src/lib/components/ui/card/card-header.svelte +16 -0
  338. dictare-0.1.140rc1/ui/src/lib/components/ui/card/card-title.svelte +25 -0
  339. dictare-0.1.140rc1/ui/src/lib/components/ui/card/card.svelte +20 -0
  340. dictare-0.1.140rc1/ui/src/lib/components/ui/card/index.ts +22 -0
  341. dictare-0.1.140rc1/ui/src/lib/components/ui/input/index.ts +7 -0
  342. dictare-0.1.140rc1/ui/src/lib/components/ui/input/input.svelte +46 -0
  343. dictare-0.1.140rc1/ui/src/lib/components/ui/label/index.ts +7 -0
  344. dictare-0.1.140rc1/ui/src/lib/components/ui/label/label.svelte +19 -0
  345. dictare-0.1.140rc1/ui/src/lib/components/ui/select/index.ts +13 -0
  346. dictare-0.1.140rc1/ui/src/lib/components/ui/select/select-content.svelte +28 -0
  347. dictare-0.1.140rc1/ui/src/lib/components/ui/select/select-item.svelte +32 -0
  348. dictare-0.1.140rc1/ui/src/lib/components/ui/select/select-trigger.svelte +28 -0
  349. dictare-0.1.140rc1/ui/src/lib/components/ui/separator/index.ts +7 -0
  350. dictare-0.1.140rc1/ui/src/lib/components/ui/separator/separator.svelte +22 -0
  351. dictare-0.1.140rc1/ui/src/lib/components/ui/switch/index.ts +1 -0
  352. dictare-0.1.140rc1/ui/src/lib/components/ui/switch/switch.svelte +27 -0
  353. dictare-0.1.140rc1/ui/src/lib/components/ui/tooltip/index.ts +18 -0
  354. dictare-0.1.140rc1/ui/src/lib/components/ui/tooltip/tooltip-content.svelte +21 -0
  355. dictare-0.1.140rc1/ui/src/lib/registry/field-config.ts +84 -0
  356. dictare-0.1.140rc1/ui/src/lib/registry/tabs.ts +88 -0
  357. dictare-0.1.140rc1/ui/src/lib/schema.ts +40 -0
  358. dictare-0.1.140rc1/ui/src/lib/stores/presets.svelte.ts +2 -0
  359. dictare-0.1.140rc1/ui/src/lib/stores/settings.svelte.ts +279 -0
  360. dictare-0.1.140rc1/ui/src/lib/stores/tab-guard.svelte.ts +32 -0
  361. dictare-0.1.140rc1/ui/src/lib/stores/theme.svelte.ts +21 -0
  362. dictare-0.1.140rc1/ui/src/lib/types.ts +60 -0
  363. dictare-0.1.140rc1/ui/src/lib/utils.ts +6 -0
  364. dictare-0.1.140rc1/ui/src/routes/+layout.svelte +10 -0
  365. dictare-0.1.140rc1/ui/src/routes/+page.svelte +22 -0
  366. dictare-0.1.140rc1/ui/static/favicon.svg +11 -0
  367. dictare-0.1.140rc1/ui/svelte.config.js +19 -0
  368. dictare-0.1.140rc1/ui/tailwind.config.js +62 -0
  369. dictare-0.1.140rc1/ui/tsconfig.json +14 -0
  370. dictare-0.1.140rc1/ui/vite.config.ts +13 -0
  371. dictare-0.1.140rc1/uv.lock +1961 -0
@@ -0,0 +1,22 @@
1
+ # Exclude dev artifacts from test builds
2
+ .venv/
3
+ .git/
4
+ __pycache__/
5
+ *.pyc
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ dist/
11
+ build/
12
+
13
+ # Config/data
14
+ .env
15
+ *.log
16
+
17
+ # IDE
18
+ .vscode/
19
+ .idea/
20
+
21
+ # Test outputs
22
+ /scripts/test-distros/*.log
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report a bug to help us improve dictare
4
+ title: ''
5
+ labels: bug
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Description
10
+
11
+ A clear and concise description of the bug.
12
+
13
+ ## Steps to Reproduce
14
+
15
+ 1. Run `dictare listen`
16
+ 2. Do '...'
17
+ 3. See error
18
+
19
+ ## Expected Behavior
20
+
21
+ What you expected to happen.
22
+
23
+ ## Actual Behavior
24
+
25
+ What actually happened.
26
+
27
+ ## Environment
28
+
29
+ - **OS**: [e.g., macOS 14.0, Ubuntu 24.04]
30
+ - **Architecture**: [e.g., Apple Silicon M1, x86_64]
31
+ - **Python version**: [e.g., 3.11.5]
32
+ - **dictare version**: [run `dictare --version`]
33
+ - **Installation method**: [e.g., install.sh, uv tool install, pip]
34
+
35
+ ## Logs
36
+
37
+ <details>
38
+ <summary>Output of `dictare check`</summary>
39
+
40
+ ```
41
+ [paste output here]
42
+ ```
43
+
44
+ </details>
45
+
46
+ <details>
47
+ <summary>Error messages or logs</summary>
48
+
49
+ ```
50
+ [paste any error messages here]
51
+ ```
52
+
53
+ </details>
54
+
55
+ ## Additional Context
56
+
57
+ Add any other context about the problem here.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for dictare
4
+ title: ''
5
+ labels: enhancement
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Problem Statement
10
+
11
+ A clear and concise description of the problem or limitation you're experiencing.
12
+
13
+ Example: "I'm always frustrated when [...]"
14
+
15
+ ## Proposed Solution
16
+
17
+ A clear and concise description of what you want to happen.
18
+
19
+ ## Alternatives Considered
20
+
21
+ A description of any alternative solutions or features you've considered.
22
+
23
+ ## Use Case
24
+
25
+ Describe your use case and how this feature would help you.
26
+
27
+ ## Additional Context
28
+
29
+ Add any other context, mockups, or examples about the feature request here.
@@ -0,0 +1,29 @@
1
+ ## Summary
2
+
3
+ <!-- Brief description of what this PR does -->
4
+
5
+ ## Changes
6
+
7
+ <!-- List the main changes in this PR -->
8
+
9
+ -
10
+
11
+ ## Test Plan
12
+
13
+ <!-- How did you test these changes? -->
14
+
15
+ - [ ] Ran `uv run pytest tests/`
16
+ - [ ] Ran `uv run ruff check .`
17
+ - [ ] Tested manually with `dictare listen`
18
+
19
+ ## Checklist
20
+
21
+ - [ ] I have read the [CONTRIBUTING](../CONTRIBUTING.md) guidelines
22
+ - [ ] My code follows the project's code style
23
+ - [ ] I have added tests for my changes (if applicable)
24
+ - [ ] I have updated the documentation (if applicable)
25
+ - [ ] I have updated CHANGELOG.md (if applicable)
26
+
27
+ ## Related Issues
28
+
29
+ <!-- Link to any related issues: Fixes #123, Closes #456 -->
@@ -0,0 +1,197 @@
1
+ name: "0 - release: sign launcher"
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ jobs:
7
+ build-sign-notarize:
8
+ runs-on: macos-latest
9
+ permissions:
10
+ contents: write
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ # Fetch secrets from Infisical (single token, all secrets centralized)
15
+ - name: Load secrets from Infisical
16
+ env:
17
+ INFISICAL_TOKEN: ${{ secrets.INFISICAL_TOKEN }}
18
+ run: |
19
+ brew install infisical/get-cli/infisical
20
+ # Export secrets as JSON → write to GITHUB_ENV + mask values
21
+ # Note: cannot use IFS='=' because base64 values contain '=' padding
22
+ infisical export \
23
+ --domain "https://eu.infisical.com" \
24
+ --projectId "7d6c2573-e67b-4243-9911-0a9ddaed58b8" \
25
+ --path "/work/dictare/app/ci" \
26
+ --env prod \
27
+ --format json | \
28
+ jq -c '.[]' | while read -r item; do
29
+ key=$(echo "$item" | jq -r '.key')
30
+ value=$(echo "$item" | jq -r '.value')
31
+ # Mask each line separately (multiline values like PEM keys)
32
+ while IFS= read -r line; do
33
+ [[ -n "$line" ]] && echo "::add-mask::$line"
34
+ done <<< "$value"
35
+ # Use heredoc for multiline values (e.g. PEM keys)
36
+ EOF_MARKER="EOF_$(head -c 8 /dev/urandom | xxd -p)"
37
+ echo "$key<<$EOF_MARKER" >> "$GITHUB_ENV"
38
+ echo "$value" >> "$GITHUB_ENV"
39
+ echo "$EOF_MARKER" >> "$GITHUB_ENV"
40
+ done
41
+
42
+ # Verify secrets were loaded
43
+ - name: Verify secrets
44
+ run: |
45
+ missing=()
46
+ for var in APPLE_DEVELOPER_ID_P12 APPLE_DEVELOPER_ID_P12_PASSWORD \
47
+ APPLE_NOTARIZATION_DICTARE_KEY APPLE_NOTARIZATION_DICTARE_KEY_ID \
48
+ APPLE_NOTARIZATION_ISSUER_ID; do
49
+ if [[ -z "${!var:-}" ]]; then
50
+ missing+=("$var")
51
+ else
52
+ val="${!var}"
53
+ echo "✓ $var is set (${#val} chars)"
54
+ fi
55
+ done
56
+ if [[ ${#missing[@]} -gt 0 ]]; then
57
+ echo "::error::Missing secrets: ${missing[*]}"
58
+ exit 1
59
+ fi
60
+
61
+ # Import Developer ID certificate into a temporary keychain
62
+ - name: Import signing certificate
63
+ run: |
64
+ KEYCHAIN="$RUNNER_TEMP/signing.keychain-db"
65
+ security create-keychain -p "" "$KEYCHAIN"
66
+ security set-keychain-settings -lut 21600 "$KEYCHAIN"
67
+ echo "$APPLE_DEVELOPER_ID_P12" | base64 -d > "$RUNNER_TEMP/cert.p12"
68
+ security import "$RUNNER_TEMP/cert.p12" -k "$KEYCHAIN" \
69
+ -P "$APPLE_DEVELOPER_ID_P12_PASSWORD" -T /usr/bin/codesign
70
+ security set-key-partition-list -S apple-tool:,apple: \
71
+ -s -k "" "$KEYCHAIN"
72
+ security list-keychains -d user -s "$KEYCHAIN" login.keychain
73
+
74
+ # Build universal binary + sign with Hardened Runtime
75
+ - name: Build and sign launcher
76
+ run: |
77
+ DICTARE_SIGN_IDENTITY="Developer ID Application" \
78
+ ./scripts/macos/sign-launcher.sh
79
+
80
+ # Assemble the complete .app bundle (binary + Info.plist + icon)
81
+ # python_path is NOT inside the bundle — the launcher reads it from
82
+ # ~/.dictare/python_path at runtime, so the signed bundle stays immutable.
83
+ - name: Assemble .app bundle
84
+ run: |
85
+ VERSION=$(grep -E '^__version__' src/dictare/__init__.py | sed 's/.*"\(.*\)"/\1/')
86
+ BUNDLE="build/bundle/Dictare.app"
87
+ CONTENTS="$BUNDLE/Contents"
88
+ MACOS_DIR="$CONTENTS/MacOS"
89
+ RESOURCES_DIR="$CONTENTS/Resources"
90
+
91
+ mkdir -p "$MACOS_DIR" "$RESOURCES_DIR"
92
+
93
+ # Binary
94
+ cp build/launcher/Dictare "$MACOS_DIR/Dictare"
95
+
96
+ # Info.plist
97
+ /usr/libexec/PlistBuddy -c "Clear dict" "$CONTENTS/Info.plist" 2>/dev/null || true
98
+ cat > "$CONTENTS/Info.plist" << 'PLIST'
99
+ <?xml version="1.0" encoding="UTF-8"?>
100
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
101
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
102
+ <plist version="1.0">
103
+ <dict>
104
+ <key>CFBundleName</key>
105
+ <string>Dictare</string>
106
+ <key>CFBundleDisplayName</key>
107
+ <string>Dictare</string>
108
+ <key>CFBundleIdentifier</key>
109
+ <string>dev.dragfly.dictare</string>
110
+ <key>CFBundleVersion</key>
111
+ <string>VERSION_PLACEHOLDER</string>
112
+ <key>CFBundleShortVersionString</key>
113
+ <string>VERSION_PLACEHOLDER</string>
114
+ <key>CFBundlePackageType</key>
115
+ <string>APPL</string>
116
+ <key>CFBundleExecutable</key>
117
+ <string>Dictare</string>
118
+ <key>CFBundleIconFile</key>
119
+ <string>Dictare</string>
120
+ <key>LSUIElement</key>
121
+ <true/>
122
+ <key>NSMicrophoneUsageDescription</key>
123
+ <string>Dictare needs microphone access for voice-to-text.</string>
124
+ <key>NSInputMonitoringUsageDescription</key>
125
+ <string>Dictare uses Input Monitoring to detect the global Right ⌘ hotkey.</string>
126
+ </dict>
127
+ </plist>
128
+ PLIST
129
+ # Inject actual version
130
+ sed -i '' "s/VERSION_PLACEHOLDER/$VERSION/g" "$CONTENTS/Info.plist"
131
+
132
+ # Icon
133
+ cp src/dictare/resources/Dictare.icns "$RESOURCES_DIR/Dictare.icns"
134
+
135
+ # Launcher metadata — stored in Resources/ (not MacOS/) because
136
+ # codesign requires all files in MacOS/ to be signed Mach-O binaries.
137
+ HASH=$(shasum -a 256 src/dictare/resources/launcher.swift | cut -c1-16)
138
+ echo "$HASH" > "$RESOURCES_DIR/launcher_hash"
139
+ echo "true" > "$RESOURCES_DIR/launcher_signed"
140
+
141
+ echo "==> Bundle assembled: $BUNDLE (version $VERSION)"
142
+ ls -laR "$BUNDLE"
143
+
144
+ # Sign the complete .app bundle (not just the binary)
145
+ - name: Sign bundle
146
+ run: |
147
+ codesign --force --options runtime \
148
+ --entitlements src/dictare/resources/Dictare.entitlements \
149
+ --sign "Developer ID Application" \
150
+ build/bundle/Dictare.app
151
+ codesign --verify --strict build/bundle/Dictare.app
152
+ echo "==> Bundle signed and verified"
153
+
154
+ # Notarize the complete bundle
155
+ - name: Notarize
156
+ run: |
157
+ echo "$APPLE_NOTARIZATION_DICTARE_KEY" > "$RUNNER_TEMP/AuthKey.p8"
158
+ ditto -c -k --keepParent build/bundle/Dictare.app build/bundle/Dictare.app.zip
159
+ xcrun notarytool submit build/bundle/Dictare.app.zip \
160
+ --key "$RUNNER_TEMP/AuthKey.p8" \
161
+ --key-id "$APPLE_NOTARIZATION_DICTARE_KEY_ID" \
162
+ --issuer "$APPLE_NOTARIZATION_ISSUER_ID" \
163
+ --wait --timeout 10m
164
+
165
+ # Staple the notarization ticket to the bundle
166
+ - name: Staple
167
+ run: |
168
+ xcrun stapler staple build/bundle/Dictare.app
169
+ echo "==> Notarization ticket stapled"
170
+
171
+ # Upload to the fixed "launcher" release tag (version-independent)
172
+ - name: Upload to launcher release
173
+ env:
174
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
175
+ run: |
176
+ ZIP="Dictare-launcher-universal.zip"
177
+ # ditto -c -k on a directory zips its CONTENTS, losing the .app
178
+ # wrapper. Use -keepParent to preserve the Dictare.app directory
179
+ # so extraction yields Dictare.app/Contents/... as expected.
180
+ ditto -c -k --keepParent build/bundle/Dictare.app "$ZIP"
181
+ # Create or update the fixed "launcher" release.
182
+ # First try to upload to existing release; if it doesn't exist, create it.
183
+ if gh release view "launcher" &>/dev/null; then
184
+ gh release upload "launcher" "$ZIP" --clobber
185
+ else
186
+ gh release create "launcher" "$ZIP" \
187
+ --title "Universal Dictare Launcher" \
188
+ --notes "Pre-built signed + notarized Dictare.app bundle. Downloaded automatically by install.sh."
189
+ fi
190
+ echo "==> Uploaded $ZIP to 'launcher' release"
191
+
192
+ # Upload as artifact (always, for manual builds)
193
+ - name: Upload artifact
194
+ uses: actions/upload-artifact@v4
195
+ with:
196
+ name: Dictare-launcher-universal
197
+ path: build/bundle/Dictare.app
@@ -0,0 +1,25 @@
1
+ name: "auto: test macOS"
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 4 * * *" # daily at 04:00 UTC
6
+ workflow_dispatch: # allow manual trigger from GitHub UI
7
+
8
+ jobs:
9
+ test-macos:
10
+ runs-on: macos-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Install uv
15
+ uses: astral-sh/setup-uv@v4
16
+
17
+ - name: Set up Python and install deps
18
+ run: |
19
+ uv venv --python 3.11 --seed .venv
20
+ echo "VIRTUAL_ENV=$PWD/.venv" >> $GITHUB_ENV
21
+ echo "$PWD/.venv/bin" >> $GITHUB_PATH
22
+ .venv/bin/pip install -e ".[dev]"
23
+
24
+ - name: Run CoreAudio tests
25
+ run: pytest tests/ -v -m macos
@@ -0,0 +1,48 @@
1
+ name: "auto: test + lint"
2
+
3
+ on:
4
+ push:
5
+ branches: ["*"] # Run on all branches
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.11"
18
+ cache: pip
19
+ cache-dependency-path: pyproject.toml
20
+
21
+ - name: Install system deps
22
+ run: sudo apt-get install -y libportaudio2 xvfb
23
+
24
+ - name: Install deps
25
+ run: pip install -e ".[dev]"
26
+
27
+ - name: Run linter
28
+ run: ruff check src/ tests/
29
+
30
+ - name: Run tests with coverage
31
+ run: xvfb-run pytest tests/ -v -m '' --cov=dictare --cov-report=term-missing
32
+
33
+ typecheck:
34
+ runs-on: ubuntu-latest
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+
38
+ - uses: actions/setup-python@v5
39
+ with:
40
+ python-version: "3.11"
41
+ cache: pip
42
+ cache-dependency-path: pyproject.toml
43
+
44
+ - name: Install deps
45
+ run: pip install -e ".[dev]"
46
+
47
+ - name: Run mypy
48
+ run: mypy src/
@@ -0,0 +1,45 @@
1
+ name: "claude: issue dedupe"
2
+
3
+ on:
4
+ issues:
5
+ types: [opened]
6
+ workflow_dispatch:
7
+ inputs:
8
+ issue_number:
9
+ description: Issue number to check for duplicates
10
+ required: true
11
+
12
+ jobs:
13
+ dedupe:
14
+ runs-on: ubuntu-latest
15
+ timeout-minutes: 10
16
+ permissions:
17
+ contents: read
18
+ issues: write
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Run Claude Code for Deduplication
23
+ timeout-minutes: 8
24
+ uses: anthropics/claude-code-action@v1
25
+ env:
26
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27
+ GH_REPO: ${{ github.repository }}
28
+ with:
29
+ github_token: ${{ secrets.GITHUB_TOKEN }}
30
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
31
+ claude_args: "--model claude-sonnet-4-6"
32
+ prompt: |
33
+ Check if this issue is a duplicate for the dictare project.
34
+
35
+ REPO: ${{ github.repository }}
36
+ ISSUE_NUMBER: ${{ github.event.issue.number || github.event.inputs.issue_number }}
37
+
38
+ Instructions:
39
+ 1. Read the new issue
40
+ 2. Search existing issues for similar ones (use gh issue list --state all --limit 200)
41
+ 3. If a duplicate is found:
42
+ - Comment on the new issue linking to the original: "Duplicate of #NNN"
43
+ - Add the label "duplicate"
44
+ - Do NOT close it (the maintainer will decide)
45
+ 4. If no duplicate, do nothing (no comment needed)
@@ -0,0 +1,49 @@
1
+ name: "claude: issue triage"
2
+
3
+ on:
4
+ issues:
5
+ types: [opened]
6
+ issue_comment:
7
+ types: [created]
8
+
9
+ jobs:
10
+ triage-issue:
11
+ runs-on: ubuntu-latest
12
+ timeout-minutes: 10
13
+ if: >-
14
+ github.event_name == 'issues' ||
15
+ (github.event_name == 'issue_comment' && !github.event.issue.pull_request && github.event.comment.user.type != 'Bot')
16
+ concurrency:
17
+ group: issue-triage-${{ github.event.issue.number }}
18
+ cancel-in-progress: true
19
+ permissions:
20
+ contents: read
21
+ issues: write
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - name: Run Claude Code for Issue Triage
26
+ timeout-minutes: 5
27
+ uses: anthropics/claude-code-action@v1
28
+ env:
29
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30
+ GH_REPO: ${{ github.repository }}
31
+ with:
32
+ github_token: ${{ secrets.GITHUB_TOKEN }}
33
+ allowed_non_write_users: "*"
34
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
35
+ claude_args: "--model claude-sonnet-4-6"
36
+ prompt: |
37
+ Triage this GitHub issue for the dictare project (voice-first control for AI coding agents).
38
+
39
+ REPO: ${{ github.repository }}
40
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
41
+ EVENT: ${{ github.event_name }}
42
+
43
+ Instructions:
44
+ 1. Read the issue carefully using the GitHub CLI
45
+ 2. Add the appropriate label(s): bug, enhancement, question, documentation, good first issue
46
+ 3. If it's a bug, ask for: OS (macOS/Linux), dictare version, steps to reproduce
47
+ 4. If it's a feature request, acknowledge it and explain where it fits in the roadmap
48
+ 5. If it's a question, answer it directly if possible or point to the README/docs
49
+ 6. Be concise and friendly. Sign off as "dictare bot"
@@ -0,0 +1,57 @@
1
+ name: "claude: pr review"
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize]
6
+
7
+ jobs:
8
+ review:
9
+ runs-on: ubuntu-latest
10
+ timeout-minutes: 15
11
+ # Skip PRs from the maintainer (manual review) and bots
12
+ if: |
13
+ github.event.pull_request.user.login != 'twisteroo' &&
14
+ github.event.pull_request.user.type != 'Bot'
15
+ permissions:
16
+ contents: read
17
+ pull-requests: write
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ with:
21
+ fetch-depth: 0
22
+
23
+ - name: Run Claude Code for PR Review
24
+ timeout-minutes: 10
25
+ uses: anthropics/claude-code-action@v1
26
+ env:
27
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28
+ GH_REPO: ${{ github.repository }}
29
+ with:
30
+ github_token: ${{ secrets.GITHUB_TOKEN }}
31
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
32
+ claude_args: "--model claude-sonnet-4-6"
33
+ prompt: |
34
+ Review this pull request for the dictare project.
35
+
36
+ REPO: ${{ github.repository }}
37
+ PR_NUMBER: ${{ github.event.pull_request.number }}
38
+ PR_TITLE: ${{ github.event.pull_request.title }}
39
+ AUTHOR: ${{ github.event.pull_request.user.login }}
40
+ BASE_BRANCH: ${{ github.event.pull_request.base.ref }}
41
+
42
+ Dictare is a voice-first control layer for AI coding agents (Claude Code, Cursor, etc.).
43
+ It implements the OpenVIP protocol. Python 3.11, FastAPI, Typer, uv.
44
+
45
+ Review instructions:
46
+ 1. Read the PR diff using gh CLI
47
+ 2. Check: code correctness, test coverage, docs updates, breaking changes
48
+ 3. Verify CHANGELOG.md is updated if the change is user-visible
49
+ 4. Check for security concerns (no credentials hardcoded, no unsafe operations)
50
+ 5. Verify Python 3.11 compatibility and uv/ruff style compliance
51
+ 6. Post a concise review comment with: summary of changes, specific feedback (if any),
52
+ and LGTM or requested changes
53
+ 7. Add labels: "needs-review" if changes needed, "ready-to-merge" if LGTM
54
+ 8. Be constructive and friendly. First-time contributors deserve extra encouragement.
55
+ 9. Sign off as "dictare bot"
56
+
57
+ Keep the review focused — max 200 words unless there are real issues to flag.
@@ -0,0 +1,35 @@
1
+ name: "claude: code"
2
+
3
+ on:
4
+ issue_comment:
5
+ types: [created]
6
+ pull_request_review_comment:
7
+ types: [created]
8
+ pull_request_review:
9
+ types: [submitted]
10
+ issues:
11
+ types: [opened, assigned]
12
+
13
+ jobs:
14
+ claude:
15
+ runs-on: ubuntu-latest
16
+ timeout-minutes: 10
17
+ if: |
18
+ (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
19
+ (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
20
+ (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
21
+ (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
22
+ permissions:
23
+ contents: read
24
+ pull-requests: read
25
+ issues: read
26
+ id-token: write
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+
30
+ - name: Run Claude Code
31
+ uses: anthropics/claude-code-action@v1
32
+ with:
33
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
34
+ github_token: ${{ secrets.GITHUB_TOKEN }}
35
+ claude_args: "--model claude-sonnet-4-6"
@@ -0,0 +1,53 @@
1
+ name: "auto: lock issues"
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 14 * * *" # daily at 14:00 UTC
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ lock:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ issues: write
13
+ steps:
14
+ - uses: actions/github-script@v7
15
+ with:
16
+ script: |
17
+ const sevenDaysAgo = new Date();
18
+ sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
19
+
20
+ const issues = await github.paginate(github.rest.issues.listForRepo, {
21
+ owner: context.repo.owner,
22
+ repo: context.repo.repo,
23
+ state: 'closed',
24
+ sort: 'updated',
25
+ direction: 'asc',
26
+ per_page: 100,
27
+ });
28
+
29
+ let locked = 0;
30
+ for (const issue of issues) {
31
+ if (issue.pull_request) continue;
32
+ if (issue.locked) continue;
33
+ if (new Date(issue.updated_at) > sevenDaysAgo) continue;
34
+
35
+ await github.rest.issues.createComment({
36
+ owner: context.repo.owner,
37
+ repo: context.repo.repo,
38
+ issue_number: issue.number,
39
+ body: 'This issue has been automatically locked since it has been closed ' +
40
+ 'and had no activity for 7 days. If you are experiencing a similar ' +
41
+ 'issue, please open a new one.',
42
+ });
43
+
44
+ await github.rest.issues.lock({
45
+ owner: context.repo.owner,
46
+ repo: context.repo.repo,
47
+ issue_number: issue.number,
48
+ lock_reason: 'resolved',
49
+ });
50
+
51
+ locked++;
52
+ }
53
+ console.log(`Locked ${locked} issues.`);
@@ -0,0 +1,29 @@
1
+ name: "0 - release: publish to PyPI"
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ jobs:
7
+ publish:
8
+ name: Build and publish to PyPI
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ contents: read
12
+ id-token: write # Required for Trusted Publisher (OIDC)
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Set up Python
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.11"
21
+
22
+ - name: Install build tools
23
+ run: pip install build
24
+
25
+ - name: Build sdist and wheel
26
+ run: python -m build
27
+
28
+ - name: Publish to PyPI
29
+ uses: pypa/gh-action-pypi-publish@release/v1