gsd-pi 2.10.12 → 2.12.0

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 (504) hide show
  1. package/dist/bundled-extension-paths.d.ts +2 -0
  2. package/dist/bundled-extension-paths.js +10 -0
  3. package/dist/loader.js +45 -28
  4. package/dist/onboarding.js +100 -0
  5. package/dist/resource-loader.js +12 -3
  6. package/dist/resources/GSD-WORKFLOW.md +661 -0
  7. package/dist/resources/agents/researcher.md +29 -0
  8. package/dist/resources/agents/scout.md +56 -0
  9. package/dist/resources/agents/worker.md +31 -0
  10. package/dist/resources/extensions/ask-user-questions.ts +289 -0
  11. package/dist/resources/extensions/async-jobs/async-bash-tool.ts +211 -0
  12. package/dist/resources/extensions/async-jobs/await-tool.ts +101 -0
  13. package/dist/resources/extensions/async-jobs/cancel-job-tool.ts +34 -0
  14. package/dist/resources/extensions/async-jobs/index.ts +133 -0
  15. package/dist/resources/extensions/async-jobs/job-manager.ts +211 -0
  16. package/dist/resources/extensions/bg-shell/index.ts +3179 -0
  17. package/dist/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
  18. package/dist/resources/extensions/browser-tools/capture.ts +165 -0
  19. package/dist/resources/extensions/browser-tools/core.d.ts +205 -0
  20. package/dist/resources/extensions/browser-tools/core.js +1057 -0
  21. package/dist/resources/extensions/browser-tools/evaluate-helpers.ts +184 -0
  22. package/dist/resources/extensions/browser-tools/index.ts +51 -0
  23. package/dist/resources/extensions/browser-tools/lifecycle.ts +270 -0
  24. package/dist/resources/extensions/browser-tools/package.json +24 -0
  25. package/dist/resources/extensions/browser-tools/refs.ts +264 -0
  26. package/dist/resources/extensions/browser-tools/settle.ts +197 -0
  27. package/dist/resources/extensions/browser-tools/state.ts +408 -0
  28. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +652 -0
  29. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +614 -0
  30. package/dist/resources/extensions/browser-tools/tools/assertions.ts +342 -0
  31. package/dist/resources/extensions/browser-tools/tools/forms.ts +801 -0
  32. package/dist/resources/extensions/browser-tools/tools/inspection.ts +492 -0
  33. package/dist/resources/extensions/browser-tools/tools/intent.ts +614 -0
  34. package/dist/resources/extensions/browser-tools/tools/interaction.ts +865 -0
  35. package/dist/resources/extensions/browser-tools/tools/navigation.ts +232 -0
  36. package/dist/resources/extensions/browser-tools/tools/pages.ts +303 -0
  37. package/dist/resources/extensions/browser-tools/tools/refs.ts +541 -0
  38. package/dist/resources/extensions/browser-tools/tools/screenshot.ts +83 -0
  39. package/dist/resources/extensions/browser-tools/tools/session.ts +400 -0
  40. package/dist/resources/extensions/browser-tools/tools/wait.ts +247 -0
  41. package/dist/resources/extensions/browser-tools/utils.ts +660 -0
  42. package/dist/resources/extensions/context7/index.ts +428 -0
  43. package/dist/resources/extensions/context7/package.json +11 -0
  44. package/dist/resources/extensions/get-secrets-from-user.ts +625 -0
  45. package/dist/resources/extensions/google-search/index.ts +336 -0
  46. package/dist/resources/extensions/google-search/package.json +9 -0
  47. package/dist/resources/extensions/gsd/activity-log.ts +116 -0
  48. package/dist/resources/extensions/gsd/auto.ts +3732 -0
  49. package/dist/resources/extensions/gsd/commands.ts +544 -0
  50. package/dist/resources/extensions/gsd/crash-recovery.ts +105 -0
  51. package/dist/resources/extensions/gsd/dashboard-overlay.ts +564 -0
  52. package/dist/resources/extensions/gsd/dispatch-guard.ts +78 -0
  53. package/dist/resources/extensions/gsd/docs/preferences-reference.md +278 -0
  54. package/dist/resources/extensions/gsd/doctor.ts +766 -0
  55. package/dist/resources/extensions/gsd/exit-command.ts +18 -0
  56. package/dist/resources/extensions/gsd/files.ts +857 -0
  57. package/dist/resources/extensions/gsd/git-service.ts +904 -0
  58. package/dist/resources/extensions/gsd/gitignore.ts +200 -0
  59. package/dist/resources/extensions/gsd/guided-flow.ts +1054 -0
  60. package/dist/resources/extensions/gsd/index.ts +735 -0
  61. package/dist/resources/extensions/gsd/metrics.ts +374 -0
  62. package/dist/resources/extensions/gsd/migrate/command.ts +218 -0
  63. package/dist/resources/extensions/gsd/migrate/index.ts +42 -0
  64. package/dist/resources/extensions/gsd/migrate/parser.ts +323 -0
  65. package/dist/resources/extensions/gsd/migrate/parsers.ts +624 -0
  66. package/dist/resources/extensions/gsd/migrate/preview.ts +48 -0
  67. package/dist/resources/extensions/gsd/migrate/transformer.ts +346 -0
  68. package/dist/resources/extensions/gsd/migrate/types.ts +370 -0
  69. package/dist/resources/extensions/gsd/migrate/validator.ts +55 -0
  70. package/dist/resources/extensions/gsd/migrate/writer.ts +539 -0
  71. package/dist/resources/extensions/gsd/native-git-bridge.ts +181 -0
  72. package/dist/resources/extensions/gsd/native-parser-bridge.ts +135 -0
  73. package/dist/resources/extensions/gsd/observability-validator.ts +408 -0
  74. package/dist/resources/extensions/gsd/package.json +11 -0
  75. package/dist/resources/extensions/gsd/paths.ts +339 -0
  76. package/dist/resources/extensions/gsd/post-unit-hooks.ts +449 -0
  77. package/dist/resources/extensions/gsd/preferences.ts +988 -0
  78. package/dist/resources/extensions/gsd/prompt-loader.ts +92 -0
  79. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +25 -0
  80. package/dist/resources/extensions/gsd/prompts/complete-slice.md +27 -0
  81. package/dist/resources/extensions/gsd/prompts/discuss.md +237 -0
  82. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +29 -0
  83. package/dist/resources/extensions/gsd/prompts/execute-task.md +63 -0
  84. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -0
  85. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -0
  86. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +61 -0
  87. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +3 -0
  88. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +29 -0
  89. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -0
  90. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +13 -0
  91. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -0
  92. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +78 -0
  93. package/dist/resources/extensions/gsd/prompts/plan-slice.md +55 -0
  94. package/dist/resources/extensions/gsd/prompts/queue.md +100 -0
  95. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +48 -0
  96. package/dist/resources/extensions/gsd/prompts/replan-slice.md +39 -0
  97. package/dist/resources/extensions/gsd/prompts/research-milestone.md +37 -0
  98. package/dist/resources/extensions/gsd/prompts/research-slice.md +28 -0
  99. package/dist/resources/extensions/gsd/prompts/review-migration.md +66 -0
  100. package/dist/resources/extensions/gsd/prompts/run-uat.md +109 -0
  101. package/dist/resources/extensions/gsd/prompts/system.md +190 -0
  102. package/dist/resources/extensions/gsd/prompts/worktree-merge.md +123 -0
  103. package/dist/resources/extensions/gsd/roadmap-slices.ts +50 -0
  104. package/dist/resources/extensions/gsd/session-forensics.ts +500 -0
  105. package/dist/resources/extensions/gsd/skill-discovery.ts +137 -0
  106. package/dist/resources/extensions/gsd/state.ts +569 -0
  107. package/dist/resources/extensions/gsd/templates/context.md +76 -0
  108. package/dist/resources/extensions/gsd/templates/decisions.md +8 -0
  109. package/dist/resources/extensions/gsd/templates/milestone-summary.md +73 -0
  110. package/dist/resources/extensions/gsd/templates/plan.md +131 -0
  111. package/dist/resources/extensions/gsd/templates/preferences.md +23 -0
  112. package/dist/resources/extensions/gsd/templates/project.md +31 -0
  113. package/dist/resources/extensions/gsd/templates/reassessment.md +28 -0
  114. package/dist/resources/extensions/gsd/templates/requirements.md +81 -0
  115. package/dist/resources/extensions/gsd/templates/research.md +46 -0
  116. package/dist/resources/extensions/gsd/templates/roadmap.md +118 -0
  117. package/dist/resources/extensions/gsd/templates/secrets-manifest.md +22 -0
  118. package/dist/resources/extensions/gsd/templates/slice-context.md +58 -0
  119. package/dist/resources/extensions/gsd/templates/slice-summary.md +99 -0
  120. package/dist/resources/extensions/gsd/templates/state.md +19 -0
  121. package/dist/resources/extensions/gsd/templates/task-plan.md +52 -0
  122. package/dist/resources/extensions/gsd/templates/task-summary.md +57 -0
  123. package/dist/resources/extensions/gsd/templates/uat.md +54 -0
  124. package/dist/resources/extensions/gsd/tests/activity-log-prune.test.ts +297 -0
  125. package/dist/resources/extensions/gsd/tests/activity-log-save.test.ts +127 -0
  126. package/dist/resources/extensions/gsd/tests/auto-draft-pause.test.ts +109 -0
  127. package/dist/resources/extensions/gsd/tests/auto-preflight.test.ts +45 -0
  128. package/dist/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +196 -0
  129. package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +53 -0
  130. package/dist/resources/extensions/gsd/tests/collect-from-manifest.test.ts +469 -0
  131. package/dist/resources/extensions/gsd/tests/complete-milestone.test.ts +200 -0
  132. package/dist/resources/extensions/gsd/tests/cost-projection.test.ts +134 -0
  133. package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +312 -0
  134. package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +299 -0
  135. package/dist/resources/extensions/gsd/tests/derive-state.test.ts +660 -0
  136. package/dist/resources/extensions/gsd/tests/discuss-prompt.test.ts +27 -0
  137. package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +91 -0
  138. package/dist/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +170 -0
  139. package/dist/resources/extensions/gsd/tests/doctor.test.ts +594 -0
  140. package/dist/resources/extensions/gsd/tests/draft-promotion.test.ts +169 -0
  141. package/dist/resources/extensions/gsd/tests/exit-command.test.ts +50 -0
  142. package/dist/resources/extensions/gsd/tests/git-service.test.ts +1788 -0
  143. package/dist/resources/extensions/gsd/tests/idle-recovery.test.ts +577 -0
  144. package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +580 -0
  145. package/dist/resources/extensions/gsd/tests/manifest-status.test.ts +283 -0
  146. package/dist/resources/extensions/gsd/tests/metrics-io.test.ts +176 -0
  147. package/dist/resources/extensions/gsd/tests/metrics.test.ts +188 -0
  148. package/dist/resources/extensions/gsd/tests/migrate-command.test.ts +369 -0
  149. package/dist/resources/extensions/gsd/tests/migrate-parser.test.ts +757 -0
  150. package/dist/resources/extensions/gsd/tests/migrate-transformer.test.ts +635 -0
  151. package/dist/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +414 -0
  152. package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +297 -0
  153. package/dist/resources/extensions/gsd/tests/migrate-writer.test.ts +398 -0
  154. package/dist/resources/extensions/gsd/tests/must-have-parser.test.ts +291 -0
  155. package/dist/resources/extensions/gsd/tests/network-error-fallback.test.ts +54 -0
  156. package/dist/resources/extensions/gsd/tests/next-milestone-id.test.ts +66 -0
  157. package/dist/resources/extensions/gsd/tests/orphaned-branch.test.ts +353 -0
  158. package/dist/resources/extensions/gsd/tests/parsers.test.ts +1664 -0
  159. package/dist/resources/extensions/gsd/tests/plan-milestone.test.ts +133 -0
  160. package/dist/resources/extensions/gsd/tests/plan-quality-validator.test.ts +363 -0
  161. package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
  162. package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
  163. package/dist/resources/extensions/gsd/tests/queue-draft-detection.test.ts +126 -0
  164. package/dist/resources/extensions/gsd/tests/reassess-prompt.test.ts +142 -0
  165. package/dist/resources/extensions/gsd/tests/regex-hardening.test.ts +281 -0
  166. package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +155 -0
  167. package/dist/resources/extensions/gsd/tests/remote-status.test.ts +99 -0
  168. package/dist/resources/extensions/gsd/tests/replan-slice.test.ts +493 -0
  169. package/dist/resources/extensions/gsd/tests/requirements.test.ts +106 -0
  170. package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +35 -0
  171. package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +11 -0
  172. package/dist/resources/extensions/gsd/tests/roadmap-slices.test.ts +41 -0
  173. package/dist/resources/extensions/gsd/tests/run-uat.test.ts +316 -0
  174. package/dist/resources/extensions/gsd/tests/secure-env-collect.test.ts +185 -0
  175. package/dist/resources/extensions/gsd/tests/smart-entry-draft.test.ts +123 -0
  176. package/dist/resources/extensions/gsd/tests/test-helpers.ts +61 -0
  177. package/dist/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +219 -0
  178. package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +234 -0
  179. package/dist/resources/extensions/gsd/tests/workspace-index.test.ts +75 -0
  180. package/dist/resources/extensions/gsd/tests/worktree-integration.test.ts +234 -0
  181. package/dist/resources/extensions/gsd/tests/worktree-manager.test.ts +141 -0
  182. package/dist/resources/extensions/gsd/tests/worktree.test.ts +597 -0
  183. package/dist/resources/extensions/gsd/tests/write-gate.test.ts +122 -0
  184. package/dist/resources/extensions/gsd/types.ts +296 -0
  185. package/dist/resources/extensions/gsd/unit-runtime.ts +184 -0
  186. package/dist/resources/extensions/gsd/workspace-index.ts +189 -0
  187. package/dist/resources/extensions/gsd/worktree-command.ts +845 -0
  188. package/dist/resources/extensions/gsd/worktree-manager.ts +459 -0
  189. package/dist/resources/extensions/gsd/{worktree.js → worktree.ts} +92 -61
  190. package/dist/resources/extensions/mac-tools/index.ts +852 -0
  191. package/dist/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
  192. package/dist/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
  193. package/dist/resources/extensions/mcporter/index.ts +429 -0
  194. package/dist/resources/extensions/remote-questions/config.ts +81 -0
  195. package/dist/resources/extensions/remote-questions/discord-adapter.ts +128 -0
  196. package/dist/resources/extensions/remote-questions/format.ts +163 -0
  197. package/dist/resources/extensions/remote-questions/manager.ts +192 -0
  198. package/dist/resources/extensions/remote-questions/remote-command.ts +361 -0
  199. package/dist/resources/extensions/remote-questions/slack-adapter.ts +92 -0
  200. package/dist/resources/extensions/remote-questions/status.ts +31 -0
  201. package/dist/resources/extensions/remote-questions/store.ts +77 -0
  202. package/dist/resources/extensions/remote-questions/types.ts +75 -0
  203. package/dist/resources/extensions/search-the-web/cache.ts +78 -0
  204. package/dist/resources/extensions/search-the-web/command-search-provider.ts +99 -0
  205. package/dist/resources/extensions/search-the-web/format.ts +258 -0
  206. package/dist/resources/extensions/search-the-web/http.ts +238 -0
  207. package/dist/resources/extensions/search-the-web/index.ts +65 -0
  208. package/dist/resources/extensions/search-the-web/native-search.ts +165 -0
  209. package/dist/resources/extensions/search-the-web/provider.ts +136 -0
  210. package/dist/resources/extensions/search-the-web/tavily.ts +116 -0
  211. package/dist/resources/extensions/search-the-web/tool-fetch-page.ts +581 -0
  212. package/dist/resources/extensions/search-the-web/tool-llm-context.ts +620 -0
  213. package/dist/resources/extensions/search-the-web/tool-search.ts +635 -0
  214. package/dist/resources/extensions/search-the-web/url-utils.ts +91 -0
  215. package/dist/resources/extensions/shared/bundled-extension-paths.ts +11 -0
  216. package/dist/resources/extensions/shared/confirm-ui.ts +126 -0
  217. package/dist/resources/extensions/shared/interview-ui.ts +613 -0
  218. package/dist/resources/extensions/shared/next-action-ui.ts +197 -0
  219. package/dist/resources/extensions/shared/progress-widget.ts +282 -0
  220. package/dist/resources/extensions/shared/terminal.ts +23 -0
  221. package/dist/resources/extensions/shared/thinking-widget.ts +107 -0
  222. package/dist/resources/extensions/shared/ui.ts +400 -0
  223. package/dist/resources/extensions/shared/wizard-ui.ts +551 -0
  224. package/dist/resources/extensions/slash-commands/audit.ts +88 -0
  225. package/dist/resources/extensions/slash-commands/clear.ts +10 -0
  226. package/dist/resources/extensions/slash-commands/create-extension.ts +297 -0
  227. package/dist/resources/extensions/slash-commands/create-slash-command.ts +234 -0
  228. package/dist/resources/extensions/slash-commands/index.ts +12 -0
  229. package/dist/resources/extensions/subagent/agents.ts +126 -0
  230. package/dist/resources/extensions/subagent/index.ts +1072 -0
  231. package/dist/resources/extensions/subagent/isolation.ts +498 -0
  232. package/dist/resources/extensions/ttsr/index.ts +163 -0
  233. package/dist/resources/extensions/ttsr/rule-loader.ts +121 -0
  234. package/dist/resources/extensions/ttsr/ttsr-interrupt.md +6 -0
  235. package/dist/resources/extensions/ttsr/ttsr-manager.ts +430 -0
  236. package/dist/resources/extensions/universal-config/discovery.ts +78 -0
  237. package/dist/resources/extensions/universal-config/format.ts +160 -0
  238. package/dist/resources/extensions/universal-config/index.ts +118 -0
  239. package/dist/resources/extensions/universal-config/package.json +11 -0
  240. package/dist/resources/extensions/universal-config/scanners.ts +579 -0
  241. package/dist/resources/extensions/universal-config/tests/discovery.test.ts +111 -0
  242. package/dist/resources/extensions/universal-config/tests/format.test.ts +111 -0
  243. package/dist/resources/extensions/universal-config/tests/scanners.test.ts +438 -0
  244. package/dist/resources/extensions/universal-config/tools.ts +60 -0
  245. package/dist/resources/extensions/universal-config/types.ts +116 -0
  246. package/dist/resources/extensions/voice/index.ts +271 -0
  247. package/dist/resources/extensions/voice/speech-recognizer.py +504 -0
  248. package/dist/resources/extensions/voice/speech-recognizer.swift +154 -0
  249. package/dist/resources/skills/debug-like-expert/SKILL.md +231 -0
  250. package/dist/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
  251. package/dist/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
  252. package/dist/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
  253. package/dist/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
  254. package/dist/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
  255. package/dist/resources/skills/frontend-design/SKILL.md +45 -0
  256. package/dist/resources/skills/github-workflows/SKILL.md +92 -0
  257. package/dist/resources/skills/github-workflows/references/gh/SKILL.md +255 -0
  258. package/dist/resources/skills/github-workflows/references/gh/references/issue-stories.md +204 -0
  259. package/dist/resources/skills/github-workflows/references/gh/references/labels.md +170 -0
  260. package/dist/resources/skills/github-workflows/references/gh/references/milestones.md +158 -0
  261. package/dist/resources/skills/github-workflows/references/gh/references/projects-v2.md +177 -0
  262. package/dist/resources/skills/github-workflows/references/gh/scripts/experiment_cleanup.py +191 -0
  263. package/dist/resources/skills/github-workflows/references/gh/scripts/github_project_setup.py +799 -0
  264. package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
  265. package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +608 -0
  266. package/dist/resources/skills/swiftui/SKILL.md +208 -0
  267. package/dist/resources/skills/swiftui/references/animations.md +921 -0
  268. package/dist/resources/skills/swiftui/references/architecture.md +1561 -0
  269. package/dist/resources/skills/swiftui/references/layout-system.md +1186 -0
  270. package/dist/resources/skills/swiftui/references/navigation.md +1492 -0
  271. package/dist/resources/skills/swiftui/references/networking-async.md +214 -0
  272. package/dist/resources/skills/swiftui/references/performance.md +1706 -0
  273. package/dist/resources/skills/swiftui/references/platform-integration.md +204 -0
  274. package/dist/resources/skills/swiftui/references/state-management.md +1443 -0
  275. package/dist/resources/skills/swiftui/references/swiftdata.md +297 -0
  276. package/dist/resources/skills/swiftui/references/testing-debugging.md +247 -0
  277. package/dist/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
  278. package/dist/resources/skills/swiftui/workflows/add-feature.md +191 -0
  279. package/dist/resources/skills/swiftui/workflows/build-new-app.md +311 -0
  280. package/dist/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
  281. package/dist/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
  282. package/dist/resources/skills/swiftui/workflows/ship-app.md +203 -0
  283. package/dist/resources/skills/swiftui/workflows/write-tests.md +235 -0
  284. package/dist/wizard.js +1 -0
  285. package/package.json +8 -6
  286. package/packages/native/dist/fd/index.d.ts +1 -0
  287. package/packages/native/dist/fd/index.js +1 -0
  288. package/packages/native/dist/grep/index.d.ts +2 -1
  289. package/packages/native/dist/grep/index.js +1 -0
  290. package/packages/native/src/__tests__/fd.test.mjs +35 -0
  291. package/packages/native/src/__tests__/grep.test.mjs +26 -9
  292. package/packages/native/src/fd/index.ts +1 -0
  293. package/packages/native/src/grep/index.ts +3 -2
  294. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  295. package/packages/pi-agent-core/dist/agent-loop.js +169 -55
  296. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  297. package/packages/pi-agent-core/dist/agent.d.ts +13 -1
  298. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  299. package/packages/pi-agent-core/dist/agent.js +16 -0
  300. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  301. package/packages/pi-agent-core/dist/types.d.ts +91 -1
  302. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  303. package/packages/pi-agent-core/dist/types.js.map +1 -1
  304. package/packages/pi-agent-core/src/agent-loop.ts +273 -63
  305. package/packages/pi-agent-core/src/agent.ts +24 -0
  306. package/packages/pi-agent-core/src/types.ts +98 -0
  307. package/packages/pi-ai/dist/env-api-keys.js +2 -0
  308. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  309. package/packages/pi-ai/dist/models.generated.d.ts +314 -0
  310. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  311. package/packages/pi-ai/dist/models.generated.js +236 -0
  312. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  313. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  314. package/packages/pi-ai/dist/providers/google-gemini-cli.js +6 -0
  315. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  316. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  317. package/packages/pi-ai/dist/providers/openai-completions.js +2 -0
  318. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  319. package/packages/pi-ai/dist/types.d.ts +1 -1
  320. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  321. package/packages/pi-ai/dist/types.js.map +1 -1
  322. package/packages/pi-ai/src/env-api-keys.ts +2 -0
  323. package/packages/pi-ai/src/models.generated.ts +236 -0
  324. package/packages/pi-ai/src/providers/google-gemini-cli.ts +8 -0
  325. package/packages/pi-ai/src/providers/openai-completions.ts +3 -0
  326. package/packages/pi-ai/src/types.ts +2 -1
  327. package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  328. package/packages/pi-coding-agent/dist/cli/args.js +1 -0
  329. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  330. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +26 -0
  331. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/agent-session.js +137 -22
  333. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  334. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +20 -0
  335. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  336. package/packages/pi-coding-agent/dist/core/auth-storage.js +43 -0
  337. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  338. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts +51 -0
  339. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -0
  340. package/packages/pi-coding-agent/dist/core/fallback-resolver.js +119 -0
  341. package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -0
  342. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.d.ts +2 -0
  343. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.d.ts.map +1 -0
  344. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +183 -0
  345. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -0
  346. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  347. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  349. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  350. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  351. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
  352. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  353. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +12 -1
  354. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  355. package/packages/pi-coding-agent/dist/core/session-manager.js +37 -1
  356. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  357. package/packages/pi-coding-agent/dist/core/session-manager.test.d.ts +2 -0
  358. package/packages/pi-coding-agent/dist/core/session-manager.test.d.ts.map +1 -0
  359. package/packages/pi-coding-agent/dist/core/session-manager.test.js +61 -0
  360. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -0
  361. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  362. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  363. package/packages/pi-coding-agent/dist/core/settings-manager.js +47 -0
  364. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  365. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  366. package/packages/pi-coding-agent/dist/core/tools/find.js +1 -0
  367. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  368. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  369. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +6 -15
  370. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  371. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +18 -1
  372. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  373. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +46 -4
  374. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  375. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  376. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +25 -2
  377. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  378. package/packages/pi-coding-agent/src/cli/args.ts +1 -0
  379. package/packages/pi-coding-agent/src/core/agent-session.ts +167 -22
  380. package/packages/pi-coding-agent/src/core/auth-storage.ts +45 -0
  381. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +229 -0
  382. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +165 -0
  383. package/packages/pi-coding-agent/src/core/index.ts +1 -0
  384. package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
  385. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -0
  386. package/packages/pi-coding-agent/src/core/session-manager.ts +51 -1
  387. package/packages/pi-coding-agent/src/core/settings-manager.ts +66 -0
  388. package/packages/pi-coding-agent/src/core/tools/find.ts +1 -0
  389. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +6 -16
  390. package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +49 -4
  391. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +28 -2
  392. package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
  393. package/packages/pi-tui/dist/autocomplete.js +3 -4
  394. package/packages/pi-tui/dist/autocomplete.js.map +1 -1
  395. package/packages/pi-tui/dist/components/editor.d.ts +7 -0
  396. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  397. package/packages/pi-tui/dist/components/editor.js +57 -50
  398. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  399. package/packages/pi-tui/src/autocomplete.ts +3 -5
  400. package/packages/pi-tui/src/components/editor.ts +70 -49
  401. package/pkg/dist/core/export-html/ansi-to-html.d.ts +22 -0
  402. package/pkg/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
  403. package/pkg/dist/core/export-html/ansi-to-html.js +249 -0
  404. package/pkg/dist/core/export-html/ansi-to-html.js.map +1 -0
  405. package/pkg/dist/core/export-html/index.d.ts +37 -0
  406. package/pkg/dist/core/export-html/index.d.ts.map +1 -0
  407. package/pkg/dist/core/export-html/index.js +223 -0
  408. package/pkg/dist/core/export-html/index.js.map +1 -0
  409. package/pkg/dist/core/export-html/template.css +971 -0
  410. package/pkg/dist/core/export-html/template.html +54 -0
  411. package/pkg/dist/core/export-html/template.js +1583 -0
  412. package/pkg/dist/core/export-html/tool-renderer.d.ts +38 -0
  413. package/pkg/dist/core/export-html/tool-renderer.d.ts.map +1 -0
  414. package/pkg/dist/core/export-html/tool-renderer.js +70 -0
  415. package/pkg/dist/core/export-html/tool-renderer.js.map +1 -0
  416. package/pkg/dist/core/export-html/vendor/highlight.min.js +1213 -0
  417. package/pkg/dist/core/export-html/vendor/marked.min.js +6 -0
  418. package/scripts/postinstall.js +30 -17
  419. package/src/resources/extensions/bg-shell/index.ts +51 -7
  420. package/src/resources/extensions/gsd/activity-log.ts +61 -14
  421. package/src/resources/extensions/gsd/auto.ts +288 -19
  422. package/src/resources/extensions/gsd/commands.ts +9 -3
  423. package/src/resources/extensions/gsd/dashboard-overlay.ts +55 -12
  424. package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -0
  425. package/src/resources/extensions/gsd/doctor.ts +60 -3
  426. package/src/resources/extensions/gsd/files.ts +45 -1
  427. package/src/resources/extensions/gsd/git-service.ts +46 -41
  428. package/src/resources/extensions/gsd/guided-flow.ts +81 -9
  429. package/src/resources/extensions/gsd/index.ts +62 -1
  430. package/src/resources/extensions/gsd/native-git-bridge.ts +181 -0
  431. package/src/resources/extensions/gsd/paths.ts +35 -4
  432. package/src/resources/extensions/gsd/post-unit-hooks.ts +449 -0
  433. package/src/resources/extensions/gsd/preferences.ts +232 -1
  434. package/src/resources/extensions/gsd/prompt-loader.ts +45 -3
  435. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  436. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -3
  437. package/src/resources/extensions/gsd/prompts/discuss.md +10 -8
  438. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  439. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -1
  440. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -1
  441. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
  442. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +3 -1
  443. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +4 -2
  444. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -1
  445. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +3 -1
  446. package/src/resources/extensions/gsd/prompts/plan-milestone.md +9 -12
  447. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -3
  448. package/src/resources/extensions/gsd/prompts/queue.md +3 -1
  449. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  450. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  451. package/src/resources/extensions/gsd/state.ts +130 -18
  452. package/src/resources/extensions/gsd/templates/context.md +1 -1
  453. package/src/resources/extensions/gsd/templates/state.md +3 -3
  454. package/src/resources/extensions/gsd/tests/activity-log-save.test.ts +127 -0
  455. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +5 -1
  456. package/src/resources/extensions/gsd/tests/doctor.test.ts +115 -1
  457. package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +6 -2
  458. package/src/resources/extensions/gsd/tests/git-service.test.ts +35 -35
  459. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +8 -8
  460. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +4 -1
  461. package/src/resources/extensions/gsd/tests/network-error-fallback.test.ts +54 -0
  462. package/src/resources/extensions/gsd/tests/orphaned-branch.test.ts +5 -5
  463. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
  464. package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
  465. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +12 -0
  466. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +6 -0
  467. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +4 -4
  468. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +4 -4
  469. package/src/resources/extensions/gsd/tests/worktree.test.ts +19 -19
  470. package/src/resources/extensions/gsd/types.ts +109 -0
  471. package/src/resources/extensions/gsd/worktree-manager.ts +72 -13
  472. package/src/resources/extensions/gsd/worktree.ts +5 -4
  473. package/src/resources/extensions/search-the-web/command-search-provider.ts +8 -4
  474. package/src/resources/extensions/search-the-web/native-search.ts +32 -23
  475. package/src/resources/extensions/search-the-web/provider.ts +19 -2
  476. package/src/resources/extensions/search-the-web/tool-fetch-page.ts +62 -0
  477. package/src/resources/extensions/search-the-web/tool-llm-context.ts +62 -3
  478. package/src/resources/extensions/search-the-web/tool-search.ts +62 -3
  479. package/src/resources/extensions/shared/bundled-extension-paths.ts +11 -0
  480. package/src/resources/extensions/subagent/index.ts +2 -1
  481. package/src/resources/skills/github-workflows/SKILL.md +5 -0
  482. package/dist/resources/extensions/gsd/git-service.d.ts +0 -225
  483. package/dist/resources/extensions/gsd/git-service.js +0 -756
  484. package/dist/resources/extensions/gsd/preferences.d.ts +0 -122
  485. package/dist/resources/extensions/gsd/preferences.js +0 -616
  486. package/dist/resources/extensions/gsd/worktree.d.ts +0 -106
  487. package/dist/resources/extensions/remote-questions/config.d.ts +0 -14
  488. package/dist/resources/extensions/remote-questions/config.js +0 -68
  489. package/dist/resources/extensions/remote-questions/discord-adapter.d.ts +0 -17
  490. package/dist/resources/extensions/remote-questions/discord-adapter.js +0 -118
  491. package/dist/resources/extensions/remote-questions/format.d.ts +0 -38
  492. package/dist/resources/extensions/remote-questions/format.js +0 -119
  493. package/dist/resources/extensions/remote-questions/manager.d.ts +0 -23
  494. package/dist/resources/extensions/remote-questions/manager.js +0 -161
  495. package/dist/resources/extensions/remote-questions/remote-command.d.ts +0 -6
  496. package/dist/resources/extensions/remote-questions/remote-command.js +0 -358
  497. package/dist/resources/extensions/remote-questions/slack-adapter.d.ts +0 -15
  498. package/dist/resources/extensions/remote-questions/slack-adapter.js +0 -82
  499. package/dist/resources/extensions/remote-questions/status.d.ts +0 -9
  500. package/dist/resources/extensions/remote-questions/status.js +0 -25
  501. package/dist/resources/extensions/remote-questions/store.d.ts +0 -11
  502. package/dist/resources/extensions/remote-questions/store.js +0 -66
  503. package/dist/resources/extensions/remote-questions/types.d.ts +0 -68
  504. package/dist/resources/extensions/remote-questions/types.js +0 -4
@@ -0,0 +1,504 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ speech-recognizer.py — STT recognizer for Linux.
4
+
5
+ Emits line protocol on stdout (unbuffered):
6
+ READY — model loaded, mic active
7
+ PARTIAL:<text> — partial transcription update (during speech)
8
+ FINAL:<text> — finalized transcription (after pause/endpoint)
9
+ ERROR:<msg> — fatal error (human-readable)
10
+
11
+ Backend: Groq Whisper API (default) or local faster-whisper.
12
+ --backend=groq → Groq API (fast, accurate, requires GROQ_API_KEY)
13
+ --backend=local → Local faster-whisper (offline, slower on CPU)
14
+
15
+ Requires: sounddevice (pip install sounddevice)
16
+ System dep: libportaudio2 (sudo apt install libportaudio2)
17
+
18
+ Designed to be spawned by index.ts startRecognizer() and communicate
19
+ exclusively via the stdout line protocol above.
20
+ """
21
+
22
+ import io
23
+ import os
24
+ import signal
25
+ import subprocess
26
+ import struct
27
+ import sys
28
+ import time
29
+ import queue
30
+ import threading
31
+ import wave
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # Helpers
35
+ # ---------------------------------------------------------------------------
36
+
37
+ def emit(tag, msg=""):
38
+ """Emit a single protocol line, flushed immediately."""
39
+ if msg:
40
+ print(f"{tag}:{msg}", flush=True)
41
+ else:
42
+ print(tag, flush=True)
43
+
44
+
45
+ def _try_pip_install(*packages):
46
+ """Attempt pip install. Returns (success, error_detail)."""
47
+ try:
48
+ result = subprocess.run(
49
+ [sys.executable, "-m", "pip", "install", *packages, "--quiet"],
50
+ capture_output=True,
51
+ timeout=300,
52
+ )
53
+ if result.returncode == 0:
54
+ return True, ""
55
+ stderr = result.stderr.decode("utf-8", errors="replace").strip()
56
+ return False, stderr
57
+ except FileNotFoundError:
58
+ return False, "pip not found"
59
+ except subprocess.TimeoutExpired:
60
+ return False, "install timed out after 300s"
61
+ except Exception as exc:
62
+ return False, str(exc)
63
+
64
+
65
+ def ensure_deps():
66
+ """Import sounddevice, auto-installing if missing.
67
+
68
+ Returns True on success. On failure, emits ERROR: and returns False.
69
+ Never raises — all failures go through the line protocol.
70
+ """
71
+ try:
72
+ __import__("sounddevice")
73
+ __import__("requests")
74
+ return True
75
+ except ImportError:
76
+ pass
77
+
78
+ # Attempt install
79
+ ok, detail = _try_pip_install("sounddevice", "requests")
80
+ if not ok:
81
+ if "externally-managed" in detail.lower():
82
+ emit(
83
+ "ERROR",
84
+ "Python environment is externally managed (PEP 668). "
85
+ "Create a venv first: python3 -m venv ~/.gsd/voice-venv && "
86
+ "~/.gsd/voice-venv/bin/pip install sounddevice requests",
87
+ )
88
+ elif "pip not found" in detail:
89
+ emit("ERROR", "pip is not available. Install: sudo apt install python3-pip")
90
+ else:
91
+ emit("ERROR", f"Failed to install sounddevice: {detail}")
92
+ return False
93
+
94
+ # Verify import after install
95
+ try:
96
+ __import__("sounddevice")
97
+ __import__("requests")
98
+ return True
99
+ except ImportError as exc:
100
+ emit("ERROR", f"Packages installed but cannot import: {exc}")
101
+ return False
102
+
103
+
104
+ def audio_to_wav_bytes(audio_data, sample_rate=16000):
105
+ """Convert float32 numpy array to WAV bytes for API upload."""
106
+ import numpy as np
107
+ # Convert float32 [-1, 1] to int16
108
+ int16_data = (audio_data * 32767).astype(np.int16)
109
+ buf = io.BytesIO()
110
+ with wave.open(buf, "wb") as wf:
111
+ wf.setnchannels(1)
112
+ wf.setsampwidth(2)
113
+ wf.setframerate(sample_rate)
114
+ wf.writeframes(int16_data.tobytes())
115
+ return buf.getvalue()
116
+
117
+
118
+ # ---------------------------------------------------------------------------
119
+ # Audio capture (shared by all backends)
120
+ # ---------------------------------------------------------------------------
121
+
122
+ SAMPLE_RATE = 16000
123
+ BLOCK_DURATION = 0.5 # seconds per audio block
124
+ BLOCK_SIZE = int(SAMPLE_RATE * BLOCK_DURATION)
125
+ SILENCE_THRESHOLD = 0.01 # RMS threshold for silence detection
126
+ SILENCE_DURATION = 0.8 # seconds of silence before finalizing
127
+ MIN_SPEECH_DURATION = 0.3 # minimum speech duration to trigger transcription
128
+
129
+
130
+ def open_mic():
131
+ """Open mic stream and return (stream, audio_queue)."""
132
+ import sounddevice as sd
133
+
134
+ audio_queue = queue.Queue()
135
+
136
+ def audio_callback(indata, frames, time_info, status):
137
+ audio_queue.put(indata[:, 0].copy())
138
+
139
+ try:
140
+ stream = sd.InputStream(
141
+ samplerate=SAMPLE_RATE,
142
+ channels=1,
143
+ dtype="float32",
144
+ blocksize=BLOCK_SIZE,
145
+ callback=audio_callback,
146
+ )
147
+ stream.start()
148
+ return stream, audio_queue
149
+ except Exception as exc:
150
+ msg = str(exc).lower()
151
+ if "portaudio" in msg or "no module" in msg:
152
+ emit("ERROR", "Audio system not available. Install: sudo apt install libportaudio2")
153
+ else:
154
+ emit("ERROR", f"Failed to initialize microphone: {exc}")
155
+ sys.exit(1)
156
+
157
+
158
+ # ---------------------------------------------------------------------------
159
+ # Groq backend
160
+ # ---------------------------------------------------------------------------
161
+
162
+ def run_groq():
163
+ """Groq Whisper API backend — fast cloud transcription."""
164
+ import numpy as np
165
+ import requests
166
+
167
+ api_key = os.environ.get("GROQ_API_KEY", "")
168
+ if not api_key:
169
+ emit("ERROR", "GROQ_API_KEY not set. Run 'gsd config' to set up, or get a free key at https://console.groq.com")
170
+ sys.exit(1)
171
+
172
+ groq_model = os.environ.get("GSD_GROQ_MODEL", "whisper-large-v3-turbo")
173
+ api_url = "https://api.groq.com/openai/v1/audio/transcriptions"
174
+
175
+ # --- Signal handling ---
176
+ shutdown_requested = False
177
+
178
+ def _handle_signal(signum, frame):
179
+ nonlocal shutdown_requested
180
+ shutdown_requested = True
181
+
182
+ signal.signal(signal.SIGTERM, _handle_signal)
183
+ signal.signal(signal.SIGINT, _handle_signal)
184
+
185
+ def transcribe_audio(audio_data):
186
+ """Send audio to Groq API, return transcription text."""
187
+ wav_bytes = audio_to_wav_bytes(audio_data, SAMPLE_RATE)
188
+
189
+ try:
190
+ resp = requests.post(
191
+ api_url,
192
+ headers={"Authorization": f"Bearer {api_key}"},
193
+ files={"file": ("audio.wav", wav_bytes, "audio/wav")},
194
+ data={
195
+ "model": groq_model,
196
+ "language": "en",
197
+ "response_format": "json",
198
+ "temperature": "0.0",
199
+ },
200
+ timeout=10,
201
+ )
202
+ if resp.ok:
203
+ return resp.json().get("text", "").strip()
204
+ else:
205
+ emit("ERROR", f"Groq API error ({resp.status_code}): {resp.text[:200]}")
206
+ return ""
207
+ except requests.exceptions.Timeout:
208
+ emit("ERROR", "Groq API timeout")
209
+ return ""
210
+ except Exception as e:
211
+ emit("ERROR", f"Groq API connection error: {e}")
212
+ return ""
213
+
214
+ # --- Open mic ---
215
+ stream, audio_queue = open_mic()
216
+ emit("READY")
217
+
218
+ # --- State ---
219
+ completed_lines = []
220
+ speech_buffer = []
221
+ silence_counter = 0.0
222
+ in_speech = False
223
+
224
+ # Background transcription for partials
225
+ partial_lock = threading.Lock()
226
+ latest_partial = [None]
227
+ partial_thread = None
228
+ last_partial_time = 0.0
229
+
230
+ def _full_text(current=""):
231
+ parts = list(completed_lines)
232
+ if current:
233
+ parts.append(current)
234
+ return " ".join(parts)
235
+
236
+ def _transcribe_partial(audio_data):
237
+ try:
238
+ text = transcribe_audio(audio_data)
239
+ if text:
240
+ with partial_lock:
241
+ latest_partial[0] = text
242
+ except Exception:
243
+ pass
244
+
245
+ try:
246
+ while not shutdown_requested:
247
+ try:
248
+ block = audio_queue.get(timeout=0.2)
249
+ except queue.Empty:
250
+ with partial_lock:
251
+ if latest_partial[0] is not None:
252
+ emit("PARTIAL", _full_text(latest_partial[0]))
253
+ latest_partial[0] = None
254
+ continue
255
+
256
+ rms = float(np.sqrt(np.mean(block ** 2)))
257
+ is_speech = rms > SILENCE_THRESHOLD
258
+
259
+ if is_speech:
260
+ speech_buffer.append(block)
261
+ silence_counter = 0.0
262
+
263
+ if not in_speech:
264
+ in_speech = True
265
+
266
+ # Emit completed partial results
267
+ with partial_lock:
268
+ if latest_partial[0] is not None:
269
+ emit("PARTIAL", _full_text(latest_partial[0]))
270
+ latest_partial[0] = None
271
+
272
+ # Launch partial every ~2s, non-blocking
273
+ now = time.monotonic()
274
+ speech_duration = len(speech_buffer) * BLOCK_DURATION
275
+ can_partial = (
276
+ speech_duration >= 1.5
277
+ and now - last_partial_time >= 2.0
278
+ and (partial_thread is None or not partial_thread.is_alive())
279
+ )
280
+ if can_partial:
281
+ audio_data = np.concatenate(speech_buffer).copy()
282
+ partial_thread = threading.Thread(
283
+ target=_transcribe_partial,
284
+ args=(audio_data,),
285
+ daemon=True,
286
+ )
287
+ partial_thread.start()
288
+ last_partial_time = now
289
+ else:
290
+ if in_speech:
291
+ silence_counter += BLOCK_DURATION
292
+
293
+ if silence_counter >= SILENCE_DURATION:
294
+ speech_duration = len(speech_buffer) * BLOCK_DURATION
295
+ if speech_duration >= MIN_SPEECH_DURATION:
296
+ # Wait for any in-flight partial
297
+ if partial_thread is not None and partial_thread.is_alive():
298
+ partial_thread.join(timeout=5.0)
299
+
300
+ audio_data = np.concatenate(speech_buffer)
301
+ text = transcribe_audio(audio_data)
302
+ if text:
303
+ completed_lines.append(text)
304
+ emit("FINAL", _full_text())
305
+
306
+ speech_buffer.clear()
307
+ silence_counter = 0.0
308
+ in_speech = False
309
+ except Exception as exc:
310
+ emit("ERROR", f"Runtime error: {exc}")
311
+ sys.exit(1)
312
+ finally:
313
+ try:
314
+ stream.stop()
315
+ stream.close()
316
+ except Exception:
317
+ pass
318
+
319
+
320
+ # ---------------------------------------------------------------------------
321
+ # Local Whisper backend
322
+ # ---------------------------------------------------------------------------
323
+
324
+ def run_local():
325
+ """Local faster-whisper backend (offline, CPU)."""
326
+ import numpy as np
327
+ from faster_whisper import WhisperModel
328
+
329
+ # --- Signal handling ---
330
+ shutdown_requested = False
331
+
332
+ def _handle_signal(signum, frame):
333
+ nonlocal shutdown_requested
334
+ shutdown_requested = True
335
+
336
+ signal.signal(signal.SIGTERM, _handle_signal)
337
+ signal.signal(signal.SIGINT, _handle_signal)
338
+
339
+ # --- Load model ---
340
+ model_size = os.environ.get("GSD_WHISPER_MODEL", "small")
341
+ cache_root = os.path.join(
342
+ os.environ.get("XDG_CACHE_HOME", os.path.expanduser("~/.cache")),
343
+ "gsd", "whisper",
344
+ )
345
+ try:
346
+ model = WhisperModel(
347
+ model_size,
348
+ device="cpu",
349
+ compute_type="int8",
350
+ download_root=cache_root,
351
+ )
352
+ except Exception as exc:
353
+ emit("ERROR", f"Failed to load Whisper model ({model_size}): {exc}")
354
+ sys.exit(1)
355
+
356
+ # --- Open mic ---
357
+ stream, audio_queue = open_mic()
358
+ emit("READY")
359
+
360
+ # --- State ---
361
+ completed_lines = []
362
+ speech_buffer = []
363
+ silence_counter = 0.0
364
+ in_speech = False
365
+
366
+ partial_lock = threading.Lock()
367
+ latest_partial = [None]
368
+ partial_thread = None
369
+ last_partial_time = 0.0
370
+
371
+ def _full_text(current=""):
372
+ parts = list(completed_lines)
373
+ if current:
374
+ parts.append(current)
375
+ return " ".join(parts)
376
+
377
+ def _transcribe_partial(audio_data):
378
+ try:
379
+ segments, _ = model.transcribe(
380
+ audio_data, language="en", beam_size=1,
381
+ vad_filter=False, condition_on_previous_text=False,
382
+ )
383
+ text = " ".join(s.text.strip() for s in segments).strip()
384
+ if text:
385
+ with partial_lock:
386
+ latest_partial[0] = text
387
+ except Exception:
388
+ pass
389
+
390
+ try:
391
+ while not shutdown_requested:
392
+ try:
393
+ block = audio_queue.get(timeout=0.2)
394
+ except queue.Empty:
395
+ with partial_lock:
396
+ if latest_partial[0] is not None:
397
+ emit("PARTIAL", _full_text(latest_partial[0]))
398
+ latest_partial[0] = None
399
+ continue
400
+
401
+ rms = float(np.sqrt(np.mean(block ** 2)))
402
+ is_speech = rms > SILENCE_THRESHOLD
403
+
404
+ if is_speech:
405
+ speech_buffer.append(block)
406
+ silence_counter = 0.0
407
+
408
+ if not in_speech:
409
+ in_speech = True
410
+
411
+ with partial_lock:
412
+ if latest_partial[0] is not None:
413
+ emit("PARTIAL", _full_text(latest_partial[0]))
414
+ latest_partial[0] = None
415
+
416
+ now = time.monotonic()
417
+ speech_duration = len(speech_buffer) * BLOCK_DURATION
418
+ can_partial = (
419
+ speech_duration >= 1.5
420
+ and now - last_partial_time >= 2.0
421
+ and (partial_thread is None or not partial_thread.is_alive())
422
+ )
423
+ if can_partial:
424
+ audio_data = np.concatenate(speech_buffer).copy()
425
+ partial_thread = threading.Thread(
426
+ target=_transcribe_partial,
427
+ args=(audio_data,),
428
+ daemon=True,
429
+ )
430
+ partial_thread.start()
431
+ last_partial_time = now
432
+ else:
433
+ if in_speech:
434
+ silence_counter += BLOCK_DURATION
435
+
436
+ if silence_counter >= SILENCE_DURATION:
437
+ speech_duration = len(speech_buffer) * BLOCK_DURATION
438
+ if speech_duration >= MIN_SPEECH_DURATION:
439
+ if partial_thread is not None and partial_thread.is_alive():
440
+ partial_thread.join(timeout=5.0)
441
+
442
+ audio_data = np.concatenate(speech_buffer)
443
+ try:
444
+ segments, _ = model.transcribe(
445
+ audio_data, language="en", beam_size=5,
446
+ vad_filter=True,
447
+ )
448
+ text = " ".join(s.text.strip() for s in segments).strip()
449
+ if text:
450
+ completed_lines.append(text)
451
+ emit("FINAL", _full_text())
452
+ except Exception as exc:
453
+ emit("ERROR", f"Transcription error: {exc}")
454
+
455
+ speech_buffer.clear()
456
+ silence_counter = 0.0
457
+ in_speech = False
458
+ except Exception as exc:
459
+ emit("ERROR", f"Runtime error: {exc}")
460
+ sys.exit(1)
461
+ finally:
462
+ try:
463
+ stream.stop()
464
+ stream.close()
465
+ except Exception:
466
+ pass
467
+
468
+
469
+ # ---------------------------------------------------------------------------
470
+ # Entry point
471
+ # ---------------------------------------------------------------------------
472
+
473
+ def main():
474
+ backend = "groq"
475
+ for arg in sys.argv[1:]:
476
+ if arg == "--backend=groq":
477
+ backend = "groq"
478
+ elif arg == "--backend=local":
479
+ backend = "local"
480
+
481
+ if not ensure_deps():
482
+ sys.exit(1)
483
+
484
+ if backend == "local":
485
+ # Check for faster-whisper
486
+ try:
487
+ __import__("faster_whisper")
488
+ except ImportError:
489
+ ok, detail = _try_pip_install("faster-whisper")
490
+ if not ok:
491
+ if "externally-managed" in detail.lower():
492
+ emit("ERROR",
493
+ "Python environment is externally managed (PEP 668). "
494
+ "Install in your venv: pip install faster-whisper")
495
+ else:
496
+ emit("ERROR", f"Failed to install faster-whisper: {detail}")
497
+ sys.exit(1)
498
+ run_local()
499
+ else:
500
+ run_groq()
501
+
502
+
503
+ if __name__ == "__main__":
504
+ main()
@@ -0,0 +1,154 @@
1
+ import Foundation
2
+ import Speech
3
+ import AVFoundation
4
+
5
+ // Unbuffered stdout
6
+ setbuf(stdout, nil)
7
+
8
+ guard SFSpeechRecognizer.authorizationStatus() == .authorized ||
9
+ SFSpeechRecognizer.authorizationStatus() == .notDetermined else {
10
+ print("ERROR:Speech recognition not authorized")
11
+ exit(1)
12
+ }
13
+
14
+ SFSpeechRecognizer.requestAuthorization { status in
15
+ guard status == .authorized else {
16
+ print("ERROR:Speech recognition denied")
17
+ exit(1)
18
+ }
19
+ }
20
+
21
+ let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))!
22
+ guard recognizer.isAvailable else {
23
+ print("ERROR:Speech recognizer not available")
24
+ exit(1)
25
+ }
26
+
27
+ let audioEngine = AVAudioEngine()
28
+ let request = SFSpeechAudioBufferRecognitionRequest()
29
+ request.shouldReportPartialResults = true
30
+ request.requiresOnDeviceRecognition = true
31
+
32
+ let node = audioEngine.inputNode
33
+ let format = node.outputFormat(forBus: 0)
34
+
35
+ node.installTap(onBus: 0, bufferSize: 1024, format: format) { buffer, _ in
36
+ request.append(buffer)
37
+ }
38
+
39
+ audioEngine.prepare()
40
+ do {
41
+ try audioEngine.start()
42
+ print("READY")
43
+ } catch {
44
+ print("ERROR:Failed to start audio engine: \(error.localizedDescription)")
45
+ exit(1)
46
+ }
47
+
48
+ // Accumulated finalized text from previous recognition segments.
49
+ // On-device recognition (especially macOS/iOS 18+) can reset
50
+ // bestTranscription.formattedString after a pause, discarding
51
+ // previous text. We detect this by tracking the last known good
52
+ // text and noticing when the new text is shorter / doesn't start
53
+ // with the previous text. When that happens we treat the previous
54
+ // text as finalized and start accumulating the new segment on top.
55
+ var accumulated = ""
56
+ var lastPartialText = ""
57
+ var lastEmitted = ""
58
+
59
+ recognizer.recognitionTask(with: request) { result, error in
60
+ if let result = result {
61
+ let text = result.bestTranscription.formattedString
62
+
63
+ if result.isFinal {
64
+ // True final from the recognizer — commit everything
65
+ let full: String
66
+ // Check if the final text already includes accumulated content
67
+ // (some OS versions give cumulative finals, others reset)
68
+ if !accumulated.isEmpty && !text.lowercased().hasPrefix(accumulated.lowercased()) {
69
+ full = accumulated + " " + text
70
+ } else if !accumulated.isEmpty && text.count < accumulated.count {
71
+ // Final is shorter than what we accumulated — use accumulated + new
72
+ full = accumulated + " " + text
73
+ } else {
74
+ full = text
75
+ }
76
+ accumulated = ""
77
+ lastPartialText = ""
78
+ if full != lastEmitted {
79
+ lastEmitted = full
80
+ print("FINAL:\(full)")
81
+ }
82
+ return
83
+ }
84
+
85
+ // Detect transcription reset: if the new partial text is significantly
86
+ // shorter than what we had, or doesn't start with the previous text,
87
+ // the recognizer has reset after a pause. Finalize what we had.
88
+ let prevText = lastPartialText
89
+ if !prevText.isEmpty && !text.isEmpty {
90
+ let prevWords = prevText.split(separator: " ")
91
+ let newWords = text.split(separator: " ")
92
+
93
+ // Reset detection: new text has fewer words than previous AND
94
+ // the first few words don't match (i.e. it's truly new speech,
95
+ // not just the recognizer revising the last word)
96
+ let looksLikeReset: Bool
97
+ if newWords.count < prevWords.count / 2 {
98
+ // Significant drop in word count — likely a reset
99
+ looksLikeReset = true
100
+ } else if newWords.count < prevWords.count &&
101
+ !prevWords.isEmpty && !newWords.isEmpty &&
102
+ newWords[0] != prevWords[0] {
103
+ // Different starting word + fewer words — reset
104
+ looksLikeReset = true
105
+ } else {
106
+ looksLikeReset = false
107
+ }
108
+
109
+ if looksLikeReset {
110
+ // Commit the previous partial text to accumulated
111
+ if accumulated.isEmpty {
112
+ accumulated = prevText
113
+ } else {
114
+ accumulated = accumulated + " " + prevText
115
+ }
116
+ // Emit a FINAL for the committed text so the TS side updates
117
+ print("FINAL:\(accumulated)")
118
+ lastEmitted = accumulated
119
+ }
120
+ }
121
+
122
+ lastPartialText = text
123
+
124
+ // Build the full display text
125
+ let displayText: String
126
+ if accumulated.isEmpty {
127
+ displayText = text
128
+ } else {
129
+ displayText = accumulated + " " + text
130
+ }
131
+
132
+ if displayText != lastEmitted {
133
+ lastEmitted = displayText
134
+ print("PARTIAL:\(displayText)")
135
+ }
136
+ }
137
+ if let error = error {
138
+ // Task finished errors are normal on kill
139
+ let nsError = error as NSError
140
+ if nsError.code != 216 { // kAFAssistantErrorDomain code for cancelled
141
+ print("ERROR:\(error.localizedDescription)")
142
+ }
143
+ }
144
+ }
145
+
146
+ // Handle SIGTERM/SIGINT gracefully
147
+ signal(SIGTERM) { _ in
148
+ exit(0)
149
+ }
150
+ signal(SIGINT) { _ in
151
+ exit(0)
152
+ }
153
+
154
+ RunLoop.current.run()