@qwen-code/qwen-code 0.19.10 → 0.19.11-nightly.20260718.767a32484

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 (307) hide show
  1. package/bundled/qc-helper/docs/configuration/model-providers.md +11 -0
  2. package/bundled/qc-helper/docs/configuration/settings.md +15 -14
  3. package/bundled/qc-helper/docs/features/approval-mode.md +2 -2
  4. package/bundled/qc-helper/docs/features/channels/dingtalk.md +30 -0
  5. package/bundled/qc-helper/docs/features/channels/overview.md +66 -17
  6. package/bundled/qc-helper/docs/features/channels/wecom.md +8 -7
  7. package/bundled/qc-helper/docs/features/sandbox.md +2 -0
  8. package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +42 -7
  9. package/bundled/qc-helper/docs/qwen-serve.md +77 -46
  10. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
  11. package/bundled/review/SKILL.md +163 -403
  12. package/chunks/{MaxSizedBox-67ODZ4SZ.js → MaxSizedBox-ZFHA4QEQ.js} +30 -30
  13. package/chunks/{StandaloneSessionPicker-SIPBQT5Z.js → StandaloneSessionPicker-YRWOQVQA.js} +44 -44
  14. package/chunks/{acpAgent-VPZJXLFX.js → acpAgent-U2P2IESZ.js} +1423 -487
  15. package/chunks/{agent-Z7NWL6XL.js → agent-GQXX6X5Y.js} +26 -26
  16. package/chunks/{agent-headless-73HZ6ROQ.js → agent-headless-3572NBCK.js} +26 -26
  17. package/chunks/{anthropicContentGenerator-56U3YCP2.js → anthropicContentGenerator-Y65DMM64.js} +103 -18
  18. package/chunks/{artifact-tool-BWZZJ42H.js → artifact-tool-WR7I2XON.js} +2 -2
  19. package/chunks/{askUserQuestion-WU3S5A5T.js → askUserQuestion-B4FUTPHD.js} +2 -44
  20. package/chunks/{bridge-XFKW6S7Q.js → bridge-N5RMGD7G.js} +31 -33
  21. package/chunks/{ca-C2JTT2N5.js → ca-M3GQQ26D.js} +7 -2
  22. package/chunks/channel-worker-group-HZVJKLGX.js +21 -0
  23. package/chunks/{channel-worker-manager-5RWKSGEU.js → channel-worker-manager-3WDK4HNS.js} +34 -10
  24. package/chunks/{channel-worker-supervisor-PCDAZN4D.js → channel-worker-supervisor-U2W6Q5F7.js} +6 -4
  25. package/chunks/{chunk-YYPXHMWO.js → chunk-2XRGFF5K.js} +6 -6
  26. package/chunks/{chunk-ZKMGAFYV.js → chunk-2YSZE74N.js} +2 -2
  27. package/chunks/{chunk-L5U3ELZX.js → chunk-335ECZTA.js} +1 -1
  28. package/chunks/{chunk-5EBKKSBX.js → chunk-336KPNNV.js} +2 -2
  29. package/chunks/{chunk-Q5GLXH5Q.js → chunk-3CL5SEDT.js} +6 -6
  30. package/chunks/{chunk-2FO5GFKZ.js → chunk-3DJY4IFO.js} +1 -1
  31. package/chunks/{chunk-CJFNEBYB.js → chunk-3NWYQ7FX.js} +2 -2
  32. package/chunks/{chunk-WIASPMLX.js → chunk-3X2CFOUM.js} +358 -298
  33. package/chunks/{chunk-K7CRWKOE.js → chunk-3YJZ6WNY.js} +5812 -4520
  34. package/chunks/{chunk-Y66VOBRP.js → chunk-4CA4WUMS.js} +2 -2
  35. package/chunks/{chunk-LQIDP6K5.js → chunk-4CHDYDG3.js} +1 -1
  36. package/chunks/{chunk-TISZXPAX.js → chunk-4HCYNDMG.js} +1 -1
  37. package/chunks/chunk-4JBTZBCW.js +140 -0
  38. package/chunks/{chunk-TV6K2FB4.js → chunk-4RPARQ5D.js} +2 -2
  39. package/chunks/{chunk-RCEEXIOO.js → chunk-4XCVGEEX.js} +3 -3
  40. package/chunks/{chunk-N6FXRR6P.js → chunk-57RWF6R7.js} +1 -1
  41. package/chunks/chunk-5O34IMY5.js +59 -0
  42. package/chunks/{chunk-5LROA5W4.js → chunk-5QRK2VZG.js} +8 -8
  43. package/chunks/{chunk-7L4XBYVW.js → chunk-632KROVU.js} +10 -3
  44. package/chunks/{chunk-65N2J6V2.js → chunk-64XGKNSI.js} +3 -3
  45. package/chunks/{chunk-P6LART6G.js → chunk-66IT3EY2.js} +1059 -129
  46. package/chunks/{chunk-FXMC7SL2.js → chunk-6ITLKEOZ.js} +3 -3
  47. package/chunks/{chunk-F7NXQH4Y.js → chunk-6YIRYY3P.js} +1 -1
  48. package/chunks/{chunk-GGJII3FM.js → chunk-6Z5NRZVU.js} +92 -3
  49. package/chunks/{chunk-DPFBNG72.js → chunk-AEKYFMYE.js} +1 -1
  50. package/chunks/{chunk-2UUAIFQO.js → chunk-ANRANWVE.js} +9 -1
  51. package/chunks/{chunk-SXU3KKNI.js → chunk-ATJ7H5AS.js} +419 -76
  52. package/chunks/{chunk-6GETGQWP.js → chunk-C5NSOSF4.js} +64 -18
  53. package/chunks/{chunk-TQBODCFD.js → chunk-CMVFTMRD.js} +251 -3
  54. package/chunks/{chunk-DK33QJ3V.js → chunk-CZSAIBUB.js} +733 -14
  55. package/chunks/{chunk-3MX7D6QN.js → chunk-DASWPKXR.js} +32 -4
  56. package/chunks/{chunk-JSJFKYWT.js → chunk-DPSHAB47.js} +2 -2
  57. package/chunks/{chunk-7MJAZMXK.js → chunk-ECZFTRTP.js} +29 -78
  58. package/chunks/{chunk-H3FQOPPS.js → chunk-EKG3BHQY.js} +4 -4
  59. package/chunks/{chunk-FSA7ERJ2.js → chunk-F2RR4HO2.js} +1 -1
  60. package/chunks/{chunk-EQY6POVO.js → chunk-F5XYN5VF.js} +2 -2
  61. package/chunks/chunk-FEOZBUMT.js +77 -0
  62. package/chunks/{chunk-L62SEJWY.js → chunk-FHUXCRAF.js} +4 -4
  63. package/chunks/{chunk-OFEVHGVU.js → chunk-FSJGBUQI.js} +818 -31
  64. package/chunks/{chunk-FBU7WRZI.js → chunk-FUTHTZVV.js} +1 -1
  65. package/chunks/{chunk-ZRKBI3DP.js → chunk-FZRES4GK.js} +1 -1
  66. package/chunks/{chunk-OKAIGAYW.js → chunk-G274ETR6.js} +3 -3
  67. package/chunks/{chunk-6GKMJPOC.js → chunk-GA3WUOO7.js} +5 -5
  68. package/chunks/{chunk-X362TMXZ.js → chunk-GAQOQMHY.js} +8 -6
  69. package/chunks/{chunk-WLXYAKV7.js → chunk-GG6RSNWS.js} +9 -4
  70. package/chunks/{chunk-CEW4HDPK.js → chunk-GUNTLALV.js} +2484 -362
  71. package/chunks/{chunk-LXLTBIDP.js → chunk-HCCR43AY.js} +1 -1
  72. package/chunks/{chunk-RDRVMDWV.js → chunk-HIMIG6PI.js} +11 -11
  73. package/chunks/{chunk-MO7O5722.js → chunk-HQXQCIT2.js} +45 -5
  74. package/chunks/{chunk-LTNI523B.js → chunk-HT7L5FCZ.js} +28 -5
  75. package/chunks/{chunk-7NAWTFVY.js → chunk-IENO2YAT.js} +3 -3
  76. package/chunks/{chunk-3XJFUTNM.js → chunk-IK5TYYVR.js} +59 -12
  77. package/chunks/{chunk-AAR5SGMD.js → chunk-IVKLDHU6.js} +7 -5
  78. package/chunks/{chunk-6W6DI34P.js → chunk-IX7O5WI3.js} +180 -8
  79. package/chunks/{chunk-SPJQO2CE.js → chunk-J2MKYJKZ.js} +2 -2
  80. package/chunks/{chunk-SPUYQB4T.js → chunk-JBAQ5BYX.js} +1 -1
  81. package/chunks/{chunk-TYLOFD2U.js → chunk-JCJPZMJV.js} +1 -1
  82. package/chunks/chunk-JDIUK2Y3.js +226 -0
  83. package/chunks/{chunk-L37RC7MQ.js → chunk-JUVTV4NF.js} +1 -1
  84. package/chunks/{chunk-WDWJ4OQJ.js → chunk-K2GBHL73.js} +4 -4
  85. package/chunks/{chunk-HHEFI4RP.js → chunk-KEVDWH3U.js} +857 -137
  86. package/chunks/{chunk-YU56QGXX.js → chunk-KTKETHMY.js} +1 -1
  87. package/chunks/{chunk-WDW64OW3.js → chunk-LGY7PG7Q.js} +5 -5
  88. package/chunks/{chunk-E67NFMF4.js → chunk-LKR7QQ63.js} +37 -3
  89. package/chunks/{chunk-4YWLED2A.js → chunk-LSFVUGXT.js} +9 -6
  90. package/chunks/{chunk-W34A5MJH.js → chunk-LTD3CHGS.js} +1 -1
  91. package/chunks/chunk-LXXMOYPL.js +22 -0
  92. package/chunks/{chunk-BBNVFRGD.js → chunk-MI2V6IWU.js} +1 -1
  93. package/chunks/{chunk-UFOKA4PR.js → chunk-O2K6BLPZ.js} +114 -4
  94. package/chunks/{chunk-B5I2IIWY.js → chunk-OBYAX5QZ.js} +6 -6
  95. package/chunks/{chunk-V7EQTZYR.js → chunk-OCQ2QTFJ.js} +203 -47
  96. package/chunks/{chunk-VBRRNQB7.js → chunk-OPVIKLKK.js} +112 -25
  97. package/chunks/{chunk-2Z5UX4KI.js → chunk-OSSDHJDU.js} +1 -1
  98. package/chunks/{chunk-TTUO4DNG.js → chunk-OXOEOOQU.js} +126 -734
  99. package/chunks/{chunk-4FMG7EDJ.js → chunk-PWYLF7SS.js} +79 -16
  100. package/chunks/chunk-QFEY6OXH.js +45 -0
  101. package/chunks/{chunk-YX4LLZ3D.js → chunk-QPRDXJIC.js} +115 -40
  102. package/chunks/{chunk-7R4DPSRA.js → chunk-R3VWUU2E.js} +1 -1
  103. package/chunks/{chunk-XLIRF7IK.js → chunk-S4N3G4BB.js} +1 -1
  104. package/chunks/{chunk-ARKANCNX.js → chunk-SGPFJMRP.js} +1 -1
  105. package/chunks/{chunk-WTSXKLG5.js → chunk-SUARMD4Q.js} +1 -1
  106. package/chunks/{chunk-PZL23GTM.js → chunk-T3W4SDRB.js} +2 -0
  107. package/chunks/chunk-T4TZQJ7W.js +48 -0
  108. package/chunks/{chunk-K4PZ5F5T.js → chunk-TVYM3Q3J.js} +101 -8
  109. package/chunks/{chunk-4LD5APFL.js → chunk-TYQMGACW.js} +1 -0
  110. package/chunks/{chunk-6OATMEYN.js → chunk-U2LNTX56.js} +12 -4
  111. package/chunks/{chunk-422XAKCK.js → chunk-U2XBPBO3.js} +4 -3
  112. package/chunks/{chunk-LNUXFLLJ.js → chunk-U4FJ26D2.js} +54 -6
  113. package/chunks/{chunk-ZQTZXVHP.js → chunk-U6OPT4H2.js} +4 -18
  114. package/chunks/{chunk-7NFB7LBQ.js → chunk-UE5TZ55T.js} +8 -0
  115. package/chunks/{chunk-CUUXANEQ.js → chunk-URP6O2PP.js} +6 -1
  116. package/chunks/{chunk-GDQQRV43.js → chunk-V2FRLYHN.js} +3 -3
  117. package/chunks/{chunk-WIEO4CWB.js → chunk-VAJS2E2D.js} +1 -1
  118. package/chunks/{chunk-TXY2C3D2.js → chunk-VNN3JNYT.js} +1 -1
  119. package/chunks/{chunk-YHN5SUIJ.js → chunk-W7H223ZZ.js} +1 -1
  120. package/chunks/{chunk-WX6SD4IQ.js → chunk-WEPXQKGP.js} +1 -1
  121. package/chunks/{chunk-KSO42X3Z.js → chunk-X6YQWCIJ.js} +21 -2
  122. package/chunks/{chunk-URU5UEK6.js → chunk-XA7OKDWM.js} +135 -68
  123. package/chunks/{chunk-Q6TUALBE.js → chunk-XAAEDML2.js} +1 -1
  124. package/chunks/{chunk-KKRTYONM.js → chunk-XSPFQQRE.js} +3 -3
  125. package/chunks/{chunk-OATTJGPJ.js → chunk-Y72B36CP.js} +7 -7
  126. package/chunks/{chunk-ZPAHLFZU.js → chunk-Z2LBNX3R.js} +2 -2
  127. package/chunks/{chunk-XXJKGHZV.js → chunk-ZTSDZQZO.js} +131 -4
  128. package/chunks/{computer-use-IYTX45WA.js → computer-use-UIFBH25Y.js} +26 -26
  129. package/chunks/{config-utils-CFT33LTP.js → config-utils-2LHI7JXU.js} +3 -3
  130. package/chunks/{contextCommand-272V77WU.js → contextCommand-VGZHKEH2.js} +28 -28
  131. package/chunks/{create-sub-session-WNX2OQVX.js → create-sub-session-DIJOV6HV.js} +2 -2
  132. package/chunks/{create-sub-session-CBJMQLYP.js → create-sub-session-OFVI4H6I.js} +26 -26
  133. package/chunks/{cron-create-36TIFKRT.js → cron-create-34GVLSW5.js} +4 -4
  134. package/chunks/{cron-delete-OQD3WULU.js → cron-delete-NMVKUL45.js} +4 -4
  135. package/chunks/{cron-list-4533T2FH.js → cron-list-277ZOR7L.js} +4 -4
  136. package/chunks/{daemon-RNGFPMAB.js → daemon-72MEV3TY.js} +361 -84
  137. package/chunks/daemon-status-provider-ZJJ6AOG2.js +75 -0
  138. package/chunks/{de-2VCDRDGU.js → de-56TMDIKS.js} +7 -2
  139. package/chunks/{dist-3V3ZV6ML.js → dist-4W3UGU2A.js} +1 -1
  140. package/chunks/{dist-HNN7DR2L.js → dist-G6QCGO2K.js} +58 -30
  141. package/chunks/{dist-ERCPDVA6.js → dist-ILVRL322.js} +4 -51
  142. package/chunks/{dist-PHEPJLXD.js → dist-KEZ5JWH4.js} +2 -2
  143. package/chunks/{dist-JZE7F6YR.js → dist-LQHDHBPP.js} +1 -1
  144. package/chunks/{dist-MOEC47TR.js → dist-SVHAGOLN.js} +1 -1
  145. package/chunks/{earlyInputCapture-EN4BRREQ.js → earlyInputCapture-NPF4PVUE.js} +27 -27
  146. package/chunks/{edit-OMAF2QDR.js → edit-F7CT6NZH.js} +27 -27
  147. package/chunks/{en-NJCA3TAA.js → en-AXS2N62H.js} +12 -3
  148. package/chunks/{enter-worktree-BBZX52HG.js → enter-worktree-Z4ET3MZL.js} +26 -26
  149. package/chunks/{enterPlanMode-5NNFMBUY.js → enterPlanMode-VYR7T5NX.js} +27 -29
  150. package/chunks/{environment-7TEWMJYN.js → environment-MBTXL57Q.js} +28 -28
  151. package/chunks/{errors-I4VKVX3F.js → errors-HN36J4FR.js} +28 -28
  152. package/chunks/{exit-worktree-FUWRJI33.js → exit-worktree-RU7JYFMF.js} +26 -26
  153. package/chunks/exitPlanMode-LUBAWMZQ.js +390 -0
  154. package/chunks/{fast-path-ZA57TOH4.js → fast-path-RFT3CDNZ.js} +2 -2
  155. package/chunks/{fr-5F3E7WKD.js → fr-ZJPE5OVN.js} +7 -2
  156. package/chunks/{gemini-UOAKVXBG.js → gemini-37NTNKZF.js} +215 -231
  157. package/chunks/{geminiContentGenerator-G6UCE6MW.js → geminiContentGenerator-76HNOYNQ.js} +5 -5
  158. package/chunks/{glob-4GJQ2UFF.js → glob-DWD7JCZE.js} +32 -27
  159. package/chunks/{grep-5QSYXF2E.js → grep-NJRXFV5C.js} +32 -27
  160. package/chunks/{handleAutoUpdate-ULHNWL6R.js → handleAutoUpdate-7GBDXW6U.js} +30 -30
  161. package/chunks/{i18n-CYDUTF6F.js → i18n-MYD5VGED.js} +27 -27
  162. package/chunks/{initializer-NRFKUGIO.js → initializer-4DHPNAZG.js} +32 -32
  163. package/chunks/{installationInfo-WELKRHHE.js → installationInfo-RWOW6BZO.js} +27 -27
  164. package/chunks/{ja-66J6B53L.js → ja-57GG4QSL.js} +7 -2
  165. package/chunks/{keychain-token-storage-AU22CQI6.js → keychain-token-storage-K23CFKGN.js} +2 -2
  166. package/chunks/{list-JVDXEG2E.js → list-MMCNNHE7.js} +34 -34
  167. package/chunks/{loadedSettingsAdapter-WAM4VUTG.js → loadedSettingsAdapter-UK4JWPYU.js} +31 -31
  168. package/chunks/{loop-wakeup-MVUKDVCP.js → loop-wakeup-KCLY4XQM.js} +5 -5
  169. package/chunks/{ls-RXNIAQDE.js → ls-UNI4LAJ3.js} +4 -4
  170. package/chunks/{lsp-HB5LM5IL.js → lsp-HPACPJAN.js} +2 -2
  171. package/chunks/{mcp-YHOZN3ZM.js → mcp-AFCVA4UV.js} +31 -31
  172. package/chunks/{monitor-R7XZPJHQ.js → monitor-RK637BNO.js} +28 -27
  173. package/chunks/nonInteractiveCli-OUGWLHNV.js +129 -0
  174. package/chunks/{notebook-edit-6RNKE2L2.js → notebook-edit-LY2X3CMF.js} +27 -27
  175. package/chunks/{openaiContentGenerator-XNS5S64I.js → openaiContentGenerator-MDYDW7IA.js} +14 -14
  176. package/chunks/{pidfile-XE4RRR2P.js → pidfile-2NUYRLKB.js} +27 -27
  177. package/chunks/processUtils-7QH3VBVN.js +29 -0
  178. package/chunks/{pt-TFZO5Y6T.js → pt-MCGZ3RZ4.js} +7 -2
  179. package/chunks/{qwenContentGenerator-APDPJ3VN.js → qwenContentGenerator-3HT4TVDL.js} +28 -28
  180. package/chunks/{qwenOAuth2-LEYOU7RU.js → qwenOAuth2-3A4TJVZT.js} +5 -5
  181. package/chunks/{read-file-XSUWXSR7.js → read-file-NE4FREFR.js} +10 -10
  182. package/chunks/{read-mcp-resource-6LRTZKXI.js → read-mcp-resource-C6NT52T6.js} +2 -2
  183. package/chunks/{record-artifact-PMDTY4OS.js → record-artifact-ENCU7QCL.js} +2 -2
  184. package/chunks/{ripGrep-APB3CDMU.js → ripGrep-DBLXWQCJ.js} +26 -26
  185. package/chunks/{ru-4L4LFHIT.js → ru-GA3NZW5Q.js} +7 -2
  186. package/chunks/{run-qwen-serve-NWTGPERT.js → run-qwen-serve-3NOCI6IL.js} +63 -39
  187. package/chunks/{runtime-EIO3NQKR.js → runtime-ZI7DSZSS.js} +35 -35
  188. package/chunks/{scheduler-JJDZBDRN.js → scheduler-SOVEP5K7.js} +26 -26
  189. package/chunks/{send-message-SR4WSXP2.js → send-message-5IFPZTPE.js} +3 -3
  190. package/chunks/{serve-WTIPB3EI.js → serve-DB6OCXIA.js} +31 -31
  191. package/chunks/{server-NJPHQHLH.js → server-LDY4YVU4.js} +2257 -648
  192. package/chunks/{session-O4AO7FTS.js → session-D6OG5SKX.js} +99 -72
  193. package/chunks/{settings-HQNDK7TG.js → settings-L52ZV5LO.js} +30 -30
  194. package/chunks/{shell-UIXM6PWG.js → shell-IU27OY3Q.js} +28 -26
  195. package/chunks/{skill-3XMB4ULV.js → skill-BSOJT7LE.js} +12 -12
  196. package/chunks/{spawnChannel-3R632QRM.js → spawnChannel-HQAM25DD.js} +28 -29
  197. package/chunks/{src-USZKPUOC.js → src-7ZBIMTJZ.js} +130 -51
  198. package/chunks/{standalone-update-L5XW3D7K.js → standalone-update-77457VVK.js} +28 -28
  199. package/chunks/{startInteractiveUI-CPZOL2WB.js → startInteractiveUI-S7WC6EZG.js} +2310 -1835
  200. package/chunks/{syntheticOutput-YKFNUQZD.js → syntheticOutput-ULOVVLY4.js} +3 -3
  201. package/chunks/{task-create-NUFOHU53.js → task-create-V2DCDSET.js} +7 -7
  202. package/chunks/{task-list-Z2IKQY3S.js → task-list-DPL5ZN55.js} +5 -5
  203. package/chunks/{task-stop-KQFIVQTJ.js → task-stop-CPEQWOT6.js} +2 -2
  204. package/chunks/{task-update-HKADXSTD.js → task-update-ZR45M5Q7.js} +7 -7
  205. package/chunks/{team-create-XXPRF3IQ.js → team-create-CO7HSUON.js} +26 -26
  206. package/chunks/{team-delete-SDNTGZLG.js → team-delete-HIWXCWJU.js} +5 -5
  207. package/chunks/{team-plan-approval-EOTTKHDW.js → team-plan-approval-QDZF5YZY.js} +26 -26
  208. package/chunks/{theme-manager-P6UITO2L.js → theme-manager-UTUT3I4P.js} +27 -27
  209. package/chunks/todoWrite-HK6B3RHJ.js +358 -0
  210. package/chunks/{tool-search-DDNGK2LR.js → tool-search-2UUORA35.js} +11 -11
  211. package/chunks/{total-session-admission-PL5N7DNY.js → total-session-admission-NTWG6G3F.js} +32 -34
  212. package/chunks/{trustedFolders-C5LMF3UR.js → trustedFolders-YF37ZCN5.js} +27 -27
  213. package/chunks/update-relaunch-QFNHPMZZ.js +87 -0
  214. package/chunks/{updateCheck-QTVVISH7.js → updateCheck-B6O42VMD.js} +30 -28
  215. package/chunks/{validateNonInterActiveAuth-RY4RKBQG.js → validateNonInterActiveAuth-SCIWJ4CX.js} +65 -65
  216. package/chunks/{version-U45RYOSD.js → version-7DA6LAI3.js} +1 -1
  217. package/chunks/{web-fetch-ZSPR3PRR.js → web-fetch-B62SJXM2.js} +5 -6
  218. package/chunks/{workflow-TCIAQYOA.js → workflow-Q5WG4THP.js} +27 -27
  219. package/chunks/{workspace-providers-status-I3G2HYLY.js → workspace-providers-status-WWLAGWQW.js} +34 -34
  220. package/chunks/{workspace-registration-store-IH5GLZ6Y.js → workspace-registration-store-BVYQVY2H.js} +1 -1
  221. package/chunks/{workspace-registry-QEKBELIX.js → workspace-registry-OD7ACADD.js} +32 -34
  222. package/chunks/{workspace-service-ORKHGLP3.js → workspace-service-4LYJWS63.js} +37 -38
  223. package/chunks/{workspace-skills-status-D7QCNDYY.js → workspace-skills-status-P2AQLZZS.js} +32 -32
  224. package/chunks/{write-file-JGRQR5VM.js → write-file-TEPGXNM3.js} +60 -27
  225. package/chunks/{zh-FSAH32JB.js → zh-E34DZ2S3.js} +12 -3
  226. package/chunks/{zh-TW-D2YIE2LO.js → zh-TW-PEI2ZWUR.js} +12 -3
  227. package/cli-entry.js +92 -8
  228. package/cli.js +11 -11
  229. package/locales/ca.js +12 -2
  230. package/locales/de.js +12 -2
  231. package/locales/en.js +20 -5
  232. package/locales/fr.js +12 -2
  233. package/locales/ja.js +12 -2
  234. package/locales/pt.js +12 -2
  235. package/locales/ru.js +12 -2
  236. package/locales/zh-TW.js +19 -3
  237. package/locales/zh.js +19 -3
  238. package/package.json +3 -3
  239. package/web-shell/assets/{arc-CUeDlxvE.js → arc-Dh-N5oEG.js} +1 -1
  240. package/web-shell/assets/{architectureDiagram-3BPJPVTR-PiUszkQA.js → architectureDiagram-3BPJPVTR-DBOQgtfF.js} +1 -1
  241. package/web-shell/assets/{blockDiagram-GPEHLZMM-s2wYSO7e.js → blockDiagram-GPEHLZMM-Dyxbuyju.js} +1 -1
  242. package/web-shell/assets/{c4Diagram-AAUBKEIU-DyLxZoz9.js → c4Diagram-AAUBKEIU-DCJR5HPT.js} +1 -1
  243. package/web-shell/assets/channel-DY0fkcKT.js +1 -0
  244. package/web-shell/assets/{chunk-2J33WTMH-Dsdai7Tk.js → chunk-2J33WTMH-BkMUcy3O.js} +1 -1
  245. package/web-shell/assets/{chunk-4BX2VUAB-DEosOjV7.js → chunk-4BX2VUAB-BSm4pLQk.js} +1 -1
  246. package/web-shell/assets/{chunk-55IACEB6-sNsRLTXf.js → chunk-55IACEB6-CuRr-XgW.js} +1 -1
  247. package/web-shell/assets/{chunk-727SXJPM-DkRNZzmh.js → chunk-727SXJPM-CLv7-w3t.js} +1 -1
  248. package/web-shell/assets/{chunk-AQP2D5EJ-BrsRNpzd.js → chunk-AQP2D5EJ-Cz_n3-JW.js} +1 -1
  249. package/web-shell/assets/{chunk-FMBD7UC4-CI039lpl.js → chunk-FMBD7UC4-CFT_62Hq.js} +1 -1
  250. package/web-shell/assets/{chunk-ND2GUHAM-M-pkeIfu.js → chunk-ND2GUHAM-DWz6DOZ6.js} +1 -1
  251. package/web-shell/assets/{chunk-QZHKN3VN-C4ckGNbH.js → chunk-QZHKN3VN-C-mRhUzw.js} +1 -1
  252. package/web-shell/assets/classDiagram-4FO5ZUOK-DBvJ6PZo.js +1 -0
  253. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-DBvJ6PZo.js +1 -0
  254. package/web-shell/assets/{cose-bilkent-S5V4N54A-BciKUAFq.js → cose-bilkent-S5V4N54A-BqCZS3i1.js} +1 -1
  255. package/web-shell/assets/{dagre-BM42HDAG-C1nTSgU6.js → dagre-BM42HDAG-BGasdP8i.js} +1 -1
  256. package/web-shell/assets/{diagram-2AECGRRQ-BDPNWr1m.js → diagram-2AECGRRQ-BSyLDkMy.js} +1 -1
  257. package/web-shell/assets/{diagram-5GNKFQAL-CNFhTszL.js → diagram-5GNKFQAL-CM-ZJxWC.js} +1 -1
  258. package/web-shell/assets/{diagram-KO2AKTUF-CjPa4p5a.js → diagram-KO2AKTUF-wJdzt_C5.js} +1 -1
  259. package/web-shell/assets/{diagram-LMA3HP47-ZzPykSyG.js → diagram-LMA3HP47-DiH2fhpL.js} +1 -1
  260. package/web-shell/assets/{diagram-OG6HWLK6-0UVtZ9A4.js → diagram-OG6HWLK6-BZ9z1ZBl.js} +1 -1
  261. package/web-shell/assets/{erDiagram-TEJ5UH35-CajDZCat.js → erDiagram-TEJ5UH35-BsyWDziR.js} +1 -1
  262. package/web-shell/assets/{flowDiagram-I6XJVG4X-BRuFBIvL.js → flowDiagram-I6XJVG4X-CzdkxIrq.js} +1 -1
  263. package/web-shell/assets/{ganttDiagram-6RSMTGT7-BevGmJqG.js → ganttDiagram-6RSMTGT7-javIv2r2.js} +1 -1
  264. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-DvPMpBMb.js → gitGraphDiagram-PVQCEYII-CjHstylC.js} +1 -1
  265. package/web-shell/assets/{index-DzHwQkQq.js → index-BnJGxpah.js} +1 -1
  266. package/web-shell/assets/index-DhXB9nTa.js +1161 -0
  267. package/web-shell/assets/index-vYHgZ7bL.css +5 -0
  268. package/web-shell/assets/{infoDiagram-5YYISTIA-Oixn7tA9.js → infoDiagram-5YYISTIA-yXuQsomo.js} +1 -1
  269. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BgKpeg-j.js → ishikawaDiagram-YF4QCWOH-a85JhE6F.js} +1 -1
  270. package/web-shell/assets/{journeyDiagram-JHISSGLW-74mwxIaA.js → journeyDiagram-JHISSGLW-Dak_4BVj.js} +1 -1
  271. package/web-shell/assets/{kanban-definition-UN3LZRKU-D4D6cEqA.js → kanban-definition-UN3LZRKU-COA-LuCV.js} +1 -1
  272. package/web-shell/assets/{linear-atZRE_L2.js → linear-DNAAAQWq.js} +1 -1
  273. package/web-shell/assets/{mermaid.core-KKudX-JC.js → mermaid.core-7Ff3aIUD.js} +5 -5
  274. package/web-shell/assets/{mindmap-definition-RKZ34NQL-CMCej9yG.js → mindmap-definition-RKZ34NQL-_rCOIODU.js} +1 -1
  275. package/web-shell/assets/{pieDiagram-4H26LBE5-nhx40X7q.js → pieDiagram-4H26LBE5-C9QCQ8EW.js} +1 -1
  276. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-CUmVcN3M.js → quadrantDiagram-W4KKPZXB-CsaE4FA8.js} +1 -1
  277. package/web-shell/assets/{requirementDiagram-4Y6WPE33-C_vyEwyy.js → requirementDiagram-4Y6WPE33-tV78naTg.js} +1 -1
  278. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-DU6G4VWR.js → sankeyDiagram-5OEKKPKP-Dk3Rw7BZ.js} +1 -1
  279. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DdeRR_KJ.js → sequenceDiagram-3UESZ5HK-BGsAWcMX.js} +1 -1
  280. package/web-shell/assets/{stateDiagram-AJRCARHV-C6iCI8ps.js → stateDiagram-AJRCARHV-zSxdtdoB.js} +1 -1
  281. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-vLEEtDpO.js +1 -0
  282. package/web-shell/assets/{timeline-definition-PNZ67QCA-B_Ea8Cb7.js → timeline-definition-PNZ67QCA-j0BQh9Go.js} +1 -1
  283. package/web-shell/assets/{vennDiagram-CIIHVFJN-BPUVZEJA.js → vennDiagram-CIIHVFJN-CRaUFFIu.js} +1 -1
  284. package/web-shell/assets/{wardley-L42UT6IY-BWEj0lKY.js → wardley-L42UT6IY-D7Py_ofm.js} +1 -1
  285. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-BvDsdIQw.js → wardleyDiagram-YWT4CUSO-BrDIAZcp.js} +1 -1
  286. package/web-shell/assets/{xychartDiagram-2RQKCTM6-crz0QhF_.js → xychartDiagram-2RQKCTM6-Cecdw-w2.js} +1 -1
  287. package/web-shell/index.html +2 -2
  288. package/chunks/channel-worker-group-K7QKH6IG.js +0 -13
  289. package/chunks/chunk-2HRYPZT5.js +0 -25
  290. package/chunks/chunk-B7NUUEXC.js +0 -311
  291. package/chunks/chunk-CARU2RR2.js +0 -24
  292. package/chunks/chunk-GYTKQYDB.js +0 -23
  293. package/chunks/chunk-LQU7EVFA.js +0 -30
  294. package/chunks/chunk-OCPBI7J5.js +0 -18
  295. package/chunks/chunk-OJAMDVF5.js +0 -66
  296. package/chunks/chunk-QAW7PIHT.js +0 -168
  297. package/chunks/chunk-TEGEBB2I.js +0 -122
  298. package/chunks/daemon-status-provider-L4STG5VO.js +0 -76
  299. package/chunks/exitPlanMode-IHCJ5EEI.js +0 -909
  300. package/chunks/nonInteractiveCli-NSOB6D74.js +0 -129
  301. package/chunks/todoWrite-YNXB27GB.js +0 -531
  302. package/web-shell/assets/channel-DkuJJ0qd.js +0 -1
  303. package/web-shell/assets/classDiagram-4FO5ZUOK-CwqHc0TB.js +0 -1
  304. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CwqHc0TB.js +0 -1
  305. package/web-shell/assets/index-Cnvv4VcI.css +0 -5
  306. package/web-shell/assets/index-D1Uyklxa.js +0 -1088
  307. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-C0_6nR6C.js +0 -1
@@ -2,12 +2,12 @@
2
2
  "use strict";
3
3
  import {
4
4
  buildPermissionSettings
5
- } from "./chunk-N6FXRR6P.js";
5
+ } from "./chunk-57RWF6R7.js";
6
6
  import {
7
7
  resolveVoiceStreamConfig,
8
8
  resolveVoiceTranscriptionConfig,
9
9
  transcribeVoiceAudio
10
- } from "./chunk-FXMC7SL2.js";
10
+ } from "./chunk-6ITLKEOZ.js";
11
11
  import {
12
12
  getVoiceSettingsScope,
13
13
  isSelectableVoiceModel,
@@ -16,7 +16,7 @@ import {
16
16
  readVoiceMode,
17
17
  readVoiceModel,
18
18
  resolveVoiceTransport
19
- } from "./chunk-DPFBNG72.js";
19
+ } from "./chunk-AEKYFMYE.js";
20
20
  import {
21
21
  WorkspacePermissionRulesSessionRequiredError,
22
22
  WorkspaceSettingsPartialPersistError,
@@ -24,9 +24,7 @@ import {
24
24
  WorkspaceSkillNotToggleableError
25
25
  } from "./chunk-OA4JVLSA.js";
26
26
  import {
27
- MCP_RESTART_SERVER_DEADLINE_MS
28
- } from "./chunk-OCPBI7J5.js";
29
- import {
27
+ MCP_RESTART_SERVER_DEADLINE_MS,
30
28
  McpServerNotFoundError,
31
29
  McpServerRestartFailedError,
32
30
  SessionNotFoundError,
@@ -34,7 +32,7 @@ import {
34
32
  WorkspaceInitPathEscapeError,
35
33
  WorkspaceInitRaceError,
36
34
  WorkspaceInitSymlinkError
37
- } from "./chunk-KSO42X3Z.js";
35
+ } from "./chunk-X6YQWCIJ.js";
38
36
  import {
39
37
  BridgeChannelClosedError,
40
38
  SERVE_CONTROL_EXT_METHODS,
@@ -48,34 +46,38 @@ import {
48
46
  createIdleWorkspaceProvidersStatus,
49
47
  createIdleWorkspaceSkillsStatus,
50
48
  mapDomainErrorToErrorKind
51
- } from "./chunk-CUUXANEQ.js";
49
+ } from "./chunk-URP6O2PP.js";
52
50
  import {
53
51
  getPersistScopeForModelSelection,
54
52
  loadSettings
55
- } from "./chunk-6GETGQWP.js";
53
+ } from "./chunk-C5NSOSF4.js";
56
54
  import {
57
55
  getWorkspaceTrustStatus
58
- } from "./chunk-4YWLED2A.js";
56
+ } from "./chunk-LSFVUGXT.js";
59
57
  import {
60
58
  writeStderrLine
61
59
  } from "./chunk-YUZI3WAC.js";
62
60
  import {
63
- ModelsConfig
64
- } from "./chunk-K7CRWKOE.js";
61
+ ModelsConfig,
62
+ SkillManager,
63
+ require_yauzl
64
+ } from "./chunk-3YJZ6WNY.js";
65
65
  import {
66
+ Storage,
66
67
  createDebugLogger
67
- } from "./chunk-7NFB7LBQ.js";
68
+ } from "./chunk-UE5TZ55T.js";
68
69
  import {
69
70
  init_esbuild_shims
70
71
  } from "./chunk-5O2XNYP6.js";
71
72
  import {
72
- __name
73
+ __name,
74
+ __toESM
73
75
  } from "./chunk-J2S4EL5Y.js";
74
76
 
75
77
  // packages/cli/src/serve/workspace-service/index.ts
76
78
  init_esbuild_shims();
77
- import { promises as fs, constants as fsConstants } from "node:fs";
78
- import * as path from "node:path";
79
+ import { promises as fs2, constants as fsConstants } from "node:fs";
80
+ import * as path2 from "node:path";
79
81
 
80
82
  // packages/cli/src/services/voice-service.ts
81
83
  init_esbuild_shims();
@@ -308,18 +310,748 @@ async function transcribeWorkspaceVoiceAudio(input) {
308
310
  }
309
311
  __name(transcribeWorkspaceVoiceAudio, "transcribeWorkspaceVoiceAudio");
310
312
 
313
+ // packages/cli/src/serve/workspace-skill-management.ts
314
+ init_esbuild_shims();
315
+ import { promises as fs } from "node:fs";
316
+ import { execFile } from "node:child_process";
317
+ import * as os from "node:os";
318
+ import * as path from "node:path";
319
+ import { promisify } from "node:util";
320
+ var import_yauzl = __toESM(require_yauzl(), 1);
321
+ var MAX_FILES = 128;
322
+ var MAX_FILE_BYTES = 2 * 1024 * 1024;
323
+ var MAX_TOTAL_BYTES = 6 * 1024 * 1024;
324
+ var MAX_PATH_LENGTH = 512;
325
+ var MAX_PATH_DEPTH = 16;
326
+ var MAX_WORKSPACE_SKILL_NAME_LENGTH = 256;
327
+ var execFileAsync = promisify(execFile);
328
+ var WorkspaceSkillManagementError = class extends Error {
329
+ constructor(code, message, statusCode = 400) {
330
+ super(message);
331
+ this.code = code;
332
+ this.statusCode = statusCode;
333
+ this.name = "WorkspaceSkillManagementError";
334
+ }
335
+ static {
336
+ __name(this, "WorkspaceSkillManagementError");
337
+ }
338
+ };
339
+ function skillError(code, message, statusCode = 400) {
340
+ throw new WorkspaceSkillManagementError(code, message, statusCode);
341
+ }
342
+ __name(skillError, "skillError");
343
+ function validateWorkspaceSkillName(name) {
344
+ const normalized = name.trim();
345
+ if (!normalized || normalized === "." || normalized === ".." || normalized.length > MAX_WORKSPACE_SKILL_NAME_LENGTH || !/^[A-Za-z0-9._-]+$/.test(normalized)) {
346
+ skillError("invalid_skill_name", "Invalid skill name");
347
+ }
348
+ return normalized;
349
+ }
350
+ __name(validateWorkspaceSkillName, "validateWorkspaceSkillName");
351
+ function decodeBase64(value) {
352
+ if (!value || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
353
+ skillError("invalid_skill_source", "Invalid base64 skill content");
354
+ }
355
+ const content = Buffer.from(value, "base64");
356
+ if (content.length > MAX_TOTAL_BYTES) {
357
+ skillError(
358
+ "skill_package_too_large",
359
+ "Skill package exceeds the allowed size",
360
+ 413
361
+ );
362
+ }
363
+ return content;
364
+ }
365
+ __name(decodeBase64, "decodeBase64");
366
+ function normalizeRelativePath(value) {
367
+ const normalized = value.replaceAll("\\", "/").replace(/^\.\//, "");
368
+ const segments = normalized.split("/");
369
+ if (!normalized || normalized.length > MAX_PATH_LENGTH || normalized.startsWith("/") || segments.length > MAX_PATH_DEPTH || segments.some((segment) => !segment || segment === "." || segment === "..")) {
370
+ skillError("invalid_skill_package", `Invalid skill file path: ${value}`);
371
+ }
372
+ return segments.join("/");
373
+ }
374
+ __name(normalizeRelativePath, "normalizeRelativePath");
375
+ function isPlatformMetadataPath(value) {
376
+ return value.replaceAll("\\", "/").split("/").some(
377
+ (segment) => segment === "__MACOSX" || segment === ".DS_Store" || segment.startsWith("._")
378
+ );
379
+ }
380
+ __name(isPlatformMetadataPath, "isPlatformMetadataPath");
381
+ function normalizePackageFiles(files) {
382
+ files = files.filter((file) => !isPlatformMetadataPath(file.relativePath));
383
+ if (!files.length || files.length > MAX_FILES) {
384
+ skillError(
385
+ "invalid_skill_package",
386
+ "Skill package has an invalid file count"
387
+ );
388
+ }
389
+ let normalized = files.map((file) => ({
390
+ relativePath: normalizeRelativePath(file.relativePath),
391
+ content: file.content
392
+ }));
393
+ if (!normalized.some((file) => file.relativePath === "SKILL.md")) {
394
+ const roots = new Set(
395
+ normalized.map((file) => file.relativePath.split("/")[0])
396
+ );
397
+ if (roots.size !== 1) {
398
+ skillError(
399
+ "skill_manifest_missing",
400
+ "Skill package must contain a root SKILL.md"
401
+ );
402
+ }
403
+ const [root] = roots;
404
+ normalized = normalized.map((file) => ({
405
+ ...file,
406
+ relativePath: file.relativePath.slice(root.length + 1)
407
+ }));
408
+ }
409
+ const seen = /* @__PURE__ */ new Set();
410
+ let totalBytes = 0;
411
+ for (const file of normalized) {
412
+ file.relativePath = normalizeRelativePath(file.relativePath);
413
+ if (seen.has(file.relativePath)) {
414
+ skillError(
415
+ "invalid_skill_package",
416
+ `Duplicate skill file path: ${file.relativePath}`
417
+ );
418
+ }
419
+ seen.add(file.relativePath);
420
+ if (file.content.length > MAX_FILE_BYTES) {
421
+ skillError(
422
+ "skill_package_too_large",
423
+ `Skill file is too large: ${file.relativePath}`,
424
+ 413
425
+ );
426
+ }
427
+ totalBytes += file.content.length;
428
+ if (totalBytes > MAX_TOTAL_BYTES) {
429
+ skillError(
430
+ "skill_package_too_large",
431
+ "Skill package exceeds the allowed size",
432
+ 413
433
+ );
434
+ }
435
+ }
436
+ if (!seen.has("SKILL.md")) {
437
+ skillError(
438
+ "skill_manifest_missing",
439
+ "Skill package must contain a root SKILL.md"
440
+ );
441
+ }
442
+ return normalized;
443
+ }
444
+ __name(normalizePackageFiles, "normalizePackageFiles");
445
+ function githubRequestError(code, status, resource) {
446
+ const message = status === 404 ? `GitHub ${resource} was not found; check the repository URL, branch, and path` : status === 401 ? "GitHub authentication failed; check GH_TOKEN or GITHUB_TOKEN" : status === 403 ? "GitHub access was denied; the repository may be private or API rate-limited" : status === 429 ? "GitHub API rate limit exceeded; try again later or configure GH_TOKEN" : `GitHub request failed (HTTP ${status})`;
447
+ return new WorkspaceSkillManagementError(
448
+ code,
449
+ message,
450
+ status === 404 ? 404 : 502
451
+ );
452
+ }
453
+ __name(githubRequestError, "githubRequestError");
454
+ async function fetchBytes(url, githubToken) {
455
+ const response = await fetch(url, {
456
+ headers: {
457
+ Accept: "application/vnd.github+json",
458
+ "User-Agent": "qwen-code",
459
+ ...githubToken ? { Authorization: `Bearer ${githubToken}` } : {}
460
+ }
461
+ });
462
+ if (!response.ok) {
463
+ throw githubRequestError(
464
+ "github_skill_download_failed",
465
+ response.status,
466
+ "Skill file"
467
+ );
468
+ }
469
+ const declared = Number(response.headers.get("content-length"));
470
+ if (Number.isFinite(declared) && declared > MAX_FILE_BYTES) {
471
+ skillError("skill_package_too_large", "Skill file is too large", 413);
472
+ }
473
+ if (!response.body) return Buffer.alloc(0);
474
+ const reader = response.body.getReader();
475
+ const chunks = [];
476
+ let size = 0;
477
+ try {
478
+ while (true) {
479
+ const { done, value } = await reader.read();
480
+ if (done) break;
481
+ size += value.byteLength;
482
+ if (size > MAX_FILE_BYTES) {
483
+ await reader.cancel().catch(() => void 0);
484
+ skillError("skill_package_too_large", "Skill file is too large", 413);
485
+ }
486
+ chunks.push(Buffer.from(value));
487
+ }
488
+ } finally {
489
+ reader.releaseLock();
490
+ }
491
+ return Buffer.concat(chunks, size);
492
+ }
493
+ __name(fetchBytes, "fetchBytes");
494
+ async function downloadGitHubDirectory(owner, repo, ref, directory, githubToken, relativeRoot = "", depth = 0, state = {
495
+ files: [],
496
+ totalBytes: 0
497
+ }) {
498
+ if (depth > MAX_PATH_DEPTH)
499
+ skillError("invalid_skill_package", "GitHub Skill is nested too deeply");
500
+ const encodedDirectory = directory.split("/").filter(Boolean).map(encodeURIComponent).join("/");
501
+ const apiUrl = `https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents${encodedDirectory ? `/${encodedDirectory}` : ""}?ref=${encodeURIComponent(ref)}`;
502
+ const response = await fetch(apiUrl, {
503
+ headers: {
504
+ Accept: "application/vnd.github+json",
505
+ "User-Agent": "qwen-code",
506
+ ...githubToken ? { Authorization: `Bearer ${githubToken}` } : {}
507
+ }
508
+ });
509
+ if (!response.ok) {
510
+ throw githubRequestError(
511
+ "github_api_failed",
512
+ response.status,
513
+ "Skill path"
514
+ );
515
+ }
516
+ const items = await response.json();
517
+ if (!Array.isArray(items))
518
+ skillError("invalid_skill_source", "GitHub URL must point to SKILL.md");
519
+ for (const item of items) {
520
+ if (!item || typeof item !== "object") continue;
521
+ const record = item;
522
+ const itemName = typeof record["name"] === "string" ? record["name"] : "";
523
+ const itemPath = typeof record["path"] === "string" ? record["path"] : "";
524
+ const itemType = typeof record["type"] === "string" ? record["type"] : "";
525
+ const relativePath = relativeRoot ? `${relativeRoot}/${itemName}` : itemName;
526
+ if (itemType === "dir") {
527
+ await downloadGitHubDirectory(
528
+ owner,
529
+ repo,
530
+ ref,
531
+ itemPath,
532
+ githubToken,
533
+ relativePath,
534
+ depth + 1,
535
+ state
536
+ );
537
+ } else if (itemType === "file") {
538
+ const downloadUrl = record["download_url"];
539
+ if (typeof downloadUrl !== "string") continue;
540
+ const parsedDownloadUrl = new URL(downloadUrl);
541
+ if (parsedDownloadUrl.protocol !== "https:" || parsedDownloadUrl.hostname !== "raw.githubusercontent.com") {
542
+ skillError(
543
+ "github_skill_download_failed",
544
+ "GitHub returned an invalid Skill file URL",
545
+ 502
546
+ );
547
+ }
548
+ const content = await fetchBytes(downloadUrl, githubToken);
549
+ state.files.push({ relativePath, content });
550
+ state.totalBytes += content.length;
551
+ if (state.files.length > MAX_FILES)
552
+ skillError("invalid_skill_package", "Skill package has too many files");
553
+ if (state.totalBytes > MAX_TOTAL_BYTES) {
554
+ skillError(
555
+ "skill_package_too_large",
556
+ "Skill package exceeds the allowed size",
557
+ 413
558
+ );
559
+ }
560
+ }
561
+ }
562
+ return state.files;
563
+ }
564
+ __name(downloadGitHubDirectory, "downloadGitHubDirectory");
565
+ async function downloadGitHubDirectoryWithGit(owner, repo, ref, directory) {
566
+ const checkout = await fs.mkdtemp(path.join(os.tmpdir(), "qwen-skill-git-"));
567
+ try {
568
+ await execFileAsync(
569
+ "git",
570
+ [
571
+ "clone",
572
+ "--depth",
573
+ "1",
574
+ "--filter=blob:none",
575
+ "--sparse",
576
+ "--branch",
577
+ ref,
578
+ `https://github.com/${owner}/${repo}.git`,
579
+ checkout
580
+ ],
581
+ { timeout: 6e4, maxBuffer: 1024 * 1024 }
582
+ );
583
+ if (directory) {
584
+ await execFileAsync(
585
+ "git",
586
+ ["-C", checkout, "sparse-checkout", "set", "--cone", directory],
587
+ { timeout: 3e4, maxBuffer: 1024 * 1024 }
588
+ );
589
+ } else {
590
+ await execFileAsync(
591
+ "git",
592
+ ["-C", checkout, "sparse-checkout", "disable"],
593
+ { timeout: 3e4, maxBuffer: 1024 * 1024 }
594
+ );
595
+ }
596
+ return await filesFromFolder(path.join(checkout, directory));
597
+ } catch (error) {
598
+ if (error instanceof WorkspaceSkillManagementError) throw error;
599
+ throw new WorkspaceSkillManagementError(
600
+ "github_skill_download_failed",
601
+ `Failed to download GitHub Skill: ${error instanceof Error ? error.message : String(error)}`,
602
+ 502
603
+ );
604
+ } finally {
605
+ await fs.rm(checkout, { recursive: true, force: true });
606
+ }
607
+ }
608
+ __name(downloadGitHubDirectoryWithGit, "downloadGitHubDirectoryWithGit");
609
+ async function downloadGitHubSkill(sourceUrl, githubToken) {
610
+ let url;
611
+ try {
612
+ url = new URL(sourceUrl);
613
+ } catch {
614
+ skillError("invalid_skill_source", "Invalid GitHub Skill URL");
615
+ }
616
+ if (url.protocol !== "https:")
617
+ skillError("invalid_skill_source", "GitHub URL must use HTTPS");
618
+ if (url.hostname === "raw.githubusercontent.com") {
619
+ if (!url.pathname.endsWith("/SKILL.md")) {
620
+ skillError("invalid_skill_source", "GitHub URL must point to SKILL.md");
621
+ }
622
+ return [
623
+ {
624
+ relativePath: "SKILL.md",
625
+ content: await fetchBytes(url.toString(), githubToken)
626
+ }
627
+ ];
628
+ }
629
+ if (url.hostname !== "github.com") {
630
+ skillError("invalid_skill_source", "Only GitHub Skill URLs are supported");
631
+ }
632
+ let segments;
633
+ try {
634
+ segments = url.pathname.split("/").filter(Boolean).map(decodeURIComponent);
635
+ } catch {
636
+ skillError("invalid_skill_source", "Invalid GitHub Skill URL");
637
+ }
638
+ if (segments.length < 5 || segments[2] !== "blob" || segments.at(-1) !== "SKILL.md") {
639
+ skillError(
640
+ "invalid_skill_source",
641
+ "GitHub URL must point to a repository SKILL.md file"
642
+ );
643
+ }
644
+ const [owner, repo, , ref, ...filePath] = segments;
645
+ if (!owner || !repo || !ref || ref.startsWith("-") || !/^[A-Za-z0-9._/+-]+$/.test(ref) || !/^[A-Za-z0-9._-]+$/.test(owner) || !/^[A-Za-z0-9._-]+$/.test(repo)) {
646
+ skillError("invalid_skill_source", "Invalid GitHub Skill URL");
647
+ }
648
+ const directory = filePath.slice(0, -1).join("/");
649
+ const directorySegments = directory.split("/");
650
+ if (directory && (directory.length > MAX_PATH_LENGTH || directory.includes("\\") || directory.startsWith("/") || directorySegments.length > MAX_PATH_DEPTH || directorySegments.some(
651
+ (segment) => !segment || segment === "." || segment === ".."
652
+ ))) {
653
+ skillError("invalid_skill_source", "Invalid GitHub Skill URL path");
654
+ }
655
+ try {
656
+ return await downloadGitHubDirectory(
657
+ owner,
658
+ repo,
659
+ ref,
660
+ directory,
661
+ githubToken
662
+ );
663
+ } catch (error) {
664
+ if (!(error instanceof WorkspaceSkillManagementError) || error.code !== "github_api_failed" || error.statusCode === 404) {
665
+ throw error;
666
+ }
667
+ return downloadGitHubDirectoryWithGit(owner, repo, ref, directory);
668
+ }
669
+ }
670
+ __name(downloadGitHubSkill, "downloadGitHubSkill");
671
+ function openZip(content) {
672
+ return new Promise((resolve3, reject) => {
673
+ (0, import_yauzl.fromBuffer)(content, { lazyEntries: true }, (error, zipFile) => {
674
+ if (error) reject(error);
675
+ else resolve3(zipFile);
676
+ });
677
+ });
678
+ }
679
+ __name(openZip, "openZip");
680
+ function readZipEntry(zipFile, entry) {
681
+ return new Promise((resolve3, reject) => {
682
+ zipFile.openReadStream(entry, (error, stream) => {
683
+ if (error) {
684
+ reject(error);
685
+ return;
686
+ }
687
+ const chunks = [];
688
+ let size = 0;
689
+ stream.on("data", (chunk) => {
690
+ size += chunk.length;
691
+ if (size > MAX_FILE_BYTES) {
692
+ stream.destroy(
693
+ new WorkspaceSkillManagementError(
694
+ "skill_package_too_large",
695
+ `Skill ZIP entry is too large: ${entry.fileName}`,
696
+ 413
697
+ )
698
+ );
699
+ } else {
700
+ chunks.push(chunk);
701
+ }
702
+ });
703
+ stream.on("error", reject);
704
+ stream.on("end", () => resolve3(Buffer.concat(chunks)));
705
+ });
706
+ });
707
+ }
708
+ __name(readZipEntry, "readZipEntry");
709
+ async function filesFromZip(content) {
710
+ const zipFile = await openZip(content);
711
+ const files = [];
712
+ let totalBytes = 0;
713
+ return new Promise((resolve3, reject) => {
714
+ let settled = false;
715
+ const finish = /* @__PURE__ */ __name((error) => {
716
+ if (settled) return;
717
+ settled = true;
718
+ zipFile.close();
719
+ if (error) reject(error);
720
+ else resolve3(files);
721
+ }, "finish");
722
+ zipFile.on("error", finish);
723
+ zipFile.on("entry", (entry) => {
724
+ const mode = entry.externalFileAttributes >>> 16 & 65535;
725
+ const fileType = mode & 61440;
726
+ if (fileType === 40960) {
727
+ finish(new Error("Skill ZIP contains a symbolic link"));
728
+ return;
729
+ }
730
+ if (entry.generalPurposeBitFlag & 1) {
731
+ finish(new Error("Encrypted Skill ZIP entries are not supported"));
732
+ return;
733
+ }
734
+ if (entry.fileName.endsWith("/") || fileType === 16384) {
735
+ zipFile.readEntry();
736
+ return;
737
+ }
738
+ if (files.length >= MAX_FILES) {
739
+ finish(
740
+ new WorkspaceSkillManagementError(
741
+ "invalid_skill_package",
742
+ "Skill ZIP contains too many files"
743
+ )
744
+ );
745
+ return;
746
+ }
747
+ if (entry.uncompressedSize > MAX_FILE_BYTES) {
748
+ finish(
749
+ new WorkspaceSkillManagementError(
750
+ "skill_package_too_large",
751
+ "Skill ZIP entry exceeds the allowed size",
752
+ 413
753
+ )
754
+ );
755
+ return;
756
+ }
757
+ if (totalBytes + entry.uncompressedSize > MAX_TOTAL_BYTES) {
758
+ finish(
759
+ new WorkspaceSkillManagementError(
760
+ "skill_package_too_large",
761
+ "Skill ZIP expands beyond the allowed size",
762
+ 413
763
+ )
764
+ );
765
+ return;
766
+ }
767
+ void readZipEntry(zipFile, entry).then((entryContent) => {
768
+ totalBytes += entryContent.length;
769
+ if (totalBytes > MAX_TOTAL_BYTES) {
770
+ finish(
771
+ new WorkspaceSkillManagementError(
772
+ "skill_package_too_large",
773
+ "Skill ZIP expands beyond the allowed size",
774
+ 413
775
+ )
776
+ );
777
+ return;
778
+ }
779
+ files.push({ relativePath: entry.fileName, content: entryContent });
780
+ if (!settled) zipFile.readEntry();
781
+ }, finish);
782
+ });
783
+ zipFile.on("end", () => finish());
784
+ zipFile.readEntry();
785
+ });
786
+ }
787
+ __name(filesFromZip, "filesFromZip");
788
+ async function filesFromSource(source, githubToken) {
789
+ try {
790
+ if (source.type === "github")
791
+ return normalizePackageFiles(
792
+ await downloadGitHubSkill(source.url, githubToken)
793
+ );
794
+ if (source.type === "folder")
795
+ return normalizePackageFiles(await filesFromFolder(source.path));
796
+ const archive = decodeBase64(source.contentBase64);
797
+ return normalizePackageFiles(await filesFromZip(archive));
798
+ } catch (error) {
799
+ if (error instanceof WorkspaceSkillManagementError) throw error;
800
+ const code = source.type === "github" ? "github_skill_download_failed" : source.type === "folder" ? "invalid_skill_folder" : "invalid_skill_package";
801
+ throw new WorkspaceSkillManagementError(
802
+ code,
803
+ error instanceof Error ? error.message : String(error),
804
+ source.type === "github" ? 502 : 400
805
+ );
806
+ }
807
+ }
808
+ __name(filesFromSource, "filesFromSource");
809
+ async function filesFromFolder(folderPath) {
810
+ if (!path.isAbsolute(folderPath)) {
811
+ skillError("invalid_skill_folder", "Skill folder path must be absolute");
812
+ }
813
+ if ((await fs.lstat(folderPath)).isSymbolicLink()) {
814
+ skillError(
815
+ "invalid_skill_folder",
816
+ "Skill folder path must not be a symbolic link"
817
+ );
818
+ }
819
+ const root = await fs.realpath(folderPath);
820
+ if (!(await fs.stat(root)).isDirectory()) {
821
+ skillError(
822
+ "invalid_skill_folder",
823
+ "Skill folder path must point to a directory"
824
+ );
825
+ }
826
+ const files = [];
827
+ let totalBytes = 0;
828
+ const visit = /* @__PURE__ */ __name(async (directory, relativeRoot = "", depth = 0) => {
829
+ if (depth > MAX_PATH_DEPTH)
830
+ skillError("invalid_skill_package", "Skill folder is nested too deeply");
831
+ for (const entry of await fs.readdir(directory, { withFileTypes: true })) {
832
+ if (depth === 0 && entry.name === ".git") continue;
833
+ const absolutePath = path.join(directory, entry.name);
834
+ const relativePath = relativeRoot ? `${relativeRoot}/${entry.name}` : entry.name;
835
+ if (entry.isSymbolicLink()) {
836
+ skillError(
837
+ "unsafe_skill_path",
838
+ "Skill folder contains a symbolic link"
839
+ );
840
+ }
841
+ if (entry.isDirectory()) {
842
+ await visit(absolutePath, relativePath, depth + 1);
843
+ continue;
844
+ }
845
+ if (!entry.isFile())
846
+ skillError("unsafe_skill_path", "Skill folder contains a special file");
847
+ if (files.length >= MAX_FILES) {
848
+ skillError("invalid_skill_package", "Skill package has too many files");
849
+ }
850
+ const stats = await fs.lstat(absolutePath);
851
+ if (stats.isSymbolicLink() || !stats.isFile()) {
852
+ skillError("unsafe_skill_path", "Skill folder contains an unsafe file");
853
+ }
854
+ if (stats.size > MAX_FILE_BYTES) {
855
+ skillError(
856
+ "skill_package_too_large",
857
+ `Skill file is too large: ${relativePath}`,
858
+ 413
859
+ );
860
+ }
861
+ totalBytes += stats.size;
862
+ if (totalBytes > MAX_TOTAL_BYTES) {
863
+ skillError(
864
+ "skill_package_too_large",
865
+ "Skill package exceeds the allowed size",
866
+ 413
867
+ );
868
+ }
869
+ const content = await fs.readFile(absolutePath);
870
+ if (content.length !== stats.size) {
871
+ skillError(
872
+ "invalid_skill_package",
873
+ `Skill file changed while reading: ${relativePath}`
874
+ );
875
+ }
876
+ files.push({ relativePath, content });
877
+ }
878
+ }, "visit");
879
+ await visit(root);
880
+ return files;
881
+ }
882
+ __name(filesFromFolder, "filesFromFolder");
883
+ function skillBaseDir(workspace, scope) {
884
+ return scope === "workspace" ? path.join(workspace, ".qwen", "skills") : path.join(Storage.getGlobalQwenDir(), "skills");
885
+ }
886
+ __name(skillBaseDir, "skillBaseDir");
887
+ async function removeInstallArtifacts(baseDir, skillName) {
888
+ const workDir = path.dirname(baseDir);
889
+ const workPrefix = `.${path.basename(baseDir)}-${skillName}`;
890
+ const locations = [
891
+ {
892
+ directory: baseDir,
893
+ prefixes: [`.${skillName}.installing-`, `.${skillName}.backup-`]
894
+ },
895
+ {
896
+ directory: workDir,
897
+ prefixes: [`${workPrefix}.installing-`, `${workPrefix}.backup-`]
898
+ }
899
+ ];
900
+ for (const { directory, prefixes } of locations) {
901
+ const entries = await fs.readdir(directory, { withFileTypes: true });
902
+ await Promise.all(
903
+ entries.filter(
904
+ (entry) => prefixes.some((prefix) => entry.name.startsWith(prefix))
905
+ ).map(
906
+ (entry) => fs.rm(path.join(directory, entry.name), {
907
+ recursive: true,
908
+ force: true
909
+ })
910
+ )
911
+ );
912
+ }
913
+ }
914
+ __name(removeInstallArtifacts, "removeInstallArtifacts");
915
+ async function ensureDirectoryWithoutSymlinks(directory) {
916
+ const missing = [];
917
+ let current = directory;
918
+ while (true) {
919
+ try {
920
+ const stats = await fs.lstat(current);
921
+ if (stats.isSymbolicLink() || !stats.isDirectory()) {
922
+ skillError("unsafe_skill_path", `Unsafe Skill directory: ${current}`);
923
+ }
924
+ break;
925
+ } catch (error) {
926
+ if (error.code !== "ENOENT") throw error;
927
+ missing.push(current);
928
+ const parent = path.dirname(current);
929
+ if (parent === current) throw error;
930
+ current = parent;
931
+ }
932
+ }
933
+ for (const entry of missing.reverse()) await fs.mkdir(entry);
934
+ }
935
+ __name(ensureDirectoryWithoutSymlinks, "ensureDirectoryWithoutSymlinks");
936
+ async function installWorkspaceSkill(workspace, request, githubToken) {
937
+ const skillName = validateWorkspaceSkillName(request.name);
938
+ const files = await filesFromSource(request.source, githubToken);
939
+ const baseDir = skillBaseDir(workspace, request.scope);
940
+ await ensureDirectoryWithoutSymlinks(baseDir);
941
+ await removeInstallArtifacts(baseDir, skillName);
942
+ const destination = path.join(baseDir, skillName);
943
+ const existing = await fs.lstat(destination).catch(() => void 0);
944
+ if (existing?.isSymbolicLink() || existing && !existing.isDirectory()) {
945
+ skillError("unsafe_skill_path", "Refusing to replace an unsafe Skill path");
946
+ }
947
+ const workDir = path.dirname(baseDir);
948
+ const workPrefix = `.${path.basename(baseDir)}-${skillName}`;
949
+ const staging = await fs.mkdtemp(
950
+ path.join(workDir, `${workPrefix}.installing-`)
951
+ );
952
+ const backup = path.join(workDir, `${workPrefix}.backup-${Date.now()}`);
953
+ let movedExisting = false;
954
+ try {
955
+ for (const file of files) {
956
+ const target = path.join(staging, ...file.relativePath.split("/"));
957
+ await fs.mkdir(path.dirname(target), { recursive: true });
958
+ await fs.writeFile(target, file.content);
959
+ }
960
+ const skillFile = path.join(staging, "SKILL.md");
961
+ let parsed;
962
+ try {
963
+ parsed = new SkillManager({}).parseSkillContent(
964
+ await fs.readFile(skillFile, "utf8"),
965
+ skillFile,
966
+ request.scope === "workspace" ? "project" : "user"
967
+ );
968
+ } catch (error) {
969
+ throw new WorkspaceSkillManagementError(
970
+ "invalid_skill_manifest",
971
+ error instanceof Error ? error.message : String(error)
972
+ );
973
+ }
974
+ if (parsed.name !== skillName) {
975
+ skillError(
976
+ "skill_name_mismatch",
977
+ `Skill name "${parsed.name}" does not match requested name "${skillName}"`
978
+ );
979
+ }
980
+ if (existing) {
981
+ await fs.rename(destination, backup);
982
+ movedExisting = true;
983
+ }
984
+ await fs.rename(staging, destination);
985
+ } catch (error) {
986
+ await fs.rm(staging, { recursive: true, force: true }).catch(() => void 0);
987
+ if (movedExisting) {
988
+ await fs.rename(backup, destination).catch(() => void 0);
989
+ }
990
+ throw error;
991
+ }
992
+ if (movedExisting) {
993
+ await fs.rm(backup, { recursive: true, force: true }).catch(() => void 0);
994
+ }
995
+ return {
996
+ skillName,
997
+ scope: request.scope,
998
+ installedPath: path.join(destination, "SKILL.md")
999
+ };
1000
+ }
1001
+ __name(installWorkspaceSkill, "installWorkspaceSkill");
1002
+ async function deleteWorkspaceSkill(workspace, scope, skillNameInput, installedPath) {
1003
+ const skillName = validateWorkspaceSkillName(skillNameInput);
1004
+ const skillDir = path.resolve(path.dirname(installedPath));
1005
+ const skillFile = path.resolve(installedPath);
1006
+ const allowedBaseDirs = new SkillManager({
1007
+ getProjectRoot: /* @__PURE__ */ __name(() => workspace, "getProjectRoot")
1008
+ }).getSkillsBaseDirs(scope === "workspace" ? "project" : "user").map((directory) => path.resolve(directory));
1009
+ const baseDir = path.dirname(skillDir);
1010
+ if (skillFile !== path.join(skillDir, "SKILL.md") || !allowedBaseDirs.includes(baseDir) || path.basename(skillDir) !== skillName) {
1011
+ skillError(
1012
+ "skill_not_managed",
1013
+ "Skill is not managed in the requested scope",
1014
+ 409
1015
+ );
1016
+ }
1017
+ const baseRealPath = await fs.realpath(baseDir);
1018
+ const skillDirStats = await fs.lstat(skillDir);
1019
+ const skillFileStats = await fs.lstat(skillFile);
1020
+ if (skillDirStats.isSymbolicLink() || !skillDirStats.isDirectory() || skillFileStats.isSymbolicLink() || !skillFileStats.isFile()) {
1021
+ skillError("unsafe_skill_path", "Refusing to delete an unsafe Skill path");
1022
+ }
1023
+ const skillDirRealPath = await fs.realpath(skillDir);
1024
+ if (path.dirname(skillDirRealPath) !== baseRealPath) {
1025
+ skillError("unsafe_skill_path", "Refusing to delete an unsafe Skill path");
1026
+ }
1027
+ const parsed = new SkillManager({}).parseSkillContent(
1028
+ await fs.readFile(skillFile, "utf8"),
1029
+ skillFile,
1030
+ scope === "workspace" ? "project" : "user"
1031
+ );
1032
+ if (parsed.name !== skillName) {
1033
+ skillError(
1034
+ "skill_name_mismatch",
1035
+ "Skill name does not match its installed directory"
1036
+ );
1037
+ }
1038
+ await fs.rm(skillDir, { recursive: true, force: true });
1039
+ return { skillName, scope, deleted: true };
1040
+ }
1041
+ __name(deleteWorkspaceSkill, "deleteWorkspaceSkill");
1042
+
311
1043
  // packages/cli/src/serve/workspace-service/index.ts
312
1044
  async function canonicalizeExistingAncestor(inputPath) {
313
1045
  let current = inputPath;
314
1046
  while (true) {
315
1047
  try {
316
- return await fs.realpath(current);
1048
+ return await fs2.realpath(current);
317
1049
  } catch (err) {
318
1050
  const code = err?.code;
319
1051
  if (code !== "ENOENT" && code !== "ENOTDIR" && code !== "ELOOP") {
320
1052
  throw err;
321
1053
  }
322
- const parent = path.dirname(current);
1054
+ const parent = path2.dirname(current);
323
1055
  if (parent === current) throw err;
324
1056
  current = parent;
325
1057
  }
@@ -328,9 +1060,9 @@ async function canonicalizeExistingAncestor(inputPath) {
328
1060
  __name(canonicalizeExistingAncestor, "canonicalizeExistingAncestor");
329
1061
  async function verifyParentPostOpen(target, wsCanonical, _fh) {
330
1062
  const parentCanonical = await canonicalizeExistingAncestor(
331
- path.dirname(target)
1063
+ path2.dirname(target)
332
1064
  );
333
- const within = parentCanonical === wsCanonical || parentCanonical.startsWith(wsCanonical + path.sep);
1065
+ const within = parentCanonical === wsCanonical || parentCanonical.startsWith(wsCanonical + path2.sep);
334
1066
  if (within) return;
335
1067
  throw new WorkspaceInitSymlinkError(
336
1068
  target,
@@ -345,14 +1077,14 @@ var TimeoutError = class extends Error {
345
1077
  }
346
1078
  };
347
1079
  async function withTimeout(promise, timeoutMs, label) {
348
- return await new Promise((resolve2, reject) => {
1080
+ return await new Promise((resolve3, reject) => {
349
1081
  const timeout = setTimeout(() => {
350
1082
  reject(new TimeoutError(`${label} timed out after ${timeoutMs}ms`));
351
1083
  }, timeoutMs);
352
1084
  promise.then(
353
1085
  (value) => {
354
1086
  clearTimeout(timeout);
355
- resolve2(value);
1087
+ resolve3(value);
356
1088
  },
357
1089
  (err) => {
358
1090
  clearTimeout(timeout);
@@ -374,6 +1106,7 @@ function createDaemonWorkspaceService(deps) {
374
1106
  persistDisabledSkills,
375
1107
  persistSetting,
376
1108
  persistSettings,
1109
+ skillInstallEnv,
377
1110
  voiceEnv,
378
1111
  voiceSettingsScope,
379
1112
  preheatAcpChild: preheatAcpChildOnBridge,
@@ -413,6 +1146,23 @@ function createDaemonWorkspaceService(deps) {
413
1146
  }
414
1147
  return status;
415
1148
  }, "getWorkspaceSkillsStatus");
1149
+ const refreshWorkspaceSkillsAfterMutation = /* @__PURE__ */ __name(async () => {
1150
+ lastWorkspaceSkillsStatus = void 0;
1151
+ workspaceSkillsStatusProvider?.invalidate?.(boundWorkspace);
1152
+ if (!(isChannelLive?.() ?? false)) return;
1153
+ try {
1154
+ await invokeWorkspaceCommand(
1155
+ SERVE_CONTROL_EXT_METHODS.workspaceSkillsRefresh,
1156
+ { cwd: boundWorkspace }
1157
+ );
1158
+ } catch (err) {
1159
+ if (!(err instanceof SessionNotFoundError) && !(err instanceof BridgeChannelClosedError)) {
1160
+ writeStderrLine(
1161
+ `qwen serve: workspace skill refresh after mutation failed: ${err instanceof Error ? err.message : String(err)}`
1162
+ );
1163
+ }
1164
+ }
1165
+ }, "refreshWorkspaceSkillsAfterMutation");
416
1166
  return {
417
1167
  // -- Status queries (delegate to ACP child via queryWorkspaceStatus) --
418
1168
  async getWorkspaceMcpStatus(_ctx) {
@@ -752,6 +1502,7 @@ function createDaemonWorkspaceService(deps) {
752
1502
  let sessionsFailed = 0;
753
1503
  if (persisted.changed) {
754
1504
  lastWorkspaceSkillsStatus = void 0;
1505
+ workspaceSkillsStatusProvider?.invalidate?.(boundWorkspace);
755
1506
  if (channelLive) {
756
1507
  try {
757
1508
  const refreshed = await invokeWorkspaceCommand(
@@ -792,18 +1543,51 @@ function createDaemonWorkspaceService(deps) {
792
1543
  sessionsFailed
793
1544
  };
794
1545
  },
1546
+ async installWorkspaceSkill(_ctx, request) {
1547
+ const result = await installWorkspaceSkill(
1548
+ boundWorkspace,
1549
+ request,
1550
+ skillInstallEnv?.["GH_TOKEN"] ?? skillInstallEnv?.["GITHUB_TOKEN"]
1551
+ );
1552
+ await refreshWorkspaceSkillsAfterMutation();
1553
+ return result;
1554
+ },
1555
+ async deleteWorkspaceSkill(_ctx, requestedSkillName, scope) {
1556
+ const normalizedName = requestedSkillName.trim().toLowerCase();
1557
+ const status = await getWorkspaceSkillsStatus();
1558
+ const skill = status.skills.find(
1559
+ (candidate) => candidate.name.trim().toLowerCase() === normalizedName
1560
+ );
1561
+ if (!skill) throw new WorkspaceSkillNotFoundError(requestedSkillName);
1562
+ const expectedLevel = scope === "workspace" ? "project" : "user";
1563
+ if (skill.level !== expectedLevel || !skill.installedPath) {
1564
+ throw new WorkspaceSkillManagementError(
1565
+ "skill_not_managed",
1566
+ "Skill is not managed in the requested scope",
1567
+ 409
1568
+ );
1569
+ }
1570
+ const result = await deleteWorkspaceSkill(
1571
+ boundWorkspace,
1572
+ scope,
1573
+ skill.name,
1574
+ skill.installedPath
1575
+ );
1576
+ await refreshWorkspaceSkillsAfterMutation();
1577
+ return result;
1578
+ },
795
1579
  async initWorkspace(ctx, opts) {
796
1580
  const filename = contextFilename;
797
- const target = path.resolve(boundWorkspace, filename);
798
- const withinWorkspace = target === boundWorkspace || target.startsWith(boundWorkspace + path.sep);
1581
+ const target = path2.resolve(boundWorkspace, filename);
1582
+ const withinWorkspace = target === boundWorkspace || target.startsWith(boundWorkspace + path2.sep);
799
1583
  if (!withinWorkspace) {
800
1584
  throw new WorkspaceInitPathEscapeError(filename, boundWorkspace);
801
1585
  }
802
- const wsCanonical = await fs.realpath(boundWorkspace);
1586
+ const wsCanonical = await fs2.realpath(boundWorkspace);
803
1587
  const parentCanonical = await canonicalizeExistingAncestor(
804
- path.dirname(target)
1588
+ path2.dirname(target)
805
1589
  );
806
- const parentWithinWorkspace = parentCanonical === wsCanonical || parentCanonical.startsWith(wsCanonical + path.sep);
1590
+ const parentWithinWorkspace = parentCanonical === wsCanonical || parentCanonical.startsWith(wsCanonical + path2.sep);
807
1591
  if (!parentWithinWorkspace) {
808
1592
  throw new WorkspaceInitSymlinkError(
809
1593
  target,
@@ -812,7 +1596,7 @@ function createDaemonWorkspaceService(deps) {
812
1596
  );
813
1597
  }
814
1598
  try {
815
- const lst = await fs.lstat(target);
1599
+ const lst = await fs2.lstat(target);
816
1600
  if (lst.isSymbolicLink()) {
817
1601
  throw new WorkspaceInitSymlinkError(
818
1602
  target,
@@ -834,7 +1618,7 @@ function createDaemonWorkspaceService(deps) {
834
1618
  }
835
1619
  let action = "created";
836
1620
  try {
837
- const existing = await fs.readFile(target, "utf8");
1621
+ const existing = await fs2.readFile(target, "utf8");
838
1622
  if (existing.trim().length > 0) {
839
1623
  const existingSize = Buffer.byteLength(existing, "utf8");
840
1624
  if (opts.force !== true) {
@@ -852,7 +1636,7 @@ function createDaemonWorkspaceService(deps) {
852
1636
  if (action === "created") {
853
1637
  let fh;
854
1638
  try {
855
- fh = await fs.open(target, "wx");
1639
+ fh = await fs2.open(target, "wx");
856
1640
  } catch (err) {
857
1641
  const code = err?.code;
858
1642
  if (code === "EEXIST") {
@@ -873,7 +1657,7 @@ function createDaemonWorkspaceService(deps) {
873
1657
  } else if (action === "overwrote") {
874
1658
  let overwriteFh;
875
1659
  try {
876
- overwriteFh = await fs.open(
1660
+ overwriteFh = await fs2.open(
877
1661
  target,
878
1662
  fsConstants.O_WRONLY | (fsConstants.O_NOFOLLOW ?? 0)
879
1663
  );
@@ -1087,6 +1871,9 @@ export {
1087
1871
  buildWorkspaceVoiceStatus,
1088
1872
  validateWorkspaceVoiceState,
1089
1873
  transcribeWorkspaceVoiceAudio,
1874
+ MAX_WORKSPACE_SKILL_NAME_LENGTH,
1875
+ WorkspaceSkillManagementError,
1876
+ validateWorkspaceSkillName,
1090
1877
  createDaemonWorkspaceService
1091
1878
  };
1092
1879
  /**