@kimicode/cli 1.0.39 → 1.0.41
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.
- package/LICENSE.md +12 -0
- package/README.md +1007 -28
- package/bin/stt/requirements.txt +20 -0
- package/bin/stt/stt_server.py +544 -0
- package/bin/tts/requirements.txt +21 -0
- package/bin/tts/tts_server.py +404 -0
- package/cli-wrapper.cjs +4 -0
- package/install.cjs +156 -2
- package/llms.txt +115 -0
- package/package.json +30 -11
- package/web/dist/assets/AssistantsView-dhdYVIy0.js +1 -0
- package/web/dist/assets/AutomationView-D1dU5ZV7.js +1 -0
- package/web/dist/assets/ChannelConfigView-CEPVZntU.js +8 -0
- package/web/dist/assets/ChartsView-DdN-beHW.js +1 -0
- package/web/dist/assets/ConnectorsView-CseCss9C.js +1 -0
- package/web/dist/assets/FileTreeView-Dnc3-gRF.js +1 -0
- package/web/dist/assets/HookConfigView-DA2h4HdJ.js +1 -0
- package/web/dist/assets/InputArea-DAgOOjOc.js +14 -0
- package/web/dist/assets/MemoryView-D6OUBi4-.js +1 -0
- package/web/dist/assets/MessageBubble-CCTRbIMZ.css +1 -0
- package/web/dist/assets/MessageBubble-CV16DZMG.js +453 -0
- package/web/dist/assets/ModelsView-BuqD9vWl.js +1 -0
- package/web/dist/assets/PluginsView-CIziDHFJ.js +2 -0
- package/web/dist/assets/ProjectsView-c6faWy32.js +1 -0
- package/web/dist/assets/SessionGrid-BZJHcklh.js +4 -0
- package/web/dist/assets/SessionGrid-Bk5CAXEn.css +1 -0
- package/web/dist/assets/SettingsModal-BqdGEGW-.js +4 -0
- package/web/dist/assets/SkillsView-CB6CKkmb.js +1 -0
- package/web/dist/assets/TemplatesTab-B8efVwVZ.js +1 -0
- package/web/dist/assets/ThreadsView-CDoM0aNb.js +2 -0
- package/web/dist/assets/ToolsView-BG-xsWsO.js +1 -0
- package/web/dist/assets/abnfDiagram-WEYOIA3C-DGUPHfRO.js +1 -0
- package/web/dist/assets/agentIconSet-Btsb_SC4.js +1 -0
- package/web/dist/assets/api-CCt9DRQm.js +1 -0
- package/web/dist/assets/arc-Y1ARJVZ4.js +1 -0
- package/web/dist/assets/architecture-WOLXFQ4H-BUERx_-B.js +1 -0
- package/web/dist/assets/architectureDiagram-ZHVYKT53-BPsQL7O5.js +36 -0
- package/web/dist/assets/array-BifhSqXX.js +1 -0
- package/web/dist/assets/blockDiagram-RJAE7QA3-pB7EXp6p.js +140 -0
- package/web/dist/assets/c4Diagram-XDPPPE54-BnPeCq_L.js +38 -0
- package/web/dist/assets/channel-CSrLW66f.js +1 -0
- package/web/dist/assets/channelMeta-BGQXQxgj.js +1 -0
- package/web/dist/assets/chunk-2E7WHVMD-xX282MrC.js +88 -0
- package/web/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/web/dist/assets/chunk-4EMNKR2T-BAQDLVqt.js +1 -0
- package/web/dist/assets/chunk-55XCU76K-BwAE3Eqq.js +1 -0
- package/web/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/web/dist/assets/chunk-7S6XSTFO-DwwaClMo.js +2 -0
- package/web/dist/assets/chunk-AQDTSKZB-DHG5Km_p.js +72 -0
- package/web/dist/assets/chunk-DSNLSHJZ-a6-B52h-.js +129 -0
- package/web/dist/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
- package/web/dist/assets/chunk-HAGFOTED-DZMcAj3o.js +62 -0
- package/web/dist/assets/chunk-HNE4Q36P-gl_4xI6B.js +1 -0
- package/web/dist/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
- package/web/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/web/dist/assets/chunk-NGNAAXSQ-Bw6tHVuc.js +136 -0
- package/web/dist/assets/chunk-NQOKRVIF-B8Q-YmhL.js +213 -0
- package/web/dist/assets/chunk-UHW7PFBP-isP5lYMB.js +1 -0
- package/web/dist/assets/chunk-VQ5W62QI-Bn68syIc.js +1 -0
- package/web/dist/assets/chunk-WQQL4CDK-CdZpmEYA.js +10 -0
- package/web/dist/assets/chunk-XXDRQBXY-CnbRkih_.js +1 -0
- package/web/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/web/dist/assets/chunk-YZO67HFG-DX9GhJkR.js +1 -0
- package/web/dist/assets/chunk-ZAUX2LTX-Ki22UlYp.js +1 -0
- package/web/dist/assets/chunk-ZCHMQSOR-BVj0Zx6L.js +2 -0
- package/web/dist/assets/classDiagram-v2-4MYWR3UA-C7PV1veb.js +217 -0
- package/web/dist/assets/cn-rx4uumOJ.js +1 -0
- package/web/dist/assets/common-BHXgEvgk.js +192 -0
- package/web/dist/assets/cose-bilkent-JH36ORCC-DHFtpmij.js +1 -0
- package/web/dist/assets/cynefin-EF2NZ3EQ-1rI2T0cc.js +1 -0
- package/web/dist/assets/cynefinDiagram-WF24UDRP-C8O_v8xU.js +62 -0
- package/web/dist/assets/cytoscape.esm-BY277UBX.js +321 -0
- package/web/dist/assets/dagre-NK4GIZVX-BWGoHIUd.js +4 -0
- package/web/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/web/dist/assets/diagram-CBK3MWTC-kf9v35RN.js +24 -0
- package/web/dist/assets/diagram-I5XIIV2D-Ro-ig56_.js +24 -0
- package/web/dist/assets/diagram-ODIL2UCW-CtGga01G.js +30 -0
- package/web/dist/assets/diagram-PFBEJUXE-C14lcR-6.js +3 -0
- package/web/dist/assets/diagram-RJA3I4VV-BBbqaSKU.js +41 -0
- package/web/dist/assets/diagram-TYUNFSNR-BynvjQsr.js +200 -0
- package/web/dist/assets/dist-CumnGVmJ.js +1 -0
- package/web/dist/assets/ebnfDiagram-V4P3TTPT-BdqUCZnk.js +1 -0
- package/web/dist/assets/elk-QONTBCTQ-CYCP_9Jy.js +27 -0
- package/web/dist/assets/erDiagram-KYQIGQAA-C3L55l_F.js +99 -0
- package/web/dist/assets/eventmodeling-K75KTNOO-CTQdA_1v.js +1 -0
- package/web/dist/assets/flowDiagram-IUGLLWBU-COLKOzBg.js +1 -0
- package/web/dist/assets/ganttDiagram-R7GPNTJY-Be4Qk8Hx.js +292 -0
- package/web/dist/assets/gitGraph-VSP46ZUC-B59HXvj1.js +1 -0
- package/web/dist/assets/gitGraphDiagram-PDYL7XHY-C2A0VA6q.js +106 -0
- package/web/dist/assets/graphlib-DS17s2tU.js +1 -0
- package/web/dist/assets/icons-BvYhTENi.js +1 -0
- package/web/dist/assets/index-BNI6CNsY.css +1 -0
- package/web/dist/assets/index-BX-d2OBW.js +130 -0
- package/web/dist/assets/info-OHQRW6UA-DWlkKvmi.js +1 -0
- package/web/dist/assets/infoDiagram-MVDRKAX5-B8e6dTjN.js +2 -0
- package/web/dist/assets/init-C-OQMol4.js +1 -0
- package/web/dist/assets/ishikawaDiagram-HPEHV2GE-udXPYi9H.js +70 -0
- package/web/dist/assets/journeyDiagram-BOSHW7O7-DTyDkf5d.js +139 -0
- package/web/dist/assets/kanban-definition-FNSA4HC5-BXgV20qe.js +89 -0
- package/web/dist/assets/katex-B940_AAO.js +257 -0
- package/web/dist/assets/line-DVabuQAu.js +1 -0
- package/web/dist/assets/linear-gLkGxN9m.js +1 -0
- package/web/dist/assets/markdown-DAQZeY5V.js +14 -0
- package/web/dist/assets/mermaid-parser.core-BrXnuEs7.js +7 -0
- package/web/dist/assets/mermaid.core-BGbz3k1k.js +44 -0
- package/web/dist/assets/mindmap-definition-6OY57UG3-DbtP-bmk.js +98 -0
- package/web/dist/assets/ordinal-BDEzSJ7C.js +1 -0
- package/web/dist/assets/packet-JDAUHWVQ-iW8w3JF5.js +1 -0
- package/web/dist/assets/panels-DYiQiVWh.js +1 -0
- package/web/dist/assets/path-fybaL0A-.js +1 -0
- package/web/dist/assets/pegDiagram-ECIUJNBX-rBWJbaq4.js +1 -0
- package/web/dist/assets/pie-XZMESJXO-KHXEq-Yx.js +1 -0
- package/web/dist/assets/pieDiagram-GNMPY74T-DsW7yHm0.js +39 -0
- package/web/dist/assets/preload-helper-BLdHbfdN.js +1 -0
- package/web/dist/assets/profileChange-xrd7jkii.js +1 -0
- package/web/dist/assets/quadrantDiagram-D57K4MC3-DF_pwNhM.js +7 -0
- package/web/dist/assets/radar-ABXABTNO-BkAUJ_Zd.js +1 -0
- package/web/dist/assets/railroad-I3PHUGI6-BdnWRdGt.js +1 -0
- package/web/dist/assets/railroad-abnf-LNEFI6M7-C8K36-8b.js +1 -0
- package/web/dist/assets/railroad-ebnf-DWYD2UWJ-BlS25T3f.js +1 -0
- package/web/dist/assets/railroad-peg-JR7BVNR7-CBKGDi75.js +1 -0
- package/web/dist/assets/railroadDiagram-Y72NRBL7-DmrlMIvv.js +1 -0
- package/web/dist/assets/react-vendor-BlngCquv.js +19 -0
- package/web/dist/assets/requirementDiagram-EQYSW5RA-cvUq9H3I.js +84 -0
- package/web/dist/assets/rolldown-runtime-COiEfhsA.js +1 -0
- package/web/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
- package/web/dist/assets/sankeyDiagram-SY24JHO5-BdxXAbER.js +40 -0
- package/web/dist/assets/sequenceDiagram-BLEHNHQU-Druumi0k.js +169 -0
- package/web/dist/assets/settingsStore-RLUAWgIk.js +1 -0
- package/web/dist/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
- package/web/dist/assets/src-49LUQhkG.js +1 -0
- package/web/dist/assets/src-BWF7jMDv.js +1 -0
- package/web/dist/assets/state-_ZfNVAsd.js +1 -0
- package/web/dist/assets/stateDiagram-v2-A6IESKWZ-Jgh6qlrr.js +291 -0
- package/web/dist/assets/sttLanguages-aqoVC79g.js +2 -0
- package/web/dist/assets/swimlanes-B3ENRKFQ-4xKumvXQ.js +1 -0
- package/web/dist/assets/swimlanesDiagram-AYQRV4AK-bHcLKL3d.js +8 -0
- package/web/dist/assets/timeline-definition-JXYKGLGB-BYKhga9x.js +120 -0
- package/web/dist/assets/treeView-D4JQ5SDB-6-eTVUuH.js +1 -0
- package/web/dist/assets/treemap-SAJKECNS-Dxl8yCLE.js +1 -0
- package/web/dist/assets/ttsSettings-DHo3OsOq.js +15 -0
- package/web/dist/assets/types-JssxRFJn.js +1 -0
- package/web/dist/assets/useTranslation-BGmCDuQI.js +1 -0
- package/web/dist/assets/usecaseDiagram-WPOLBNNX-BaQ8nAv9.js +328 -0
- package/web/dist/assets/vennDiagram-Q3Y3IDCW-DkPvfmfT.js +34 -0
- package/web/dist/assets/wardley-7MLQ67FV-CZtI22aa.js +1 -0
- package/web/dist/assets/wardleyDiagram-IVAIDKWA-Dgi2OWQ4.js +78 -0
- package/web/dist/assets/websocket-C9e3h7VU.js +1 -0
- package/web/dist/assets/whatsNewStore-Bf_7lW8o.js +1 -0
- package/web/dist/assets/workspaceSemantics-RaIRer76.js +3 -0
- package/web/dist/assets/xychartDiagram-4URNHDU4-Ch96dep-.js +7 -0
- package/web/dist/favicon.svg +18 -39
- package/web/dist/icons/icon-1024.png +0 -0
- package/web/dist/icons/icon-180.png +0 -0
- package/web/dist/icons/icon-192.png +0 -0
- package/web/dist/icons/icon-512.png +0 -0
- package/web/dist/icons/icon-maskable-512.png +0 -0
- package/web/dist/index.html +46 -12
- package/web/dist/logo.svg +25 -39
- package/web/dist/manifest.webmanifest +2 -2
- package/web/dist/assets/AssistantsView-0aLB_cG6.js +0 -1
- package/web/dist/assets/AutomationView-CAMjPhJ2.js +0 -1
- package/web/dist/assets/ChannelConfigView-FcioeeYb.js +0 -8
- package/web/dist/assets/ConnectorsView-DERP7zAW.js +0 -1
- package/web/dist/assets/FileTreeView-hBtHBbAV.js +0 -11
- package/web/dist/assets/HookConfigView-NModtSB8.js +0 -1
- package/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/web/dist/assets/ModelsView-BPpO50C_.js +0 -1
- package/web/dist/assets/PluginsView-D0NE7zrt.js +0 -1
- package/web/dist/assets/ProjectsView-PIv7Gx4q.js +0 -1
- package/web/dist/assets/SessionGrid-BGpz0-op.css +0 -1
- package/web/dist/assets/SessionGrid-BsDL3lov.js +0 -47
- package/web/dist/assets/SettingsModal-DdebvEmv.js +0 -10
- package/web/dist/assets/SkillsView-BNoigImJ.js +0 -1
- package/web/dist/assets/TemplatesTab-D8Pa68fj.js +0 -1
- package/web/dist/assets/ToolsView-NY-yk5YX.js +0 -1
- package/web/dist/assets/WorkspaceDirPicker-C5knnArH.js +0 -6
- package/web/dist/assets/abap-BdImnpbu.js +0 -1
- package/web/dist/assets/actionscript-3-B3316cI-.js +0 -1
- package/web/dist/assets/ada-bCR0ucgS.js +0 -1
- package/web/dist/assets/ahk-CsyLZFj1.js +0 -1
- package/web/dist/assets/ahk2-8Zs4aa1G.js +0 -1
- package/web/dist/assets/andromeeda-C4gqWexZ.js +0 -1
- package/web/dist/assets/angular-html-DA-rfuFy.js +0 -1
- package/web/dist/assets/angular-ts-BrjP3tb8.js +0 -1
- package/web/dist/assets/apache-Pmp26Uib.js +0 -1
- package/web/dist/assets/apex-DhZFqWV2.js +0 -1
- package/web/dist/assets/apl-CORt7UWP.js +0 -1
- package/web/dist/assets/applescript-Co6uUVPk.js +0 -1
- package/web/dist/assets/ara-BRHolxvo.js +0 -1
- package/web/dist/assets/asciidoc-CSVQ5wI8.js +0 -1
- package/web/dist/assets/asm-D_Q5rh1f.js +0 -1
- package/web/dist/assets/astro-HNnZUWAn.js +0 -1
- package/web/dist/assets/aurora-x-D-2ljcwZ.js +0 -1
- package/web/dist/assets/awk-DMzUqQB5.js +0 -1
- package/web/dist/assets/ayu-dark-DYE7WIF3.js +0 -1
- package/web/dist/assets/ayu-light-BA47KaF1.js +0 -1
- package/web/dist/assets/ayu-mirage-32ctXXKs.js +0 -1
- package/web/dist/assets/ballerina-BFfxhgS-.js +0 -1
- package/web/dist/assets/bat-CickPsom.js +0 -1
- package/web/dist/assets/beancount-k_qm7-4y.js +0 -1
- package/web/dist/assets/berry-uYugtg8r.js +0 -1
- package/web/dist/assets/bibtex-CHM0blh-.js +0 -1
- package/web/dist/assets/bicep-Bmn6On1c.js +0 -1
- package/web/dist/assets/bird2-Bx8U0n9b.js +0 -1
- package/web/dist/assets/blade-2xfisSek.js +0 -1
- package/web/dist/assets/bsl-DlhNcFeZ.js +0 -1
- package/web/dist/assets/c-BIGW1oBm.js +0 -1
- package/web/dist/assets/c3-Dp5svz6Z.js +0 -1
- package/web/dist/assets/cadence-Bv_4Rxtq.js +0 -1
- package/web/dist/assets/cairo-KRGpt6FW.js +0 -1
- package/web/dist/assets/catppuccin-frappe-CZL1YF0i.js +0 -1
- package/web/dist/assets/catppuccin-latte-DH-8KZSZ.js +0 -1
- package/web/dist/assets/catppuccin-macchiato-B7yYVSCf.js +0 -1
- package/web/dist/assets/catppuccin-mocha-Ct7hS0mc.js +0 -1
- package/web/dist/assets/chapel-DTp_pixX.js +0 -1
- package/web/dist/assets/clarity-Dn5IMItf.js +0 -1
- package/web/dist/assets/clojure-P80f7IUj.js +0 -1
- package/web/dist/assets/cmake-D1j8_8rp.js +0 -1
- package/web/dist/assets/cobol-nBiQ_Alo.js +0 -1
- package/web/dist/assets/codeowners-Bp6g37R7.js +0 -1
- package/web/dist/assets/codeql-DsOJ9woJ.js +0 -1
- package/web/dist/assets/coffee-Ch7k5sss.js +0 -1
- package/web/dist/assets/common-lisp-Cg-RD9OK.js +0 -1
- package/web/dist/assets/coq-C7JzOVbR.js +0 -1
- package/web/dist/assets/cpp-BMRokrvK.js +0 -1
- package/web/dist/assets/crystal-DGywbUpC.js +0 -1
- package/web/dist/assets/csharp-DSvCPggb.js +0 -1
- package/web/dist/assets/css-CLj8gQPS.js +0 -1
- package/web/dist/assets/csv-fuZLfV_i.js +0 -1
- package/web/dist/assets/cue-D82EKSYY.js +0 -1
- package/web/dist/assets/cypher-COkxafJQ.js +0 -1
- package/web/dist/assets/d-85-TOEBH.js +0 -1
- package/web/dist/assets/dark-plus-C3mMm8J8.js +0 -1
- package/web/dist/assets/dart-bE4Kk8sk.js +0 -1
- package/web/dist/assets/dax-CEL-wOlO.js +0 -1
- package/web/dist/assets/desktop-BmXAJ9_W.js +0 -1
- package/web/dist/assets/diff-D97Zzqfu.js +0 -1
- package/web/dist/assets/docker-BcOcwvcX.js +0 -1
- package/web/dist/assets/dotenv-Da5cRb03.js +0 -1
- package/web/dist/assets/dracula-BzJJZx-M.js +0 -1
- package/web/dist/assets/dracula-soft-BXkSAIEj.js +0 -1
- package/web/dist/assets/dream-maker-BtqSS_iP.js +0 -1
- package/web/dist/assets/edge-FbVlp4U3.js +0 -1
- package/web/dist/assets/elixir-CkH2-t6x.js +0 -1
- package/web/dist/assets/elm-DbKCFpqz.js +0 -1
- package/web/dist/assets/emacs-lisp-C_m_b--Z.js +0 -1
- package/web/dist/assets/erb-DXfck5VN.js +0 -1
- package/web/dist/assets/erlang-DsQrWhSR.js +0 -1
- package/web/dist/assets/everforest-dark-BgDCqdQA.js +0 -1
- package/web/dist/assets/everforest-light-C8M2exoo.js +0 -1
- package/web/dist/assets/fennel-BYunw83y.js +0 -1
- package/web/dist/assets/fish-BvzEVeQv.js +0 -1
- package/web/dist/assets/fluent-C4IJs8-o.js +0 -1
- package/web/dist/assets/fortran-fixed-form-CkoXwp7k.js +0 -1
- package/web/dist/assets/fortran-free-form-BxgE0vQu.js +0 -1
- package/web/dist/assets/fsharp-CXgrBDvD.js +0 -1
- package/web/dist/assets/gdresource-TyuKm33G.js +0 -1
- package/web/dist/assets/gdscript-DqcFQ5yU.js +0 -1
- package/web/dist/assets/gdshader-DkwncUOv.js +0 -1
- package/web/dist/assets/genie-D0YGMca9.js +0 -1
- package/web/dist/assets/gherkin-DyxjwDmM.js +0 -1
- package/web/dist/assets/git-commit-F4YmCXRG.js +0 -1
- package/web/dist/assets/git-rebase-r7XF79zn.js +0 -1
- package/web/dist/assets/github-dark-DHJKELXO.js +0 -1
- package/web/dist/assets/github-dark-default-Cuk6v7N8.js +0 -1
- package/web/dist/assets/github-dark-dimmed-DH5Ifo-i.js +0 -1
- package/web/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +0 -1
- package/web/dist/assets/github-light-DAi9KRSo.js +0 -1
- package/web/dist/assets/github-light-default-D7oLnXFd.js +0 -1
- package/web/dist/assets/github-light-high-contrast-BfjtVDDH.js +0 -1
- package/web/dist/assets/gleam-BspZqrRM.js +0 -1
- package/web/dist/assets/glimmer-js-ByusRIyA.js +0 -1
- package/web/dist/assets/glimmer-ts-BfAWNZQY.js +0 -1
- package/web/dist/assets/glsl-DplSGwfg.js +0 -1
- package/web/dist/assets/gn-n2N0HUVH.js +0 -1
- package/web/dist/assets/gnuplot-DdkO51Og.js +0 -1
- package/web/dist/assets/go-C27-OAKa.js +0 -1
- package/web/dist/assets/graphql-ChdNCCLP.js +0 -1
- package/web/dist/assets/groovy-gcz8RCvz.js +0 -1
- package/web/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +0 -1
- package/web/dist/assets/gruvbox-dark-medium-GsRaNv29.js +0 -1
- package/web/dist/assets/gruvbox-dark-soft-CVdnzihN.js +0 -1
- package/web/dist/assets/gruvbox-light-hard-CH1njM8p.js +0 -1
- package/web/dist/assets/gruvbox-light-medium-DRw_LuNl.js +0 -1
- package/web/dist/assets/gruvbox-light-soft-hJgmCMqR.js +0 -1
- package/web/dist/assets/hack-BWmVpMyf.js +0 -1
- package/web/dist/assets/haml-D5jkg6IW.js +0 -1
- package/web/dist/assets/handlebars-BpdQsYii.js +0 -1
- package/web/dist/assets/haskell-Df6bDoY_.js +0 -1
- package/web/dist/assets/haxe-CfZj7gIn.js +0 -1
- package/web/dist/assets/hcl-BWvSN4gD.js +0 -1
- package/web/dist/assets/hjson-D5-asLiD.js +0 -1
- package/web/dist/assets/hlsl-D3lLCCz7.js +0 -1
- package/web/dist/assets/horizon-BUw7H-hv.js +0 -1
- package/web/dist/assets/horizon-bright-CUuTKBJd.js +0 -1
- package/web/dist/assets/houston-DnULxvSX.js +0 -1
- package/web/dist/assets/html-derivative-DlHx6ybY.js +0 -1
- package/web/dist/assets/html-pp8916En.js +0 -1
- package/web/dist/assets/http-jrhK8wxY.js +0 -1
- package/web/dist/assets/hurl-irOxFIW8.js +0 -1
- package/web/dist/assets/hxml-2-FPmUDs.js +0 -1
- package/web/dist/assets/hy-DFXneXwc.js +0 -1
- package/web/dist/assets/icons-BxNxyk-c.js +0 -804
- package/web/dist/assets/imba-DGztddWO.js +0 -1
- package/web/dist/assets/index-DaiVo1RY.css +0 -1
- package/web/dist/assets/index-RB5ffy32.js +0 -620
- package/web/dist/assets/ini-BEwlwnbL.js +0 -1
- package/web/dist/assets/java-CylS5w8V.js +0 -1
- package/web/dist/assets/javascript-wDzz0qaB.js +0 -1
- package/web/dist/assets/jinja-f2NsQr07.js +0 -1
- package/web/dist/assets/jison-wvAkD_A8.js +0 -1
- package/web/dist/assets/json-Cp-IABpG.js +0 -1
- package/web/dist/assets/json5-C9tS-k6U.js +0 -1
- package/web/dist/assets/jsonc-Des-eS-w.js +0 -1
- package/web/dist/assets/jsonl-DcaNXYhu.js +0 -1
- package/web/dist/assets/jsonnet-DFQXde-d.js +0 -1
- package/web/dist/assets/jssm-C2t-YnRu.js +0 -1
- package/web/dist/assets/jsx-g9-lgVsj.js +0 -1
- package/web/dist/assets/julia-5Bft2YPA.js +0 -1
- package/web/dist/assets/just-Cwhn7H3k.js +0 -1
- package/web/dist/assets/kanagawa-dragon-BuwD2xS4.js +0 -1
- package/web/dist/assets/kanagawa-lotus-C3DzagqV.js +0 -1
- package/web/dist/assets/kanagawa-wave-DFGoQZhC.js +0 -1
- package/web/dist/assets/kdl-DV7GczEv.js +0 -1
- package/web/dist/assets/kotlin-BdnUsdx6.js +0 -1
- package/web/dist/assets/kusto-wEQ09or8.js +0 -1
- package/web/dist/assets/laserwave-DUszq2jm.js +0 -1
- package/web/dist/assets/latex-D5pSuvFb.js +0 -1
- package/web/dist/assets/lean-BZvkOJ9d.js +0 -1
- package/web/dist/assets/less-B1dDrJ26.js +0 -1
- package/web/dist/assets/light-plus-B7mTdjB0.js +0 -1
- package/web/dist/assets/liquid-C0sCDyMI.js +0 -1
- package/web/dist/assets/llvm-BZoOZj88.js +0 -1
- package/web/dist/assets/log-2UxHyX5q.js +0 -1
- package/web/dist/assets/logo-BtOb2qkB.js +0 -1
- package/web/dist/assets/lua-BaeVxFsk.js +0 -1
- package/web/dist/assets/luau-BnpPk5vE.js +0 -1
- package/web/dist/assets/make-CHLpvVh8.js +0 -1
- package/web/dist/assets/markdown-B2L4Mq-x.js +0 -30
- package/web/dist/assets/markdown-Cvjx9yec.js +0 -1
- package/web/dist/assets/marko-DjSrsDqO.js +0 -1
- package/web/dist/assets/material-theme-D5KoaKCx.js +0 -1
- package/web/dist/assets/material-theme-darker-BfHTSMKl.js +0 -1
- package/web/dist/assets/material-theme-lighter-B0m2ddpp.js +0 -1
- package/web/dist/assets/material-theme-ocean-CyktbL80.js +0 -1
- package/web/dist/assets/material-theme-palenight-Csfq5Kiy.js +0 -1
- package/web/dist/assets/matlab-D7o27uSR.js +0 -1
- package/web/dist/assets/mdc-D1_yUvq7.js +0 -1
- package/web/dist/assets/mdx-Cmh6b_Ma.js +0 -1
- package/web/dist/assets/mermaid-CQcHuHx7.js +0 -1
- package/web/dist/assets/min-dark-CafNBF8u.js +0 -1
- package/web/dist/assets/min-light-CTRr51gU.js +0 -1
- package/web/dist/assets/mipsasm-CKIfxQSi.js +0 -1
- package/web/dist/assets/mojo-DJz3ZmWd.js +0 -1
- package/web/dist/assets/monokai-BRVnQi9A.js +0 -1
- package/web/dist/assets/moonbit-CHtswR0a.js +0 -1
- package/web/dist/assets/move-el3G9tDJ.js +0 -1
- package/web/dist/assets/narrat-DRg8JJMk.js +0 -1
- package/web/dist/assets/nextflow-C-mBbutL.js +0 -1
- package/web/dist/assets/nextflow-groovy-vE_lwT2v.js +0 -1
- package/web/dist/assets/nginx-BpAMiNFr.js +0 -1
- package/web/dist/assets/night-owl-C39BiMTA.js +0 -1
- package/web/dist/assets/night-owl-light-CMTm3GFP.js +0 -1
- package/web/dist/assets/nim-BIad80T-.js +0 -1
- package/web/dist/assets/nix-CwoSXNpI.js +0 -1
- package/web/dist/assets/nord-Ddv68eIx.js +0 -1
- package/web/dist/assets/nsis-BlV79W_Q.js +0 -1
- package/web/dist/assets/nushell-D3jzshHO.js +0 -1
- package/web/dist/assets/objective-c-DXmwc3jG.js +0 -1
- package/web/dist/assets/objective-cpp-CLxacb5B.js +0 -1
- package/web/dist/assets/ocaml-C0hk2d4L.js +0 -1
- package/web/dist/assets/odin-BBf5iR-q.js +0 -1
- package/web/dist/assets/one-dark-pro-DVMEJ2y_.js +0 -1
- package/web/dist/assets/one-light-C3Wv6jpd.js +0 -1
- package/web/dist/assets/openscad-C4EeE6gA.js +0 -1
- package/web/dist/assets/org-DM6o9KBp.js +0 -1
- package/web/dist/assets/panels-P_I7Q72_.js +0 -1
- package/web/dist/assets/pascal-D93ZcfNL.js +0 -1
- package/web/dist/assets/perl-B9cMNwum.js +0 -1
- package/web/dist/assets/php-Csjmro_R.js +0 -1
- package/web/dist/assets/pkl-u5AG7uiY.js +0 -1
- package/web/dist/assets/plastic-3e1v2bzS.js +0 -1
- package/web/dist/assets/plsql-ChMvpjG-.js +0 -1
- package/web/dist/assets/po-BTJTHyun.js +0 -1
- package/web/dist/assets/poimandres-CS3Unz2-.js +0 -1
- package/web/dist/assets/polar-C0HS_06l.js +0 -1
- package/web/dist/assets/postcss-CXtECtnM.js +0 -1
- package/web/dist/assets/powerquery-CEu0bR-o.js +0 -1
- package/web/dist/assets/powershell-BmBUJMz7.js +0 -1
- package/web/dist/assets/prisma-Vru482bI.js +0 -1
- package/web/dist/assets/profileChange-C7Jg9C61.js +0 -1
- package/web/dist/assets/prolog-CbFg5uaA.js +0 -1
- package/web/dist/assets/proto-C7zT0LnQ.js +0 -1
- package/web/dist/assets/pug-DKIMFp6K.js +0 -1
- package/web/dist/assets/puppet-BMWR74SV.js +0 -1
- package/web/dist/assets/purescript-CklMAg4u.js +0 -1
- package/web/dist/assets/python-B6aJPvgy.js +0 -1
- package/web/dist/assets/qml-3beO22l8.js +0 -1
- package/web/dist/assets/qmldir-C8lEn-DE.js +0 -1
- package/web/dist/assets/qss-IeuSbFQv.js +0 -1
- package/web/dist/assets/r-Cf5RLm7j.js +0 -1
- package/web/dist/assets/racket-BqYA7rlc.js +0 -1
- package/web/dist/assets/raku-DXvB9xmW.js +0 -1
- package/web/dist/assets/razor-BjBPvh-w.js +0 -1
- package/web/dist/assets/rbs-CpoqiR4B.js +0 -1
- package/web/dist/assets/react-vendor-B2V_5iSS.js +0 -9
- package/web/dist/assets/red-hvxz__6c.js +0 -1
- package/web/dist/assets/reg-C-SQnVFl.js +0 -1
- package/web/dist/assets/regexp-CDVJQ6XC.js +0 -1
- package/web/dist/assets/rel-C3B-1QV4.js +0 -1
- package/web/dist/assets/riscv-BM1_JUlF.js +0 -1
- package/web/dist/assets/ron-D8l8udqQ.js +0 -1
- package/web/dist/assets/rose-pine-5qJOZa0Y.js +0 -1
- package/web/dist/assets/rose-pine-dawn-zx0QlTCp.js +0 -1
- package/web/dist/assets/rose-pine-moon-C9pEdX9L.js +0 -1
- package/web/dist/assets/rosmsg-BJDFO7_C.js +0 -1
- package/web/dist/assets/rst-bs7f0vWN.js +0 -1
- package/web/dist/assets/ruby-C0TQ7zu5.js +0 -1
- package/web/dist/assets/rust-B1yitclQ.js +0 -1
- package/web/dist/assets/sas-DEy46yEz.js +0 -1
- package/web/dist/assets/sass-Cj5Yp3dK.js +0 -1
- package/web/dist/assets/scala-CqE71os6.js +0 -1
- package/web/dist/assets/scheme-C98Dy4si.js +0 -1
- package/web/dist/assets/scss-D5BDwBP9.js +0 -1
- package/web/dist/assets/sdbl-DVxCFoDh.js +0 -1
- package/web/dist/assets/shaderlab-Dg9Lc6iA.js +0 -1
- package/web/dist/assets/shellscript-Yzrsuije.js +0 -1
- package/web/dist/assets/shellsession-BADoaaVG.js +0 -1
- package/web/dist/assets/slack-dark-BthQWCQV.js +0 -1
- package/web/dist/assets/slack-ochin-DqwNpetd.js +0 -1
- package/web/dist/assets/smalltalk-BOQMe2GC.js +0 -1
- package/web/dist/assets/smithy-cds9vsN8.js +0 -1
- package/web/dist/assets/snazzy-light-Bw305WKR.js +0 -1
- package/web/dist/assets/solarized-dark-CpvCGNkr.js +0 -1
- package/web/dist/assets/solarized-light-Dlz6yCKv.js +0 -1
- package/web/dist/assets/solidity-DijEV5ha.js +0 -1
- package/web/dist/assets/soy-8wufbnw4.js +0 -1
- package/web/dist/assets/sparql-rVzFXLq3.js +0 -1
- package/web/dist/assets/splunk-BtCnVYZw.js +0 -1
- package/web/dist/assets/sql-CRqJ_cUM.js +0 -1
- package/web/dist/assets/ssh-config-_ykCGR6B.js +0 -1
- package/web/dist/assets/stata-DI20mbqo.js +0 -1
- package/web/dist/assets/state-0T92JV0u.js +0 -17
- package/web/dist/assets/stylus-BEDo0Tqx.js +0 -1
- package/web/dist/assets/surrealql-Cjom0U5J.js +0 -1
- package/web/dist/assets/svelte-Cy7k_4gC.js +0 -1
- package/web/dist/assets/swift-C2oV4EkX.js +0 -1
- package/web/dist/assets/synthwave-84-CbfX1IO0.js +0 -1
- package/web/dist/assets/system-verilog-0hqHdDBg.js +0 -1
- package/web/dist/assets/systemd-4A_iFExJ.js +0 -1
- package/web/dist/assets/talonscript-CkByrt1z.js +0 -1
- package/web/dist/assets/tasl-QIJgUcNo.js +0 -1
- package/web/dist/assets/tcl-dwOrl1Do.js +0 -1
- package/web/dist/assets/templ-DhtptRzy.js +0 -1
- package/web/dist/assets/terraform-BETggiCN.js +0 -1
- package/web/dist/assets/tex-D96PA37w.js +0 -1
- package/web/dist/assets/tokyo-night-hegEt444.js +0 -1
- package/web/dist/assets/toml-vGWfd6FD.js +0 -1
- package/web/dist/assets/ts-tags-D351s5mN.js +0 -1
- package/web/dist/assets/tsv-B_m7g4N7.js +0 -1
- package/web/dist/assets/tsx-COt5Ahok.js +0 -1
- package/web/dist/assets/turtle-BsS91CYL.js +0 -1
- package/web/dist/assets/twig-27uCiNez.js +0 -1
- package/web/dist/assets/typescript-BPQ3VLAy.js +0 -1
- package/web/dist/assets/typespec-CAFt9gP4.js +0 -1
- package/web/dist/assets/typst-BUadGCkm.js +0 -1
- package/web/dist/assets/v-BGw2Nkan.js +0 -1
- package/web/dist/assets/vala-CsfeWuGM.js +0 -1
- package/web/dist/assets/vb-Cu-pLBUe.js +0 -1
- package/web/dist/assets/verilog-nZwndyjY.js +0 -1
- package/web/dist/assets/vesper-DRje8inN.js +0 -1
- package/web/dist/assets/vhdl-CeAyd5Ju.js +0 -1
- package/web/dist/assets/viml-CJc9bBzg.js +0 -1
- package/web/dist/assets/vitesse-black-Bkuqu6BP.js +0 -1
- package/web/dist/assets/vitesse-dark-D0r3Knsf.js +0 -1
- package/web/dist/assets/vitesse-light-CVO1_9PV.js +0 -1
- package/web/dist/assets/vue-BqiEGhQt.js +0 -1
- package/web/dist/assets/vue-html-AaS7Mt5G.js +0 -1
- package/web/dist/assets/vue-vine-BoDAl6tE.js +0 -1
- package/web/dist/assets/vyper-CDx5xZoG.js +0 -1
- package/web/dist/assets/wasm-CG6Dc4jp.js +0 -1
- package/web/dist/assets/wasm-MzD3tlZU.js +0 -1
- package/web/dist/assets/wenyan-BV7otONQ.js +0 -1
- package/web/dist/assets/wgsl-Dx-B1_4e.js +0 -1
- package/web/dist/assets/wikitext-BhOHFoWU.js +0 -1
- package/web/dist/assets/wit-5i3qLPDT.js +0 -1
- package/web/dist/assets/wolfram-lXgVvXCa.js +0 -1
- package/web/dist/assets/xml-sdJ4AIDG.js +0 -1
- package/web/dist/assets/xsl-CtQFsRM5.js +0 -1
- package/web/dist/assets/yaml-Buea-lGh.js +0 -1
- package/web/dist/assets/zenscript-DVFEvuxE.js +0 -1
- package/web/dist/assets/zig-VOosw3JB.js +0 -1
|
@@ -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()
|
package/cli-wrapper.cjs
CHANGED
|
@@ -86,6 +86,10 @@ function main() {
|
|
|
86
86
|
const result = spawnSync(binaryPath, process.argv.slice(2), {
|
|
87
87
|
stdio: 'inherit',
|
|
88
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,
|
|
89
93
|
})
|
|
90
94
|
if (result.error) {
|
|
91
95
|
console.error(`[${WRAPPER_NAME}] Failed to execute native binary at ` + binaryPath)
|
package/install.cjs
CHANGED
|
@@ -15,6 +15,23 @@
|
|
|
15
15
|
// application" error, so its message is best-effort; install.cjs failure output
|
|
16
16
|
// above is the primary guidance when postinstall does run.
|
|
17
17
|
//
|
|
18
|
+
// WHY repairWindowsShims() EXISTS
|
|
19
|
+
//
|
|
20
|
+
// npm reads bin/dscode.exe's shebang while generating the `dscode` /
|
|
21
|
+
// `deepseekcode` shims. The placeholder has to start with `#!/bin/sh` (that is
|
|
22
|
+
// the runnable "not installed yet" message on Unix before this script replaces
|
|
23
|
+
// it), so on Windows cmd-shim copies that interpreter verbatim:
|
|
24
|
+
//
|
|
25
|
+
// & "/bin/sh" "$basedir/node_modules/@deepseekcode/cli/bin/dscode.exe" $args
|
|
26
|
+
//
|
|
27
|
+
// /bin/sh does not exist there, so every fresh `npm i -g` on Windows lands a
|
|
28
|
+
// `dscode` that dies with `/bin/sh.exe is not recognized` — while the real
|
|
29
|
+
// 100MB PE binary sits right next to it. The shims are written BEFORE this
|
|
30
|
+
// script runs, so they cannot be avoided; repairWindowsShims() rewrites them to
|
|
31
|
+
// exec the binary that is on disk by now. (`npm rebuild -g <pkg>` also repairs
|
|
32
|
+
// them: re-linking reads the shebang of the then-real PE binary, which has
|
|
33
|
+
// none.)
|
|
34
|
+
//
|
|
18
35
|
// Platform detection + PLATFORMS map is duplicated in cli-wrapper.cjs — keep in sync.
|
|
19
36
|
|
|
20
37
|
const { spawnSync } = require('child_process')
|
|
@@ -37,6 +54,14 @@ const WRAPPER_NAME = require('./package.json').name
|
|
|
37
54
|
const PACKAGE_PREFIX = WRAPPER_NAME
|
|
38
55
|
const BINARY_NAME = 'dscode'
|
|
39
56
|
|
|
57
|
+
// The command names npm creates shims for (dscode + deepseekcode). Taken from
|
|
58
|
+
// the published bin map so a rename never leaves a stale shim behind.
|
|
59
|
+
const BIN_MAP = require('./package.json').bin || {}
|
|
60
|
+
const SHIM_NAMES = Object.keys(BIN_MAP)
|
|
61
|
+
// Where the native binary lands, and therefore what every shim must exec: the
|
|
62
|
+
// published wrapper's bin field points at this path.
|
|
63
|
+
const BIN_TARGET = path.join(__dirname, 'bin', 'dscode.exe')
|
|
64
|
+
|
|
40
65
|
|
|
41
66
|
const PLATFORMS = {
|
|
42
67
|
'darwin-arm64': { pkg: PACKAGE_PREFIX + '-darwin-arm64', bin: BINARY_NAME },
|
|
@@ -118,6 +143,121 @@ function placeBinary(src, dest) {
|
|
|
118
143
|
}
|
|
119
144
|
}
|
|
120
145
|
|
|
146
|
+
// ---- Windows shim repair -------------------------------------------------
|
|
147
|
+
// The three templates below mirror what npm writes for a non-JS bin target, i.e.
|
|
148
|
+
// the shape it produces after re-linking against the real (shebang-less) PE
|
|
149
|
+
// binary — a repaired shim is indistinguishable from a healthy one.
|
|
150
|
+
|
|
151
|
+
function ps1Shim(target) {
|
|
152
|
+
return [
|
|
153
|
+
'#!/usr/bin/env pwsh',
|
|
154
|
+
'$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent',
|
|
155
|
+
'',
|
|
156
|
+
'$ret=0',
|
|
157
|
+
'# Support pipeline input',
|
|
158
|
+
'if ($MyInvocation.ExpectingInput) {',
|
|
159
|
+
' $input | & "$basedir/' + target + '" $args',
|
|
160
|
+
'} else {',
|
|
161
|
+
' & "$basedir/' + target + '" $args',
|
|
162
|
+
'}',
|
|
163
|
+
'$ret=$LASTEXITCODE',
|
|
164
|
+
'exit $ret',
|
|
165
|
+
'',
|
|
166
|
+
].join('\n')
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function cmdShim(target) {
|
|
170
|
+
return [
|
|
171
|
+
'@ECHO off',
|
|
172
|
+
'GOTO start',
|
|
173
|
+
':find_dp0',
|
|
174
|
+
'SET dp0=%~dp0',
|
|
175
|
+
'EXIT /b',
|
|
176
|
+
':start',
|
|
177
|
+
'SETLOCAL',
|
|
178
|
+
'CALL :find_dp0',
|
|
179
|
+
'"%dp0%\\' + target + '" %*',
|
|
180
|
+
'',
|
|
181
|
+
].join('\n')
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function shShim(target) {
|
|
185
|
+
return [
|
|
186
|
+
'#!/bin/sh',
|
|
187
|
+
"basedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")",
|
|
188
|
+
'',
|
|
189
|
+
'case `uname` in',
|
|
190
|
+
' *CYGWIN*|*MINGW*|*MSYS*)',
|
|
191
|
+
' if command -v cygpath > /dev/null 2>&1; then',
|
|
192
|
+
' basedir=`cygpath -w "$basedir"`',
|
|
193
|
+
' fi',
|
|
194
|
+
' ;;',
|
|
195
|
+
'esac',
|
|
196
|
+
'',
|
|
197
|
+
'exec "$basedir/' + target + '" "$@"',
|
|
198
|
+
'',
|
|
199
|
+
].join('\n')
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Path from the shim's directory to the binary, spelled the way each shim kind
|
|
203
|
+
// expects: npm uses forward slashes in .ps1/.sh and backslashes in .cmd.
|
|
204
|
+
function shimTarget(shimDir, exeAbs, sep) {
|
|
205
|
+
const rel = path.relative(shimDir, exeAbs)
|
|
206
|
+
const picked = rel && !path.isAbsolute(rel) ? rel : exeAbs
|
|
207
|
+
return sep === '\\' ? picked.replace(/\//g, '\\') : picked.replace(/\\/g, '/')
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function shimFor(ext, target) {
|
|
211
|
+
if (ext === '.ps1') return ps1Shim(target)
|
|
212
|
+
if (ext === '.cmd') return cmdShim(target)
|
|
213
|
+
return shShim(target)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Rewrite every shim under shimDirs that still calls the POSIX interpreter, and
|
|
217
|
+
// return the repaired paths (empty when there was nothing to do). Inputs are
|
|
218
|
+
// arguments so a test can drive it with a temp dir on any platform.
|
|
219
|
+
function repairShims(shimDirs, exeAbs) {
|
|
220
|
+
const repaired = []
|
|
221
|
+
for (const dir of shimDirs) {
|
|
222
|
+
for (const name of SHIM_NAMES) {
|
|
223
|
+
for (const ext of ['.ps1', '.cmd', '']) {
|
|
224
|
+
const file = path.join(dir, name + ext)
|
|
225
|
+
let text
|
|
226
|
+
try {
|
|
227
|
+
text = readFileSync(file, 'utf8')
|
|
228
|
+
} catch {
|
|
229
|
+
continue
|
|
230
|
+
}
|
|
231
|
+
// Skip the shebang line: a healthy .sh shim legitimately starts with
|
|
232
|
+
// `#!/bin/sh`. Only /bin/sh used as an *interpreter* is the bug.
|
|
233
|
+
if (!text.replace(/^[^\n]*\n/, '').includes('/bin/sh')) continue
|
|
234
|
+
try {
|
|
235
|
+
const target = shimTarget(dir, exeAbs, ext === '.cmd' ? '\\' : '/')
|
|
236
|
+
writeFileSync(file, shimFor(ext, target), { mode: 0o755 })
|
|
237
|
+
repaired.push(file)
|
|
238
|
+
} catch {
|
|
239
|
+
// A read-only prefix (`sudo npm i -g`, then `dscode` as a user) must
|
|
240
|
+
// not fail the install — the binary itself is already in place.
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return repaired
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Candidate shim directories: the npm prefix (global install) and
|
|
249
|
+
// node_modules/.bin (local install). Both derive from the package location, so
|
|
250
|
+
// the same code covers `npm i -g`, a project dependency and pnpm-style layouts.
|
|
251
|
+
function shimDirsFor(pkgDir) {
|
|
252
|
+
const nodeModules = path.dirname(path.dirname(pkgDir))
|
|
253
|
+
return [path.dirname(nodeModules), path.join(nodeModules, '.bin')]
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function repairWindowsShims() {
|
|
257
|
+
if (process.platform !== 'win32') return []
|
|
258
|
+
return repairShims(shimDirsFor(__dirname), BIN_TARGET)
|
|
259
|
+
}
|
|
260
|
+
|
|
121
261
|
function main() {
|
|
122
262
|
const platformKey = getPlatformKey()
|
|
123
263
|
const info = PLATFORMS[platformKey]
|
|
@@ -162,11 +302,22 @@ function main() {
|
|
|
162
302
|
// On Unix npm links `bin/dscode` → `bin/dscode.exe` and ignores the
|
|
163
303
|
// extension, so overwriting the .exe path replaces the running target on
|
|
164
304
|
// every platform. Same pattern as Claude Code / Bun npm packages.
|
|
165
|
-
const dest =
|
|
305
|
+
const dest = BIN_TARGET
|
|
166
306
|
|
|
167
307
|
try {
|
|
168
308
|
placeBinary(src, dest)
|
|
169
309
|
console.log(`[${WRAPPER_NAME} postinstall] Native binary placed → ${dest}`)
|
|
310
|
+
try {
|
|
311
|
+
const repaired = repairWindowsShims()
|
|
312
|
+
if (repaired.length > 0) {
|
|
313
|
+
console.log(
|
|
314
|
+
`[${WRAPPER_NAME} postinstall] Repaired ${repaired.length} Windows shim(s) → exec the native binary`,
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
} catch {
|
|
318
|
+
// Never fail the install over cosmetic shims: the binary is placed, and
|
|
319
|
+
// `npm rebuild -g ${WRAPPER_NAME}` repairs them too.
|
|
320
|
+
}
|
|
170
321
|
} catch (err) {
|
|
171
322
|
console.error(`[${WRAPPER_NAME} postinstall] Failed to place binary: ${err.message}`)
|
|
172
323
|
console.error(' Fallback: node ' + path.join(__dirname, 'cli-wrapper.cjs'))
|
|
@@ -174,4 +325,7 @@ function main() {
|
|
|
174
325
|
}
|
|
175
326
|
}
|
|
176
327
|
|
|
177
|
-
main()
|
|
328
|
+
if (require.main === module) main()
|
|
329
|
+
|
|
330
|
+
// Exported for the shim-repair tests; npm runs this file directly.
|
|
331
|
+
module.exports = { repairShims, shimFor, shimTarget }
|