@opencue/cli 0.0.0-stage → 1.0.40

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 (485) hide show
  1. package/LICENSE.md +12 -0
  2. package/README.md +625 -2
  3. package/bin/dscode.exe +12 -0
  4. package/bin/stt/requirements.txt +32 -0
  5. package/bin/stt/stt_server.py +619 -0
  6. package/bin/tts/requirements.txt +21 -0
  7. package/bin/tts/tts_server.py +404 -0
  8. package/cli-wrapper.cjs +109 -0
  9. package/install.cjs +177 -0
  10. package/llms.txt +88 -0
  11. package/package.json +56 -4
  12. package/scripts/figure/compose.py +363 -0
  13. package/scripts/figure/replay-shots.mjs +205 -0
  14. package/web/dist/assets/AssistantsView-BiUiWjhF.js +1 -0
  15. package/web/dist/assets/AutomationView-Dcf_yNaI.js +1 -0
  16. package/web/dist/assets/ChannelConfigView-BLnxsMGm.js +8 -0
  17. package/web/dist/assets/ConnectorsView-CX3E6X6c.js +1 -0
  18. package/web/dist/assets/DesignSystemView--x-P-lpD.js +1 -0
  19. package/web/dist/assets/Drawer-CjAgqH3B.js +1 -0
  20. package/web/dist/assets/FileTreeView-Chb_fzTK.js +11 -0
  21. package/web/dist/assets/HookConfigView-EafYlWdN.js +1 -0
  22. package/web/dist/assets/InputArea-BbHslX7b.js +50 -0
  23. package/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  24. package/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  25. package/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  26. package/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  27. package/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  28. package/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  29. package/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  30. package/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  31. package/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  32. package/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  33. package/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  34. package/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  35. package/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  36. package/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  37. package/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  38. package/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  39. package/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  40. package/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  41. package/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  42. package/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  43. package/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  44. package/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  45. package/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  46. package/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  47. package/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  48. package/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  49. package/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  50. package/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  51. package/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  52. package/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  53. package/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  54. package/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  55. package/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  56. package/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  57. package/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  58. package/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  59. package/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  60. package/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  61. package/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  62. package/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  63. package/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  64. package/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  65. package/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  66. package/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  67. package/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  68. package/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  69. package/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  70. package/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  71. package/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  72. package/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  73. package/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  74. package/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  75. package/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  76. package/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  77. package/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  78. package/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  79. package/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  80. package/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  81. package/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  82. package/web/dist/assets/ModelsView-CGN5Nljr.js +1 -0
  83. package/web/dist/assets/PluginsView-CDiJgvI8.js +2 -0
  84. package/web/dist/assets/ProjectsView-C5Usmwqy.js +1 -0
  85. package/web/dist/assets/SessionGrid-BGpz0-op.css +1 -0
  86. package/web/dist/assets/SessionGrid-Drxg0r_u.js +4 -0
  87. package/web/dist/assets/SettingsModal-Cmts6aBG.js +10 -0
  88. package/web/dist/assets/Skeleton-Dsk6B0U3.js +1 -0
  89. package/web/dist/assets/SkillsView-TEDR_3XX.js +1 -0
  90. package/web/dist/assets/TemplatesTab-DtN5Kdgh.js +1 -0
  91. package/web/dist/assets/ToolsView-VukZnIt1.js +1 -0
  92. package/web/dist/assets/VizCardsSkeleton-C_GaEfXd.js +1 -0
  93. package/web/dist/assets/abap-BdImnpbu.js +1 -0
  94. package/web/dist/assets/abnfDiagram-YUKMZFIV-BIFw6B_N.js +1 -0
  95. package/web/dist/assets/actionscript-3-B3316cI-.js +1 -0
  96. package/web/dist/assets/ada-bCR0ucgS.js +1 -0
  97. package/web/dist/assets/ahk-CsyLZFj1.js +1 -0
  98. package/web/dist/assets/ahk2-8Zs4aa1G.js +1 -0
  99. package/web/dist/assets/andromeeda-C4gqWexZ.js +1 -0
  100. package/web/dist/assets/angular-html-DA-rfuFy.js +1 -0
  101. package/web/dist/assets/angular-ts-BrjP3tb8.js +1 -0
  102. package/web/dist/assets/apache-Pmp26Uib.js +1 -0
  103. package/web/dist/assets/apex-DhZFqWV2.js +1 -0
  104. package/web/dist/assets/apl-CORt7UWP.js +1 -0
  105. package/web/dist/assets/applescript-Co6uUVPk.js +1 -0
  106. package/web/dist/assets/ara-BRHolxvo.js +1 -0
  107. package/web/dist/assets/arc-BZQ951h9.js +1 -0
  108. package/web/dist/assets/architectureDiagram-47P4ROYG-BP5qiXzf.js +36 -0
  109. package/web/dist/assets/asciidoc-CSVQ5wI8.js +1 -0
  110. package/web/dist/assets/asm-D_Q5rh1f.js +1 -0
  111. package/web/dist/assets/astro-HNnZUWAn.js +1 -0
  112. package/web/dist/assets/aurora-x-D-2ljcwZ.js +1 -0
  113. package/web/dist/assets/awk-DMzUqQB5.js +1 -0
  114. package/web/dist/assets/ayu-dark-DYE7WIF3.js +1 -0
  115. package/web/dist/assets/ayu-light-BA47KaF1.js +1 -0
  116. package/web/dist/assets/ayu-mirage-32ctXXKs.js +1 -0
  117. package/web/dist/assets/ballerina-BFfxhgS-.js +1 -0
  118. package/web/dist/assets/bat-CickPsom.js +1 -0
  119. package/web/dist/assets/beancount-k_qm7-4y.js +1 -0
  120. package/web/dist/assets/berry-uYugtg8r.js +1 -0
  121. package/web/dist/assets/bibtex-CHM0blh-.js +1 -0
  122. package/web/dist/assets/bicep-Bmn6On1c.js +1 -0
  123. package/web/dist/assets/bird2-Bx8U0n9b.js +1 -0
  124. package/web/dist/assets/blade-2xfisSek.js +1 -0
  125. package/web/dist/assets/blockDiagram-E7TT5TSB-DtRpcE7F.js +140 -0
  126. package/web/dist/assets/bsl-DlhNcFeZ.js +1 -0
  127. package/web/dist/assets/c-BIGW1oBm.js +1 -0
  128. package/web/dist/assets/c3-Dp5svz6Z.js +1 -0
  129. package/web/dist/assets/c4Diagram-CRA5TL53-Gdzn8UBh.js +38 -0
  130. package/web/dist/assets/cadence-Bv_4Rxtq.js +1 -0
  131. package/web/dist/assets/cairo-KRGpt6FW.js +1 -0
  132. package/web/dist/assets/catppuccin-frappe-CZL1YF0i.js +1 -0
  133. package/web/dist/assets/catppuccin-latte-DH-8KZSZ.js +1 -0
  134. package/web/dist/assets/catppuccin-macchiato-B7yYVSCf.js +1 -0
  135. package/web/dist/assets/catppuccin-mocha-Ct7hS0mc.js +1 -0
  136. package/web/dist/assets/channel-BND6_KSH.js +1 -0
  137. package/web/dist/assets/chapel-DTp_pixX.js +1 -0
  138. package/web/dist/assets/chunk-2Q5K7J3B-3U6HMlsm.js +1 -0
  139. package/web/dist/assets/chunk-5VM5RSS4-CYl9mwa-.js +15 -0
  140. package/web/dist/assets/chunk-7TKQ45FW-Dn6ktcY5.js +1 -0
  141. package/web/dist/assets/chunk-AW2ZBBNX-De0QX6p1.js +88 -0
  142. package/web/dist/assets/chunk-FVRAUYC3-CpXDfvz4.js +2 -0
  143. package/web/dist/assets/chunk-HTAEGDNF-D1KDvcDd.js +1 -0
  144. package/web/dist/assets/chunk-JWPE2WC7-umm4A-fq.js +1 -0
  145. package/web/dist/assets/chunk-KQW6MTUR-JYH94hpE.js +1 -0
  146. package/web/dist/assets/chunk-XXDRQBXY-CSlCFByc.js +1 -0
  147. package/web/dist/assets/clarity-Dn5IMItf.js +1 -0
  148. package/web/dist/assets/classDiagram-v2-K4WV4PDN-DnFwS0qN.js +217 -0
  149. package/web/dist/assets/clojure-P80f7IUj.js +1 -0
  150. package/web/dist/assets/cmake-D1j8_8rp.js +1 -0
  151. package/web/dist/assets/cobol-nBiQ_Alo.js +1 -0
  152. package/web/dist/assets/codeowners-Bp6g37R7.js +1 -0
  153. package/web/dist/assets/codeql-DsOJ9woJ.js +1 -0
  154. package/web/dist/assets/coffee-Ch7k5sss.js +1 -0
  155. package/web/dist/assets/common-lisp-Cg-RD9OK.js +1 -0
  156. package/web/dist/assets/coq-C7JzOVbR.js +1 -0
  157. package/web/dist/assets/cose-bilkent-JH36ORCC-BxUTUyep.js +1 -0
  158. package/web/dist/assets/cpp-BMRokrvK.js +1 -0
  159. package/web/dist/assets/crystal-DGywbUpC.js +1 -0
  160. package/web/dist/assets/csharp-DSvCPggb.js +1 -0
  161. package/web/dist/assets/css-CLj8gQPS.js +1 -0
  162. package/web/dist/assets/csv-fuZLfV_i.js +1 -0
  163. package/web/dist/assets/cue-D82EKSYY.js +1 -0
  164. package/web/dist/assets/cynefin-EF2NZ3EQ-CiMvulJr.js +141 -0
  165. package/web/dist/assets/cynefinDiagram-3GCD6N5R-DuXFORdW.js +62 -0
  166. package/web/dist/assets/cypher-COkxafJQ.js +1 -0
  167. package/web/dist/assets/cytoscape.esm-Ix0LnXOy.js +331 -0
  168. package/web/dist/assets/d-85-TOEBH.js +1 -0
  169. package/web/dist/assets/dagre-W4DXFKR2-DzMZHXci.js +4 -0
  170. package/web/dist/assets/dark-plus-C3mMm8J8.js +1 -0
  171. package/web/dist/assets/dart-bE4Kk8sk.js +1 -0
  172. package/web/dist/assets/dax-CEL-wOlO.js +1 -0
  173. package/web/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  174. package/web/dist/assets/desktop-BmXAJ9_W.js +1 -0
  175. package/web/dist/assets/diagram-2UJZ2QOL-B6tO5G1v.js +200 -0
  176. package/web/dist/assets/diagram-OVF4WLC6-DRZt8tGc.js +24 -0
  177. package/web/dist/assets/diagram-PFPMY2P6-DGh6IecR.js +30 -0
  178. package/web/dist/assets/diagram-UMYRVEAY-BLbnt0yT.js +24 -0
  179. package/web/dist/assets/diagram-YEKJPTXX-C-S5DVhj.js +41 -0
  180. package/web/dist/assets/diagram-ZIFT7M5P-JrGHTWbo.js +3 -0
  181. package/web/dist/assets/diff-D97Zzqfu.js +1 -0
  182. package/web/dist/assets/docker-BcOcwvcX.js +1 -0
  183. package/web/dist/assets/dotenv-Da5cRb03.js +1 -0
  184. package/web/dist/assets/dracula-BzJJZx-M.js +1 -0
  185. package/web/dist/assets/dracula-soft-BXkSAIEj.js +1 -0
  186. package/web/dist/assets/dream-maker-BtqSS_iP.js +1 -0
  187. package/web/dist/assets/ebnfDiagram-VR2GEFS7-DPXA-YOi.js +1 -0
  188. package/web/dist/assets/edge-FbVlp4U3.js +1 -0
  189. package/web/dist/assets/elixir-CkH2-t6x.js +1 -0
  190. package/web/dist/assets/elk-IJKZMXRS-CINeWt2W.js +27 -0
  191. package/web/dist/assets/elm-DbKCFpqz.js +1 -0
  192. package/web/dist/assets/emacs-lisp-C_m_b--Z.js +1 -0
  193. package/web/dist/assets/erDiagram-O2IAPWRE-PPaHmqA1.js +99 -0
  194. package/web/dist/assets/erb-DXfck5VN.js +1 -0
  195. package/web/dist/assets/erlang-DsQrWhSR.js +1 -0
  196. package/web/dist/assets/everforest-dark-BgDCqdQA.js +1 -0
  197. package/web/dist/assets/everforest-light-C8M2exoo.js +1 -0
  198. package/web/dist/assets/fennel-BYunw83y.js +1 -0
  199. package/web/dist/assets/fish-BvzEVeQv.js +1 -0
  200. package/web/dist/assets/flowDiagram-OXPTDLAJ-t-u0QXEA.js +213 -0
  201. package/web/dist/assets/fluent-C4IJs8-o.js +1 -0
  202. package/web/dist/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  203. package/web/dist/assets/fortran-free-form-BxgE0vQu.js +1 -0
  204. package/web/dist/assets/fsharp-CXgrBDvD.js +1 -0
  205. package/web/dist/assets/ganttDiagram-R7TSEDQI-Bw49ZD_b.js +292 -0
  206. package/web/dist/assets/gdresource-TyuKm33G.js +1 -0
  207. package/web/dist/assets/gdscript-DqcFQ5yU.js +1 -0
  208. package/web/dist/assets/gdshader-DkwncUOv.js +1 -0
  209. package/web/dist/assets/genie-D0YGMca9.js +1 -0
  210. package/web/dist/assets/gherkin-DyxjwDmM.js +1 -0
  211. package/web/dist/assets/git-commit-F4YmCXRG.js +1 -0
  212. package/web/dist/assets/git-rebase-r7XF79zn.js +1 -0
  213. package/web/dist/assets/gitGraphDiagram-XJZIOB7I-BAfOqeeg.js +106 -0
  214. package/web/dist/assets/github-dark-DHJKELXO.js +1 -0
  215. package/web/dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
  216. package/web/dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  217. package/web/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  218. package/web/dist/assets/github-light-DAi9KRSo.js +1 -0
  219. package/web/dist/assets/github-light-default-D7oLnXFd.js +1 -0
  220. package/web/dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  221. package/web/dist/assets/gleam-BspZqrRM.js +1 -0
  222. package/web/dist/assets/glimmer-js-ByusRIyA.js +1 -0
  223. package/web/dist/assets/glimmer-ts-BfAWNZQY.js +1 -0
  224. package/web/dist/assets/glsl-DplSGwfg.js +1 -0
  225. package/web/dist/assets/gn-n2N0HUVH.js +1 -0
  226. package/web/dist/assets/gnuplot-DdkO51Og.js +1 -0
  227. package/web/dist/assets/go-C27-OAKa.js +1 -0
  228. package/web/dist/assets/graph-Bn3Yngep.js +1 -0
  229. package/web/dist/assets/graphql-ChdNCCLP.js +1 -0
  230. package/web/dist/assets/groovy-gcz8RCvz.js +1 -0
  231. package/web/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  232. package/web/dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  233. package/web/dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  234. package/web/dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  235. package/web/dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  236. package/web/dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  237. package/web/dist/assets/hack-BWmVpMyf.js +1 -0
  238. package/web/dist/assets/haml-D5jkg6IW.js +1 -0
  239. package/web/dist/assets/handlebars-BpdQsYii.js +1 -0
  240. package/web/dist/assets/haskell-Df6bDoY_.js +1 -0
  241. package/web/dist/assets/haxe-CfZj7gIn.js +1 -0
  242. package/web/dist/assets/hcl-BWvSN4gD.js +1 -0
  243. package/web/dist/assets/hjson-D5-asLiD.js +1 -0
  244. package/web/dist/assets/hlsl-D3lLCCz7.js +1 -0
  245. package/web/dist/assets/horizon-BUw7H-hv.js +1 -0
  246. package/web/dist/assets/horizon-bright-CUuTKBJd.js +1 -0
  247. package/web/dist/assets/houston-DnULxvSX.js +1 -0
  248. package/web/dist/assets/html-derivative-DlHx6ybY.js +1 -0
  249. package/web/dist/assets/html-pp8916En.js +1 -0
  250. package/web/dist/assets/http-jrhK8wxY.js +1 -0
  251. package/web/dist/assets/hurl-irOxFIW8.js +1 -0
  252. package/web/dist/assets/hxml-2-FPmUDs.js +1 -0
  253. package/web/dist/assets/hy-DFXneXwc.js +1 -0
  254. package/web/dist/assets/icons-Bm_ZzSAy.js +964 -0
  255. package/web/dist/assets/imba-DGztddWO.js +1 -0
  256. package/web/dist/assets/index-CeeLdENM.js +677 -0
  257. package/web/dist/assets/index-Ceez9lYk.css +1 -0
  258. package/web/dist/assets/infoDiagram-5W2HQ5XZ-Bv4RBxYW.js +2 -0
  259. package/web/dist/assets/ini-BEwlwnbL.js +1 -0
  260. package/web/dist/assets/init-Gi6I4Gst.js +1 -0
  261. package/web/dist/assets/ishikawaDiagram-K3B6WC7H-DEpj0bRp.js +70 -0
  262. package/web/dist/assets/java-CylS5w8V.js +1 -0
  263. package/web/dist/assets/javascript-wDzz0qaB.js +1 -0
  264. package/web/dist/assets/jinja-f2NsQr07.js +1 -0
  265. package/web/dist/assets/jison-wvAkD_A8.js +1 -0
  266. package/web/dist/assets/journeyDiagram-COXZFDF6-MJu84Iiz.js +139 -0
  267. package/web/dist/assets/json-Cp-IABpG.js +1 -0
  268. package/web/dist/assets/json5-C9tS-k6U.js +1 -0
  269. package/web/dist/assets/jsonc-Des-eS-w.js +1 -0
  270. package/web/dist/assets/jsonl-DcaNXYhu.js +1 -0
  271. package/web/dist/assets/jsonnet-DFQXde-d.js +1 -0
  272. package/web/dist/assets/jssm-C2t-YnRu.js +1 -0
  273. package/web/dist/assets/jsx-g9-lgVsj.js +1 -0
  274. package/web/dist/assets/julia-5Bft2YPA.js +1 -0
  275. package/web/dist/assets/just-Cwhn7H3k.js +1 -0
  276. package/web/dist/assets/kanagawa-dragon-BuwD2xS4.js +1 -0
  277. package/web/dist/assets/kanagawa-lotus-C3DzagqV.js +1 -0
  278. package/web/dist/assets/kanagawa-wave-DFGoQZhC.js +1 -0
  279. package/web/dist/assets/kanban-definition-P3RFRI5V-mlYSRALK.js +89 -0
  280. package/web/dist/assets/kdl-DV7GczEv.js +1 -0
  281. package/web/dist/assets/kotlin-BdnUsdx6.js +1 -0
  282. package/web/dist/assets/kusto-wEQ09or8.js +1 -0
  283. package/web/dist/assets/laserwave-DUszq2jm.js +1 -0
  284. package/web/dist/assets/latex-D5pSuvFb.js +1 -0
  285. package/web/dist/assets/lean-BZvkOJ9d.js +1 -0
  286. package/web/dist/assets/less-B1dDrJ26.js +1 -0
  287. package/web/dist/assets/light-plus-B7mTdjB0.js +1 -0
  288. package/web/dist/assets/linear-5j9gt8MV.js +1 -0
  289. package/web/dist/assets/liquid-C0sCDyMI.js +1 -0
  290. package/web/dist/assets/llvm-BZoOZj88.js +1 -0
  291. package/web/dist/assets/log-2UxHyX5q.js +1 -0
  292. package/web/dist/assets/logo-BtOb2qkB.js +1 -0
  293. package/web/dist/assets/lua-BaeVxFsk.js +1 -0
  294. package/web/dist/assets/luau-BnpPk5vE.js +1 -0
  295. package/web/dist/assets/make-CHLpvVh8.js +1 -0
  296. package/web/dist/assets/markdown-BWXjRrSw.js +30 -0
  297. package/web/dist/assets/markdown-Cvjx9yec.js +1 -0
  298. package/web/dist/assets/marko-DjSrsDqO.js +1 -0
  299. package/web/dist/assets/material-theme-D5KoaKCx.js +1 -0
  300. package/web/dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
  301. package/web/dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  302. package/web/dist/assets/material-theme-ocean-CyktbL80.js +1 -0
  303. package/web/dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  304. package/web/dist/assets/matlab-D7o27uSR.js +1 -0
  305. package/web/dist/assets/mdc-D1_yUvq7.js +1 -0
  306. package/web/dist/assets/mdx-Cmh6b_Ma.js +1 -0
  307. package/web/dist/assets/mermaid-CQcHuHx7.js +1 -0
  308. package/web/dist/assets/mermaid.core-DLb6eAON.js +314 -0
  309. package/web/dist/assets/min-dark-CafNBF8u.js +1 -0
  310. package/web/dist/assets/min-light-CTRr51gU.js +1 -0
  311. package/web/dist/assets/mindmap-definition-LZFPQGKD-C9v_57Ex.js +96 -0
  312. package/web/dist/assets/mipsasm-CKIfxQSi.js +1 -0
  313. package/web/dist/assets/mojo-DJz3ZmWd.js +1 -0
  314. package/web/dist/assets/monokai-BRVnQi9A.js +1 -0
  315. package/web/dist/assets/moonbit-CHtswR0a.js +1 -0
  316. package/web/dist/assets/move-el3G9tDJ.js +1 -0
  317. package/web/dist/assets/narrat-DRg8JJMk.js +1 -0
  318. package/web/dist/assets/nextflow-C-mBbutL.js +1 -0
  319. package/web/dist/assets/nextflow-groovy-vE_lwT2v.js +1 -0
  320. package/web/dist/assets/nginx-BpAMiNFr.js +1 -0
  321. package/web/dist/assets/night-owl-C39BiMTA.js +1 -0
  322. package/web/dist/assets/night-owl-light-CMTm3GFP.js +1 -0
  323. package/web/dist/assets/nim-BIad80T-.js +1 -0
  324. package/web/dist/assets/nix-CwoSXNpI.js +1 -0
  325. package/web/dist/assets/nord-Ddv68eIx.js +1 -0
  326. package/web/dist/assets/nsis-BlV79W_Q.js +1 -0
  327. package/web/dist/assets/nushell-D3jzshHO.js +1 -0
  328. package/web/dist/assets/objective-c-DXmwc3jG.js +1 -0
  329. package/web/dist/assets/objective-cpp-CLxacb5B.js +1 -0
  330. package/web/dist/assets/ocaml-C0hk2d4L.js +1 -0
  331. package/web/dist/assets/odin-BBf5iR-q.js +1 -0
  332. package/web/dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  333. package/web/dist/assets/one-light-C3Wv6jpd.js +1 -0
  334. package/web/dist/assets/openscad-C4EeE6gA.js +1 -0
  335. package/web/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  336. package/web/dist/assets/org-DM6o9KBp.js +1 -0
  337. package/web/dist/assets/panels-BQOvnbWH.js +1 -0
  338. package/web/dist/assets/pascal-D93ZcfNL.js +1 -0
  339. package/web/dist/assets/pegDiagram-BGZESJAR-KQP26s3-.js +1 -0
  340. package/web/dist/assets/perl-B9cMNwum.js +1 -0
  341. package/web/dist/assets/php-Csjmro_R.js +1 -0
  342. package/web/dist/assets/pieDiagram-CAPJLFHJ-DN3RQ_ih.js +39 -0
  343. package/web/dist/assets/pkl-u5AG7uiY.js +1 -0
  344. package/web/dist/assets/plastic-3e1v2bzS.js +1 -0
  345. package/web/dist/assets/plsql-ChMvpjG-.js +1 -0
  346. package/web/dist/assets/po-BTJTHyun.js +1 -0
  347. package/web/dist/assets/poimandres-CS3Unz2-.js +1 -0
  348. package/web/dist/assets/polar-C0HS_06l.js +1 -0
  349. package/web/dist/assets/postcss-CXtECtnM.js +1 -0
  350. package/web/dist/assets/powerquery-CEu0bR-o.js +1 -0
  351. package/web/dist/assets/powershell-BmBUJMz7.js +1 -0
  352. package/web/dist/assets/prisma-Vru482bI.js +1 -0
  353. package/web/dist/assets/profileChange-B7TaQ18u.js +1 -0
  354. package/web/dist/assets/prolog-CbFg5uaA.js +1 -0
  355. package/web/dist/assets/proto-C7zT0LnQ.js +1 -0
  356. package/web/dist/assets/pug-DKIMFp6K.js +1 -0
  357. package/web/dist/assets/puppet-BMWR74SV.js +1 -0
  358. package/web/dist/assets/purescript-CklMAg4u.js +1 -0
  359. package/web/dist/assets/python-B6aJPvgy.js +1 -0
  360. package/web/dist/assets/qml-3beO22l8.js +1 -0
  361. package/web/dist/assets/qmldir-C8lEn-DE.js +1 -0
  362. package/web/dist/assets/qss-IeuSbFQv.js +1 -0
  363. package/web/dist/assets/quadrantDiagram-GDMTTRAM-BpL_ZL76.js +7 -0
  364. package/web/dist/assets/r-Cf5RLm7j.js +1 -0
  365. package/web/dist/assets/racket-BqYA7rlc.js +1 -0
  366. package/web/dist/assets/railroadDiagram-SM67HX2B-DZ-fPU85.js +1 -0
  367. package/web/dist/assets/raku-DXvB9xmW.js +1 -0
  368. package/web/dist/assets/razor-BjBPvh-w.js +1 -0
  369. package/web/dist/assets/rbs-CpoqiR4B.js +1 -0
  370. package/web/dist/assets/react-vendor-C0HIWSpf.js +9 -0
  371. package/web/dist/assets/red-hvxz__6c.js +1 -0
  372. package/web/dist/assets/reg-C-SQnVFl.js +1 -0
  373. package/web/dist/assets/regexp-CDVJQ6XC.js +1 -0
  374. package/web/dist/assets/rel-C3B-1QV4.js +1 -0
  375. package/web/dist/assets/requirementDiagram-X7JNWC4A-mKPGj64L.js +84 -0
  376. package/web/dist/assets/riscv-BM1_JUlF.js +1 -0
  377. package/web/dist/assets/ron-D8l8udqQ.js +1 -0
  378. package/web/dist/assets/rose-pine-5qJOZa0Y.js +1 -0
  379. package/web/dist/assets/rose-pine-dawn-zx0QlTCp.js +1 -0
  380. package/web/dist/assets/rose-pine-moon-C9pEdX9L.js +1 -0
  381. package/web/dist/assets/rosmsg-BJDFO7_C.js +1 -0
  382. package/web/dist/assets/rst-bs7f0vWN.js +1 -0
  383. package/web/dist/assets/ruby-C0TQ7zu5.js +1 -0
  384. package/web/dist/assets/rust-B1yitclQ.js +1 -0
  385. package/web/dist/assets/sankeyDiagram-UM26HJRW-Bs4xfjQP.js +40 -0
  386. package/web/dist/assets/sas-DEy46yEz.js +1 -0
  387. package/web/dist/assets/sass-Cj5Yp3dK.js +1 -0
  388. package/web/dist/assets/scala-CqE71os6.js +1 -0
  389. package/web/dist/assets/scheme-C98Dy4si.js +1 -0
  390. package/web/dist/assets/scss-D5BDwBP9.js +1 -0
  391. package/web/dist/assets/sdbl-DVxCFoDh.js +1 -0
  392. package/web/dist/assets/sequenceDiagram-ZO4K6R2Y-BjUmzZaO.js +169 -0
  393. package/web/dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
  394. package/web/dist/assets/shellscript-Yzrsuije.js +1 -0
  395. package/web/dist/assets/shellsession-BADoaaVG.js +1 -0
  396. package/web/dist/assets/sizeCapture-INFHLROL-BXBM3j_Q.js +1 -0
  397. package/web/dist/assets/slack-dark-BthQWCQV.js +1 -0
  398. package/web/dist/assets/slack-ochin-DqwNpetd.js +1 -0
  399. package/web/dist/assets/smalltalk-BOQMe2GC.js +1 -0
  400. package/web/dist/assets/smithy-cds9vsN8.js +1 -0
  401. package/web/dist/assets/snazzy-light-Bw305WKR.js +1 -0
  402. package/web/dist/assets/solarized-dark-CpvCGNkr.js +1 -0
  403. package/web/dist/assets/solarized-light-Dlz6yCKv.js +1 -0
  404. package/web/dist/assets/solidity-DijEV5ha.js +1 -0
  405. package/web/dist/assets/soy-8wufbnw4.js +1 -0
  406. package/web/dist/assets/sparql-rVzFXLq3.js +1 -0
  407. package/web/dist/assets/splunk-BtCnVYZw.js +1 -0
  408. package/web/dist/assets/sql-CRqJ_cUM.js +1 -0
  409. package/web/dist/assets/ssh-config-_ykCGR6B.js +1 -0
  410. package/web/dist/assets/stata-DI20mbqo.js +1 -0
  411. package/web/dist/assets/state-Kfon1nTr.js +17 -0
  412. package/web/dist/assets/stateDiagram-v2-TBUQTH76-FGgFDGUU.js +291 -0
  413. package/web/dist/assets/sttLanguages-C7kVulzY.js +1 -0
  414. package/web/dist/assets/stylus-BEDo0Tqx.js +1 -0
  415. package/web/dist/assets/surrealql-Cjom0U5J.js +1 -0
  416. package/web/dist/assets/svelte-Cy7k_4gC.js +1 -0
  417. package/web/dist/assets/swift-C2oV4EkX.js +1 -0
  418. package/web/dist/assets/swimlanes-N4OXWK64-wkd_n4HU.js +1 -0
  419. package/web/dist/assets/swimlanesDiagram-K3J5GTZL-CKnwEuq_.js +8 -0
  420. package/web/dist/assets/synthwave-84-CbfX1IO0.js +1 -0
  421. package/web/dist/assets/system-verilog-0hqHdDBg.js +1 -0
  422. package/web/dist/assets/systemd-4A_iFExJ.js +1 -0
  423. package/web/dist/assets/talonscript-CkByrt1z.js +1 -0
  424. package/web/dist/assets/tasl-QIJgUcNo.js +1 -0
  425. package/web/dist/assets/tcl-dwOrl1Do.js +1 -0
  426. package/web/dist/assets/templ-DhtptRzy.js +1 -0
  427. package/web/dist/assets/terraform-BETggiCN.js +1 -0
  428. package/web/dist/assets/tex-D96PA37w.js +1 -0
  429. package/web/dist/assets/timeline-definition-YOQAKGHF-DyBln1jw.js +120 -0
  430. package/web/dist/assets/tokyo-night-hegEt444.js +1 -0
  431. package/web/dist/assets/toml-vGWfd6FD.js +1 -0
  432. package/web/dist/assets/ts-tags-D351s5mN.js +1 -0
  433. package/web/dist/assets/tsv-B_m7g4N7.js +1 -0
  434. package/web/dist/assets/tsx-COt5Ahok.js +1 -0
  435. package/web/dist/assets/turtle-BsS91CYL.js +1 -0
  436. package/web/dist/assets/twig-27uCiNez.js +1 -0
  437. package/web/dist/assets/typescript-BPQ3VLAy.js +1 -0
  438. package/web/dist/assets/typespec-CAFt9gP4.js +1 -0
  439. package/web/dist/assets/typst-BUadGCkm.js +1 -0
  440. package/web/dist/assets/usecaseDiagram-VIAY4XPW-Cqis3XHX.js +370 -0
  441. package/web/dist/assets/v-BGw2Nkan.js +1 -0
  442. package/web/dist/assets/vala-CsfeWuGM.js +1 -0
  443. package/web/dist/assets/vb-Cu-pLBUe.js +1 -0
  444. package/web/dist/assets/vennDiagram-BLWOH2XV-BaiFLOVS.js +34 -0
  445. package/web/dist/assets/verilog-nZwndyjY.js +1 -0
  446. package/web/dist/assets/vesper-DRje8inN.js +1 -0
  447. package/web/dist/assets/vhdl-CeAyd5Ju.js +1 -0
  448. package/web/dist/assets/viml-CJc9bBzg.js +1 -0
  449. package/web/dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
  450. package/web/dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
  451. package/web/dist/assets/vitesse-light-CVO1_9PV.js +1 -0
  452. package/web/dist/assets/vue-BqiEGhQt.js +1 -0
  453. package/web/dist/assets/vue-html-AaS7Mt5G.js +1 -0
  454. package/web/dist/assets/vue-vine-BoDAl6tE.js +1 -0
  455. package/web/dist/assets/vyper-CDx5xZoG.js +1 -0
  456. package/web/dist/assets/wardleyDiagram-YMQ3BMBF-C4CzpJto.js +78 -0
  457. package/web/dist/assets/wasm-CG6Dc4jp.js +1 -0
  458. package/web/dist/assets/wasm-MzD3tlZU.js +1 -0
  459. package/web/dist/assets/wenyan-BV7otONQ.js +1 -0
  460. package/web/dist/assets/wgsl-Dx-B1_4e.js +1 -0
  461. package/web/dist/assets/wikitext-BhOHFoWU.js +1 -0
  462. package/web/dist/assets/wit-5i3qLPDT.js +1 -0
  463. package/web/dist/assets/wolfram-lXgVvXCa.js +1 -0
  464. package/web/dist/assets/xml-sdJ4AIDG.js +1 -0
  465. package/web/dist/assets/xsl-CtQFsRM5.js +1 -0
  466. package/web/dist/assets/xychartDiagram-TAQBALBS-Dp1hfe3-.js +7 -0
  467. package/web/dist/assets/yaml-Buea-lGh.js +1 -0
  468. package/web/dist/assets/zenscript-DVFEvuxE.js +1 -0
  469. package/web/dist/assets/zig-VOosw3JB.js +1 -0
  470. package/web/dist/favicon.svg +40 -0
  471. package/web/dist/figma-demo/product-1.jpg +0 -0
  472. package/web/dist/figma-demo/product-2.jpg +0 -0
  473. package/web/dist/figma-demo/trail-1.jpg +0 -0
  474. package/web/dist/figma-demo/trail-2.jpg +0 -0
  475. package/web/dist/figma-demo/trail-3.jpg +0 -0
  476. package/web/dist/fonts/OFL-Inter.txt +93 -0
  477. package/web/dist/fonts/inter-latin-400-normal.woff2 +0 -0
  478. package/web/dist/fonts/inter-latin-600-normal.woff2 +0 -0
  479. package/web/dist/icons/icon-180.png +0 -0
  480. package/web/dist/icons/icon-192.png +0 -0
  481. package/web/dist/icons/icon-512.png +0 -0
  482. package/web/dist/icons/icon-maskable-512.png +0 -0
  483. package/web/dist/index.html +56 -0
  484. package/web/dist/logo.svg +40 -0
  485. package/web/dist/manifest.webmanifest +16 -0
@@ -0,0 +1,404 @@
1
+ """TTS(语音合成)sidecar — Kokoro-82M(ONNX),零 torch。
2
+
3
+ 与 `packages/stt/stt_server.py` 同构:Node 侧分配端口后用 `--port` 传入、靠 `/health`
4
+ 判断就绪、`--parent-pid` 看门狗防孤儿进程;父进程退出后本进程自杀。
5
+ 权重**不由本进程下载**(Node 侧 `ttsDownload.ts` 负责,含国内镜像选择),本进程只从
6
+ models_dir 加载。
7
+
8
+ 环境变量:
9
+ DSC_TTS_PORT 监听端口(默认 0 = 系统分配)
10
+ DSC_TTS_MODELS_DIR 权重目录(默认 ~/.agent/tts-models)
11
+ DSC_TTS_MODEL 模型文件名(默认 model_uint8f16.onnx)
12
+ DSC_TTS_VOICES 音色文件名(默认 voices-v1.0.bin)
13
+
14
+ 端点:
15
+ GET /health 进程就绪(不依赖模型加载完成)
16
+ GET /status 依赖与权重就绪情况(供「缺什么 + 一键装」文案使用)
17
+ POST /synthesize {"text","voice","speed","lang","stream"}
18
+ 非流式 -> application/wav 整段返回
19
+ 流式 -> audio/L16 裸 PCM(s16le 24kHz 单声道),HTTP/1.0 连接关闭定界
20
+
21
+ 中文音素**必须**走 misaki(见 docs/architecture-design/PERSONAL_REMOTE_AGENT_PLAN.md
22
+ gotcha 11):kokoro-onnx 自带的 `phonemize(text, "cmn")` 走 espeak,产出丢声母且**完全无音调**,
23
+ 中文因此听不懂——而且不报错、不掉字,只有人耳能发现。Kokoro 的中文音色是用 misaki 的
24
+ 拼音 IPA(带 `↓→↗↘` 调号)训练的,所以这里自己产出音素,再以 `is_phonemes=True` 送入。
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import asyncio
30
+ import io
31
+ import json
32
+ import os
33
+ import re
34
+ import sys
35
+ import threading
36
+ import time
37
+ import wave
38
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
39
+ from pathlib import Path
40
+ from typing import Any, Callable
41
+
42
+ import numpy as np
43
+
44
+ DEFAULT_MODELS_DIR = str(Path.home() / ".agent" / "tts-models")
45
+ SAMPLE_RATE = 24_000
46
+ DEFAULT_MODEL = "model_uint8f16.onnx"
47
+ DEFAULT_VOICES = "voices-v1.0.bin"
48
+ # 每档语言的默认音色(Kokoro v1.0 音色名;未知音色会被 resolve_voice 挡下并列出可选值)
49
+ DEFAULT_VOICE = {"zh": "zf_xiaoxiao", "en": "af_heart"}
50
+ FALLBACK_VOICE = "af_heart"
51
+ MAX_TEXT_CHARS = 5_000
52
+ # 中英混排切分:英文段(含文件名/路径里的 . _ - /)与其余段。见 gotcha 11 的切分理由。
53
+ _MIXED_RE = re.compile(r"[A-Za-z][A-Za-z0-9_.\-/]*|[^A-Za-z]+")
54
+
55
+
56
+ def log(message: str) -> None:
57
+ print(f"[tts] {message}", flush=True)
58
+
59
+
60
+ def _arg_value(name: str) -> str | None:
61
+ """从 sys.argv 取 `--x value` 或 `--x=value`(与 stt_server.py 同一约定)。"""
62
+ argv = sys.argv
63
+ for index, item in enumerate(argv):
64
+ if item == name and index + 1 < len(argv):
65
+ return argv[index + 1]
66
+ if item.startswith(f"{name}="):
67
+ return item.split("=", 1)[1]
68
+ return None
69
+
70
+
71
+ def is_chinese(lang: str) -> bool:
72
+ normalized = (lang or "").lower().replace("_", "-")
73
+ return normalized.startswith("zh") or normalized.startswith("cmn") or normalized.startswith("yue")
74
+
75
+
76
+ def lang_key(lang: str) -> str:
77
+ return "zh" if is_chinese(lang) else "en"
78
+
79
+
80
+ def parent_alive(pid: int) -> bool:
81
+ """父进程是否还在。
82
+
83
+ **不要**用 `os.kill(pid, 0)` 探活:Windows 上它并非「发 0 号信号」,CPython 会走
84
+ `OpenProcess(PROCESS_ALL_ACCESS)` + `TerminateProcess`(文档:除 CTRL_C_EVENT /
85
+ CTRL_BREAK_EVENT 外的 sig 会「unconditionally killed by the TerminateProcess API」),
86
+ 而且 `PROCESS_ALL_ACCESS` 在子进程带 `CREATE_NO_WINDOW`(Node 的 `windowsHide: true`)
87
+ 时**会失败**并抛 OSError → 看门狗误判「父进程已死」→ 服务约 5 秒后自杀,表现为
88
+ 第一个请求连接被重置、之后一律 ConnectionRefused。实测见 .agent/tts-probe/shape_probe.py。
89
+ """
90
+ if os.name == "nt":
91
+ import ctypes
92
+
93
+ kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
94
+ # 只申请「查询」权限,不做任何写/终止操作
95
+ handle = kernel32.OpenProcess(0x1000, False, pid)
96
+ if not handle:
97
+ return False
98
+ try:
99
+ code = ctypes.c_ulong()
100
+ if not kernel32.GetExitCodeProcess(handle, ctypes.byref(code)):
101
+ return False
102
+ return code.value == 259 # STILL_ACTIVE
103
+ finally:
104
+ kernel32.CloseHandle(handle)
105
+ try:
106
+ os.kill(pid, 0)
107
+ return True
108
+ except (OSError, ValueError):
109
+ return False
110
+
111
+
112
+ def build_phonemes(text: str, lang: str, tokenizer: Any, zh_g2p: Any) -> str:
113
+ """text -> 音素串。非中文交给 kokoro-onnx 原生 espeak 路径;中文走 misaki,
114
+ 并把中英混排自己切开——否则英文段会被原样保留、随后被 tokenizer 静默丢弃。"""
115
+ if not is_chinese(lang):
116
+ return tokenizer.phonemize(text, lang)
117
+ parts: list[str] = []
118
+ for match in _MIXED_RE.finditer(text):
119
+ chunk = match.group(0)
120
+ if not chunk.strip():
121
+ continue
122
+ if chunk[0].isascii() and chunk[0].isalpha():
123
+ parts.append(tokenizer.phonemize(chunk, "en-us"))
124
+ else:
125
+ phonemes, _ = zh_g2p(chunk)
126
+ parts.append(phonemes)
127
+ return " ".join(part for part in parts if part)
128
+
129
+
130
+ def to_pcm16(samples: Any) -> bytes:
131
+ clipped = np.clip(np.asarray(samples, dtype=np.float32), -1.0, 1.0)
132
+ return (clipped * 32767.0).astype("<i2").tobytes()
133
+
134
+
135
+ def wav_bytes(samples: Any, sample_rate: int) -> bytes:
136
+ buffer = io.BytesIO()
137
+ with wave.open(buffer, "wb") as handle:
138
+ handle.setnchannels(1)
139
+ handle.setsampwidth(2)
140
+ handle.setframerate(sample_rate)
141
+ handle.writeframes(to_pcm16(samples))
142
+ return buffer.getvalue()
143
+
144
+
145
+ class TtsEngine:
146
+ """懒加载 Kokoro。加载失败时把原因留在 probe() 里,供前端「缺什么」文案使用。"""
147
+
148
+ def __init__(self, models_dir: str, model_file: str, voices_file: str) -> None:
149
+ self.models_dir = models_dir
150
+ self.model_file = model_file
151
+ self.voices_file = voices_file
152
+ self.model_path = str(Path(models_dir) / model_file)
153
+ self.voices_path = str(Path(models_dir) / voices_file)
154
+ self._kokoro: Any = None
155
+ self._zh_g2p: Any = None
156
+ self._load_error: str | None = None
157
+ self._lock = threading.Lock()
158
+
159
+ def missing_weights(self) -> list[str]:
160
+ pairs = ((self.model_file, self.model_path), (self.voices_file, self.voices_path))
161
+ return [name for name, path in pairs if not Path(path).is_file()]
162
+
163
+ def probe(self) -> dict:
164
+ """不加载模型,只探测依赖可导入性与权重是否就位。"""
165
+ try:
166
+ import kokoro_onnx # noqa: F401
167
+ import misaki # noqa: F401
168
+
169
+ import_error: str | None = None
170
+ except Exception as exc: # noqa: BLE001
171
+ import_error = f"{type(exc).__name__}: {exc}"
172
+ missing = self.missing_weights()
173
+ status: dict = {
174
+ "installed": import_error is None and not missing,
175
+ "loaded": self._kokoro is not None,
176
+ "model": self.model_file,
177
+ "voicesFile": self.voices_file,
178
+ "voiceNames": self.voice_names(),
179
+ "device": "cpu",
180
+ "missingWeights": missing,
181
+ }
182
+ if import_error:
183
+ status["error"] = import_error
184
+ elif self._load_error:
185
+ status["error"] = self._load_error
186
+ return status
187
+
188
+ def load(self) -> Any:
189
+ with self._lock:
190
+ if self._kokoro is not None:
191
+ return self._kokoro
192
+ if self._load_error:
193
+ raise RuntimeError(self._load_error)
194
+ missing = self.missing_weights()
195
+ if missing:
196
+ raise RuntimeError(f"missing weights: {', '.join(missing)}")
197
+ try:
198
+ from kokoro_onnx import Kokoro
199
+ from misaki import zh
200
+
201
+ self._zh_g2p = zh.ZHG2P()
202
+ self._kokoro = Kokoro(self.model_path, self.voices_path)
203
+ except Exception as exc: # noqa: BLE001
204
+ self._load_error = f"{type(exc).__name__}: {exc}"
205
+ raise RuntimeError(self._load_error) from exc
206
+ log(f"model loaded ({self.model_file}, {len(self._kokoro.voices)} voices)")
207
+ return self._kokoro
208
+
209
+ def voice_names(self) -> list[str]:
210
+ """音色名清单(voices 文件的 key),**不加载 ONNX 模型**。
211
+
212
+ 为什么不用 available_voices():那条路径要过 load(),会把 114 MiB 模型读进内存,
213
+ 而 probe() 是被设置页高频轮询的——这个代价付不起。模型已加载时直接取它的键,
214
+ 与读文件是同一份数据,只是省一次解析。
215
+ """
216
+ if self._kokoro is not None:
217
+ return sorted(self._kokoro.voices)
218
+ if not Path(self.voices_path).is_file():
219
+ return []
220
+ try:
221
+ import numpy
222
+
223
+ return sorted(numpy.load(self.voices_path, allow_pickle=False).files)
224
+ except Exception as exc: # noqa: BLE001
225
+ # 拿不到清单不该让整个状态接口失败:合成侧仍会按 lang 选默认音色
226
+ log(f"voice list unavailable: {exc}")
227
+ return []
228
+
229
+ def available_voices(self) -> list[str]:
230
+ return sorted(self.load().voices)
231
+
232
+ def resolve_voice(self, lang: str, voice: str | None) -> str:
233
+ available = self.available_voices()
234
+ wanted = voice or DEFAULT_VOICE.get(lang_key(lang), FALLBACK_VOICE)
235
+ if wanted in available:
236
+ return wanted
237
+ raise ValueError(f"unknown voice {wanted!r}; available: {', '.join(available)}")
238
+
239
+ def _phonemes(self, kokoro: Any, text: str, lang: str) -> str:
240
+ return build_phonemes(text, lang, kokoro.tokenizer, self._zh_g2p)
241
+
242
+ def synthesize(self, text: str, lang: str, voice: str | None, speed: float) -> tuple[bytes, int]:
243
+ kokoro = self.load()
244
+ phonemes = self._phonemes(kokoro, text, lang)
245
+ if not phonemes.strip():
246
+ raise ValueError("text produced no phonemes")
247
+ audio, rate = kokoro.create(
248
+ phonemes,
249
+ voice=self.resolve_voice(lang, voice),
250
+ speed=speed,
251
+ lang=lang,
252
+ is_phonemes=True,
253
+ )
254
+ return wav_bytes(audio, rate), rate
255
+
256
+ def synthesize_stream(
257
+ self, text: str, lang: str, voice: str | None, speed: float, write: Callable[[bytes], None]
258
+ ) -> None:
259
+ """边合成边写裸 PCM。放弃生成器即停止后续批次,客户端断连自然收敛。"""
260
+ kokoro = self.load()
261
+ phonemes = self._phonemes(kokoro, text, lang)
262
+ if not phonemes.strip():
263
+ raise ValueError("text produced no phonemes")
264
+ style = self.resolve_voice(lang, voice)
265
+
266
+ async def run() -> None:
267
+ async for audio, _rate in kokoro.create_stream(
268
+ phonemes, voice=style, speed=speed, lang=lang, is_phonemes=True
269
+ ):
270
+ write(to_pcm16(audio))
271
+
272
+ asyncio.run(run())
273
+
274
+
275
+ class TtsHttpServer(ThreadingHTTPServer):
276
+ daemon_threads = True
277
+
278
+ def __init__(self, address: tuple[str, int], engine: TtsEngine) -> None:
279
+ super().__init__(address, TtsHandler)
280
+ self.engine = engine
281
+
282
+
283
+ class TtsHandler(BaseHTTPRequestHandler):
284
+ server_version = "DeepSeekCodeTts/1.0"
285
+ # 流式响应无 Content-Length,靠连接关闭定界;HTTP/1.0 正好是这个语义
286
+ protocol_version = "HTTP/1.0"
287
+
288
+ def log_message(self, fmt: str, *args: Any) -> None:
289
+ """静音 http.server 默认的逐请求 stderr 噪音。"""
290
+
291
+ @property
292
+ def engine(self) -> TtsEngine:
293
+ return self.server.engine # type: ignore[attr-defined]
294
+
295
+ def _send_json(self, status: int, payload: dict) -> None:
296
+ body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
297
+ self.send_response(status)
298
+ self.send_header("Content-Type", "application/json; charset=utf-8")
299
+ self.send_header("Content-Length", str(len(body)))
300
+ self.end_headers()
301
+ self.wfile.write(body)
302
+
303
+ def do_GET(self) -> None: # noqa: N802 (http.server 的约定命名)
304
+ if self.path == "/health":
305
+ self._send_json(200, {"ok": True})
306
+ elif self.path == "/status":
307
+ self._send_json(200, self.engine.probe())
308
+ else:
309
+ self._send_json(404, {"error": "not found"})
310
+
311
+ def do_POST(self) -> None: # noqa: N802
312
+ if self.path != "/synthesize":
313
+ self._send_json(404, {"error": "not found"})
314
+ return
315
+ try:
316
+ length = int(self.headers.get("Content-Length") or 0)
317
+ payload = json.loads(self.rfile.read(length) or b"{}")
318
+ except Exception as exc: # noqa: BLE001
319
+ self._send_json(400, {"error": f"bad request body: {exc}"})
320
+ return
321
+ log(f"-> synthesize {len(payload.get('text') or '')} chars lang={payload.get('lang')}")
322
+
323
+ text = str(payload.get("text") or "").strip()
324
+ if not text:
325
+ self._send_json(400, {"error": "text is required"})
326
+ return
327
+ if len(text) > MAX_TEXT_CHARS:
328
+ self._send_json(400, {"error": f"text too long (> {MAX_TEXT_CHARS} chars)"})
329
+ return
330
+
331
+ lang = str(payload.get("lang") or "en-us")
332
+ voice = payload.get("voice") or None
333
+ speed = float(payload.get("speed") or 1.0)
334
+ if not 0.5 <= speed <= 2.0:
335
+ self._send_json(400, {"error": f"speed must be within 0.5~2.0, got {speed}"})
336
+ return
337
+
338
+ if payload.get("stream"):
339
+ self._stream(text, lang, voice, speed)
340
+ return
341
+
342
+ try:
343
+ audio, rate = self.engine.synthesize(text, lang, voice, speed)
344
+ except ValueError as exc:
345
+ self._send_json(400, {"error": str(exc)})
346
+ except Exception as exc: # noqa: BLE001
347
+ self._send_json(500, {"error": f"{type(exc).__name__}: {exc}"})
348
+ else:
349
+ log(f"<- synthesized {len(audio)} bytes, responding")
350
+ self.send_response(200)
351
+ self.send_header("Content-Type", "audio/wav")
352
+ self.send_header("X-Sample-Rate", str(rate))
353
+ self.send_header("Content-Length", str(len(audio)))
354
+ self.end_headers()
355
+ self.wfile.write(audio)
356
+
357
+ def _stream(self, text: str, lang: str, voice: str | None, speed: float) -> None:
358
+ """头一旦发出就无法再改状态码,所以失败只能记日志 + 断流(客户端按截断处理)。"""
359
+ self.send_response(200)
360
+ self.send_header("Content-Type", "audio/L16")
361
+ self.send_header("X-Sample-Rate", str(SAMPLE_RATE))
362
+ self.send_header("Connection", "close")
363
+ self.end_headers()
364
+ try:
365
+ self.engine.synthesize_stream(text, lang, voice, speed, self.wfile.write)
366
+ except (BrokenPipeError, ConnectionResetError):
367
+ log("client closed the stream")
368
+ except Exception as exc: # noqa: BLE001
369
+ log(f"stream failed: {type(exc).__name__}: {exc}")
370
+
371
+
372
+ def main() -> None:
373
+ models_dir = os.environ.get("DSC_TTS_MODELS_DIR") or DEFAULT_MODELS_DIR
374
+ Path(models_dir).mkdir(parents=True, exist_ok=True)
375
+ model_file = os.environ.get("DSC_TTS_MODEL") or DEFAULT_MODEL
376
+ voices_file = os.environ.get("DSC_TTS_VOICES") or DEFAULT_VOICES
377
+ port = int(_arg_value("--port") or os.environ.get("DSC_TTS_PORT") or "0")
378
+ raw_parent = _arg_value("--parent-pid")
379
+ parent_pid = int(raw_parent) if raw_parent and raw_parent.isdigit() else None
380
+
381
+ engine = TtsEngine(models_dir, model_file, voices_file)
382
+ server = TtsHttpServer(("127.0.0.1", port), engine)
383
+ log(f"listening on 127.0.0.1:{server.server_address[1]} (models_dir={models_dir})")
384
+
385
+ def watchdog() -> None:
386
+ """父进程(Node server)退出后自动退出,避免残留孤儿进程(Windows 上尤为必要)。"""
387
+ while True:
388
+ time.sleep(5)
389
+ if not parent_alive(parent_pid):
390
+ log(f"parent pid {parent_pid} gone, exiting")
391
+ server.shutdown()
392
+ return
393
+
394
+ if parent_pid is not None:
395
+ threading.Thread(target=watchdog, daemon=True).start()
396
+
397
+ try:
398
+ server.serve_forever()
399
+ except KeyboardInterrupt:
400
+ pass
401
+
402
+
403
+ if __name__ == "__main__":
404
+ main()
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ // Fallback launcher for the @deepseekcode/cli wrapper package.
3
+ //
4
+ // Normally the postinstall script (install.cjs) copies the native binary over
5
+ // bin/dscode(.exe), so this file is never invoked. It exists for environments
6
+ // where postinstall doesn't run (--ignore-scripts) — users can run
7
+ // `node cli-wrapper.cjs` directly and pay the Node-process overhead as the
8
+ // price. Marks the child with DEEPSEEKCODE_INSTALLED_VIA_NPM_WRAPPER so the
9
+ // binary knows it was reached through the npm wrapper (update path decisions).
10
+
11
+ const { spawnSync } = require('child_process')
12
+ const { arch, constants } = require('os')
13
+ const path = require('path')
14
+
15
+ // Platform detection + PLATFORMS map is duplicated in install.cjs — keep in sync.
16
+ const WRAPPER_NAME = require('./package.json').name
17
+ // Same scope as the wrapper (@<scope>/cli-<platform>) — derived, not hard-coded,
18
+ // so one source file serves every published scope. Keep in sync with install.cjs.
19
+ const PACKAGE_PREFIX = WRAPPER_NAME
20
+ const BINARY_NAME = 'dscode'
21
+
22
+
23
+ const PLATFORMS = {
24
+ 'darwin-arm64': { pkg: PACKAGE_PREFIX + '-darwin-arm64', bin: BINARY_NAME },
25
+ 'darwin-x64': { pkg: PACKAGE_PREFIX + '-darwin-x64', bin: BINARY_NAME },
26
+ 'linux-x64': { pkg: PACKAGE_PREFIX + '-linux-x64', bin: BINARY_NAME },
27
+ 'linux-arm64': { pkg: PACKAGE_PREFIX + '-linux-arm64', bin: BINARY_NAME },
28
+ 'linux-x64-musl': { pkg: PACKAGE_PREFIX + '-linux-x64-musl', bin: BINARY_NAME },
29
+ 'linux-arm64-musl': { pkg: PACKAGE_PREFIX + '-linux-arm64-musl', bin: BINARY_NAME },
30
+ 'win32-x64': { pkg: PACKAGE_PREFIX + '-win32-x64', bin: BINARY_NAME + '.exe' },
31
+ 'win32-arm64': { pkg: PACKAGE_PREFIX + '-win32-arm64', bin: BINARY_NAME + '.exe' },
32
+ }
33
+
34
+ function detectMusl() {
35
+ if (process.platform !== 'linux') return false
36
+ const report =
37
+ typeof process.report?.getReport === 'function'
38
+ ? process.report.getReport()
39
+ : null
40
+ return report != null && report.header?.glibcVersionRuntime === undefined
41
+ }
42
+
43
+ function getPlatformKey() {
44
+ const platform = process.platform
45
+ let cpu = arch()
46
+ if (platform === 'linux') {
47
+ return 'linux-' + cpu + (detectMusl() ? '-musl' : '')
48
+ }
49
+ if (platform === 'darwin' && cpu === 'x64') {
50
+ const r = spawnSync('sysctl', ['-n', 'sysctl.proc_translated'], { encoding: 'utf8' })
51
+ if (r.stdout?.trim() === '1') cpu = 'arm64'
52
+ }
53
+ return platform + '-' + cpu
54
+ }
55
+
56
+ function getBinaryPath() {
57
+ const platformKey = getPlatformKey()
58
+ const info = PLATFORMS[platformKey]
59
+ if (!info) {
60
+ console.error(`[${WRAPPER_NAME}] Unsupported platform: ${process.platform} ${arch()}. Supported: ${Object.keys(PLATFORMS).join(', ')}`)
61
+ process.exit(1)
62
+ }
63
+ const optionalDeps = require('./package.json').optionalDependencies || {}
64
+ if (!optionalDeps[info.pkg]) {
65
+ console.error(`[${WRAPPER_NAME}] Native binaries for ${platformKey} are not available on this release channel.`)
66
+ console.error(` Available: ${Object.keys(optionalDeps).map((p) => p.replace(PACKAGE_PREFIX + '-', '')).join(', ')}`)
67
+ process.exit(1)
68
+ }
69
+ try {
70
+ const pkgDir = path.dirname(require.resolve(info.pkg + '/package.json'))
71
+ return path.join(pkgDir, info.bin)
72
+ } catch {
73
+ console.error(`[${WRAPPER_NAME}] Could not find native binary package "${info.pkg}".`)
74
+ if (platformKey === 'darwin-arm64' && arch() === 'x64') {
75
+ console.error(' You are running x64 Node under Rosetta 2 on Apple Silicon. npm only')
76
+ console.error(' installed the darwin-x64 binary.')
77
+ } else {
78
+ console.error(' Try reinstalling with: npm install')
79
+ }
80
+ process.exit(1)
81
+ }
82
+ }
83
+
84
+ function main() {
85
+ const binaryPath = getBinaryPath()
86
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
87
+ stdio: 'inherit',
88
+ env: { ...process.env, DEEPSEEKCODE_INSTALLED_VIA_NPM_WRAPPER: '1' },
89
+ // windowsHide:本 wrapper 会被 daemon 当作 process.argv[1] 再次执行(见
90
+ // src/instance.ts 的 detached spawn,那层已带 windowsHide)。无控制台宿主下
91
+ // 这里拉起原生二进制若不隐藏,每次启动 daemon 都会补闪一个黑框。
92
+ windowsHide: true,
93
+ })
94
+ if (result.error) {
95
+ console.error(`[${WRAPPER_NAME}] Failed to execute native binary at ` + binaryPath)
96
+ console.error(' ' + result.error.message)
97
+ process.exit(1)
98
+ }
99
+ if (result.signal) {
100
+ // Node.js ignores some signals (e.g. SIGPIPE → SIG_IGN), so re-raising is
101
+ // unreliable. Exit with the POSIX convention 128+signum instead.
102
+ const signum = constants.signals[result.signal] ?? 0
103
+ process.exit(128 + signum)
104
+ } else {
105
+ process.exit(result.status ?? 1)
106
+ }
107
+ }
108
+
109
+ main()
package/install.cjs ADDED
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env node
2
+ // Postinstall for the @deepseekcode/cli wrapper package.
3
+ //
4
+ // Mirrors the Claude Code 2.x distribution model: the npm package is a thin
5
+ // installer. This script detects the platform, finds the matching native binary
6
+ // from optionalDependencies (@deepseekcode/cli-<platform>), and copies it over
7
+ // the bin/dscode.exe placeholder. After this runs, `dscode` execs the native
8
+ // binary directly — no Node process stays resident.
9
+ //
10
+ // If the native package isn't present (--omit=optional), prints instructions and
11
+ // leaves the placeholder stub in place. cli-wrapper.cjs (same directory) can be
12
+ // invoked manually as a fallback.
13
+ //
14
+ // On Windows the stub (a non-PE .exe) surfaces as a native "not a valid Win32
15
+ // application" error, so its message is best-effort; install.cjs failure output
16
+ // above is the primary guidance when postinstall does run.
17
+ //
18
+ // Platform detection + PLATFORMS map is duplicated in cli-wrapper.cjs — keep in sync.
19
+
20
+ const { spawnSync } = require('child_process')
21
+ const {
22
+ copyFileSync,
23
+ linkSync,
24
+ unlinkSync,
25
+ chmodSync,
26
+ readFileSync,
27
+ writeFileSync,
28
+ statSync,
29
+ } = require('fs')
30
+ const { arch } = require('os')
31
+ const path = require('path')
32
+
33
+ const WRAPPER_NAME = require('./package.json').name
34
+ // Platform packages live in the SAME npm scope as the wrapper
35
+ // (@<scope>/cli-<platform>). Derived rather than hard-coded so one source file
36
+ // serves every scope the release is published to (see scripts/multi-publish.mjs).
37
+ const PACKAGE_PREFIX = WRAPPER_NAME
38
+ const BINARY_NAME = 'dscode'
39
+
40
+
41
+ const PLATFORMS = {
42
+ 'darwin-arm64': { pkg: PACKAGE_PREFIX + '-darwin-arm64', bin: BINARY_NAME },
43
+ 'darwin-x64': { pkg: PACKAGE_PREFIX + '-darwin-x64', bin: BINARY_NAME },
44
+ 'linux-x64': { pkg: PACKAGE_PREFIX + '-linux-x64', bin: BINARY_NAME },
45
+ 'linux-arm64': { pkg: PACKAGE_PREFIX + '-linux-arm64', bin: BINARY_NAME },
46
+ 'linux-x64-musl': { pkg: PACKAGE_PREFIX + '-linux-x64-musl', bin: BINARY_NAME },
47
+ 'linux-arm64-musl': { pkg: PACKAGE_PREFIX + '-linux-arm64-musl', bin: BINARY_NAME },
48
+ 'win32-x64': { pkg: PACKAGE_PREFIX + '-win32-x64', bin: BINARY_NAME + '.exe' },
49
+ 'win32-arm64': { pkg: PACKAGE_PREFIX + '-win32-arm64', bin: BINARY_NAME + '.exe' },
50
+ }
51
+
52
+ function detectMusl() {
53
+ if (process.platform !== 'linux') return false
54
+ // process.report is available in Node ≥12; glibcVersionRuntime is absent on musl.
55
+ // Faster than spawning `ldd` and avoids the ENOENT→musl false positive when ldd
56
+ // isn't on PATH (minimal containers).
57
+ const report =
58
+ typeof process.report?.getReport === 'function'
59
+ ? process.report.getReport()
60
+ : null
61
+ return report != null && report.header?.glibcVersionRuntime === undefined
62
+ }
63
+
64
+ function getPlatformKey() {
65
+ const platform = process.platform
66
+ let cpu = arch()
67
+ if (platform === 'linux') {
68
+ return 'linux-' + cpu + (detectMusl() ? '-musl' : '')
69
+ }
70
+ // Rosetta 2: an x64 Node on Apple Silicon reports arch()==='x64'. Prefer the
71
+ // native arm64 binary — the x64 build needs AVX, which Rosetta doesn't emulate.
72
+ if (platform === 'darwin' && cpu === 'x64') {
73
+ const r = spawnSync('sysctl', ['-n', 'sysctl.proc_translated'], { encoding: 'utf8' })
74
+ if (r.stdout?.trim() === '1') cpu = 'arm64'
75
+ }
76
+ return platform + '-' + cpu
77
+ }
78
+
79
+ function placeBinary(src, dest) {
80
+ // Try hardlink first (instant, zero extra disk for a ~110MB binary; src and
81
+ // dest are both under node_modules/ so same-filesystem is the common case).
82
+ // We attempt the link BEFORE touching dest — if src is missing (partial
83
+ // extraction) the first linkSync throws ENOENT and the fallback stub stays.
84
+ try {
85
+ linkSync(src, dest)
86
+ } catch (err) {
87
+ if (err.code === 'EEXIST') {
88
+ // Read the stub before unlinking so we can restore it if both link and
89
+ // copy fail (ENOSPC, NFS error mid-copy). Only read if dest is
90
+ // stub-sized — on re-install dest is the ~110MB binary.
91
+ const stub = statSync(dest).size < 4096 ? readFileSync(dest) : null
92
+ unlinkSync(dest)
93
+ try {
94
+ linkSync(src, dest)
95
+ } catch {
96
+ try {
97
+ copyFileSync(src, dest)
98
+ } catch (copyErr) {
99
+ if (stub) {
100
+ try {
101
+ writeFileSync(dest, stub, { mode: 0o755 })
102
+ } catch {
103
+ // Do nothing
104
+ }
105
+ }
106
+ throw copyErr
107
+ }
108
+ }
109
+ } else if (err.code === 'EXDEV' || err.code === 'EPERM') {
110
+ // Cross-device or no-link-perms — copyFileSync overwrites existing dest.
111
+ copyFileSync(src, dest)
112
+ } else {
113
+ throw err
114
+ }
115
+ }
116
+ if (process.platform !== 'win32') {
117
+ chmodSync(dest, 0o755)
118
+ }
119
+ }
120
+
121
+ function main() {
122
+ const platformKey = getPlatformKey()
123
+ const info = PLATFORMS[platformKey]
124
+
125
+ if (!info) {
126
+ console.error(
127
+ `[${WRAPPER_NAME} postinstall] Unsupported platform: ${process.platform} ${arch()}`,
128
+ )
129
+ console.error(` Supported: ${Object.keys(PLATFORMS).join(', ')}`)
130
+ return
131
+ }
132
+
133
+ const optionalDeps = require('./package.json').optionalDependencies || {}
134
+ if (!optionalDeps[info.pkg]) {
135
+ console.error(
136
+ `[${WRAPPER_NAME} postinstall] Native binaries for ${platformKey} are not available on this release channel.`,
137
+ )
138
+ console.error(` Available: ${Object.keys(optionalDeps).map((p) => p.replace(PACKAGE_PREFIX + '-', '')).join(', ')}`)
139
+ return
140
+ }
141
+
142
+ let src
143
+ try {
144
+ const pkgDir = path.dirname(require.resolve(info.pkg + '/package.json'))
145
+ src = path.join(pkgDir, info.bin)
146
+ } catch {
147
+ console.error(`[${WRAPPER_NAME} postinstall] Native package "${info.pkg}" not found.`)
148
+ if (platformKey === 'darwin-arm64' && arch() === 'x64') {
149
+ console.error(' You are running x64 Node under Rosetta 2 on Apple Silicon. npm only')
150
+ console.error(' installed the darwin-x64 binary. Install arm64 Node and reinstall:')
151
+ console.error(' arch -arm64 zsh -c "nvm install --lts && npm i -g ' + WRAPPER_NAME + '"')
152
+ return
153
+ }
154
+ console.error(' This happens with --omit=optional or when the download failed.')
155
+ console.error(' The `dscode` command will print instructions when invoked.')
156
+ console.error(' Fallback: node ' + path.join(__dirname, 'cli-wrapper.cjs'))
157
+ return
158
+ }
159
+
160
+ // Always write to bin/dscode.exe — the package.json bin field points here
161
+ // (npm generates its shim/symlink from the .exe extension at install time).
162
+ // On Unix npm links `bin/dscode` → `bin/dscode.exe` and ignores the
163
+ // extension, so overwriting the .exe path replaces the running target on
164
+ // every platform. Same pattern as Claude Code / Bun npm packages.
165
+ const dest = path.join(__dirname, 'bin', 'dscode.exe')
166
+
167
+ try {
168
+ placeBinary(src, dest)
169
+ console.log(`[${WRAPPER_NAME} postinstall] Native binary placed → ${dest}`)
170
+ } catch (err) {
171
+ console.error(`[${WRAPPER_NAME} postinstall] Failed to place binary: ${err.message}`)
172
+ console.error(' Fallback: node ' + path.join(__dirname, 'cli-wrapper.cjs'))
173
+ process.exitCode = 1
174
+ }
175
+ }
176
+
177
+ main()