@qwen-code/qwen-code 0.21.8-nightly.20260810.55e20db328 → 0.21.9

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 (211) hide show
  1. package/README.md +2 -1
  2. package/bundled/qc-helper/docs/configuration/settings.md +2 -1
  3. package/bundled/qc-helper/docs/features/code-review.md +2 -0
  4. package/bundled/qc-helper/docs/qwen-serve.md +38 -37
  5. package/bundled/review/SKILL.md +7 -7
  6. package/chunks/{MaxSizedBox-A52T4GEU.js → MaxSizedBox-6BZANW7X.js} +3 -3
  7. package/chunks/{StandaloneSessionPicker-4J654SOB.js → StandaloneSessionPicker-VDC5KE7T.js} +19 -16
  8. package/chunks/{acpAgent-65AM4AOR.js → acpAgent-F2NSBCUF.js} +49 -40
  9. package/chunks/{agent-SVQ7U7NJ.js → agent-VOHJOEBB.js} +3 -3
  10. package/chunks/{agent-headless-XXGY2SQO.js → agent-headless-J5NFOPHP.js} +3 -3
  11. package/chunks/{bridge-Y32B5S3G.js → bridge-NQIZZLAS.js} +4 -4
  12. package/chunks/{channel-settings-store-OW43U6VB.js → channel-settings-store-VIY2OENO.js} +11 -9
  13. package/chunks/{chunk-OR6R3IUW.js → chunk-23VQTELM.js} +1 -1
  14. package/chunks/{chunk-VHXPSL57.js → chunk-3WDYBTTI.js} +4 -4
  15. package/chunks/{chunk-FAD7OC7V.js → chunk-3XVDTHBJ.js} +2 -2
  16. package/chunks/{chunk-7XX5IBXL.js → chunk-46YJDYCU.js} +6 -6
  17. package/chunks/{chunk-FYB4GIDW.js → chunk-4XQNB3KN.js} +2 -2
  18. package/chunks/chunk-5EJZE3FP.js +140 -0
  19. package/chunks/{chunk-DPMJLKUP.js → chunk-5RBDAGC6.js} +2 -2
  20. package/chunks/{chunk-D2D7J3EW.js → chunk-7AEPJGL4.js} +1 -1
  21. package/chunks/{chunk-HKI3KHAO.js → chunk-7GOYZQPR.js} +19 -1976
  22. package/chunks/{chunk-2ASQDZSJ.js → chunk-7S4JBJLU.js} +3 -3
  23. package/chunks/{chunk-EISUQQPS.js → chunk-ATMO54WE.js} +2 -2
  24. package/chunks/{chunk-NZMXUSKS.js → chunk-BAMN6XSD.js} +1 -1
  25. package/chunks/{chunk-2545EHZR.js → chunk-BIRWP6LU.js} +1 -1
  26. package/chunks/{chunk-UGUKH3SU.js → chunk-BZP4QPNK.js} +9 -9
  27. package/chunks/{chunk-AUWN7BAG.js → chunk-D7BXVKSF.js} +1 -1
  28. package/chunks/{chunk-TXO5BMR2.js → chunk-DH5YXSIF.js} +2 -2
  29. package/chunks/{chunk-OSVH4SMN.js → chunk-FBMCDU63.js} +3 -3
  30. package/chunks/{chunk-GY24H6IA.js → chunk-FCLHHEUK.js} +10 -10
  31. package/chunks/{chunk-FWWQIFDT.js → chunk-G2TX5ZXC.js} +3 -3
  32. package/chunks/{chunk-HDYQYYWB.js → chunk-GAKGOXTC.js} +1 -1
  33. package/chunks/{chunk-TWFFY5BP.js → chunk-HADWBW5R.js} +4 -4
  34. package/chunks/{chunk-E2N554HK.js → chunk-HZGBKOX3.js} +2 -2
  35. package/chunks/{chunk-V47QNK5W.js → chunk-II6G3EY6.js} +288 -72
  36. package/chunks/{chunk-ZV7LTLFE.js → chunk-IOEZE2YT.js} +1 -1
  37. package/chunks/chunk-JUWS2Z5K.js +1995 -0
  38. package/chunks/{chunk-F3II4BTZ.js → chunk-K4ADGWHU.js} +1 -1
  39. package/chunks/{chunk-5ZTS3OQ3.js → chunk-KSAFZ5TA.js} +1 -1
  40. package/chunks/{chunk-KMS57JDD.js → chunk-KTKYGS2P.js} +29 -6
  41. package/chunks/{chunk-HWXGX534.js → chunk-KTQGGPGV.js} +3 -3
  42. package/chunks/{chunk-ZIKTCMQF.js → chunk-LZZLUCRS.js} +5 -5
  43. package/chunks/{chunk-S5CULOHB.js → chunk-MHP476D3.js} +64 -21
  44. package/chunks/{chunk-PNVPFARW.js → chunk-MTCYGTWH.js} +4 -4
  45. package/chunks/{chunk-WQYWK4DG.js → chunk-OGDIJKHK.js} +1 -1
  46. package/chunks/{chunk-WH6QMLUW.js → chunk-OGNFHGIG.js} +3 -3
  47. package/chunks/{chunk-P5ULXPK5.js → chunk-P2FK2HBV.js} +2 -2
  48. package/chunks/{chunk-5WZL724W.js → chunk-P3RBMQ4P.js} +3 -3
  49. package/chunks/{chunk-4EOURKA4.js → chunk-P4ZEZSJZ.js} +177 -17
  50. package/chunks/{chunk-RQ6U2JJQ.js → chunk-PNBBJOCP.js} +1 -1
  51. package/chunks/{chunk-E2T7FLDU.js → chunk-PVOGHGSF.js} +5 -5
  52. package/chunks/{chunk-EUVOKP6Y.js → chunk-QSNSL4R4.js} +1 -1
  53. package/chunks/{chunk-RYQMJCUO.js → chunk-RBHQXGDK.js} +1 -1
  54. package/chunks/{chunk-ZI5IH2HP.js → chunk-RVSTTOJ4.js} +2 -2
  55. package/chunks/{chunk-OW2BWT2P.js → chunk-SCAZZ3Q4.js} +4 -4
  56. package/chunks/{chunk-OBP6QWD5.js → chunk-T5RLUXWJ.js} +2 -2
  57. package/chunks/{chunk-KP25NJNM.js → chunk-T6HEQR2Q.js} +16 -5
  58. package/chunks/{chunk-RMPLEWF3.js → chunk-THIKWITR.js} +2 -2
  59. package/chunks/{chunk-V2226RFW.js → chunk-TQCYNLNJ.js} +1 -1
  60. package/chunks/{chunk-O277O7U6.js → chunk-TZ6KJ44L.js} +1 -1
  61. package/chunks/{chunk-ZCJBCKL5.js → chunk-UJUM2SRN.js} +115 -29
  62. package/chunks/{chunk-3KJQZEN3.js → chunk-UYAUA63Q.js} +1 -1
  63. package/chunks/chunk-VFMASYQA.js +389 -0
  64. package/chunks/chunk-VGHZT6JR.js +51 -0
  65. package/chunks/{chunk-H4JC7LZX.js → chunk-W3FSZSF2.js} +1 -1
  66. package/chunks/{chunk-YFRFZCIP.js → chunk-WGK4TSB7.js} +3 -3
  67. package/chunks/{chunk-BL65MO72.js → chunk-WP5VOXF7.js} +6 -127
  68. package/chunks/{chunk-T2O6NIOY.js → chunk-XTY5DN4Y.js} +1 -1
  69. package/chunks/{chunk-47ZUMGGY.js → chunk-XX7QFP34.js} +56 -55
  70. package/chunks/{chunk-ZSNBQXMZ.js → chunk-YTFDX4PR.js} +8 -3
  71. package/chunks/{chunk-F6TUUA2U.js → chunk-ZBXGWQ4S.js} +2 -2
  72. package/chunks/{chunk-YR7ZQ4RD.js → chunk-ZOSTTOUJ.js} +1 -1
  73. package/chunks/{chunk-UAB6J2IE.js → chunk-ZTQSOV56.js} +3 -3
  74. package/chunks/{computer-use-SLN7DV2E.js → computer-use-PMZ7ICGY.js} +3 -3
  75. package/chunks/{contextCommand-EHFYX6FW.js → contextCommand-GEZU7YHE.js} +6 -5
  76. package/chunks/{core-runtime-FBSP5IIG.js → core-runtime-HRJI2MN6.js} +3 -3
  77. package/chunks/{create-sub-session-WC7YGVSL.js → create-sub-session-VBNVI4YU.js} +3 -3
  78. package/chunks/{daemon-VSX3FHTY.js → daemon-POSQPD3G.js} +26 -3
  79. package/chunks/{daemon-status-provider-WW2AD2T7.js → daemon-status-provider-N4CRQKFI.js} +8 -8
  80. package/chunks/{daemon-trust-policy-E4MAYWPI.js → daemon-trust-policy-BHO3JUHM.js} +11 -9
  81. package/chunks/{daemon-trust-policy-monitor-XVIDV6T4.js → daemon-trust-policy-monitor-YEKJ2726.js} +11 -9
  82. package/chunks/{deferred-core-runtime-5SVUC6UC.js → deferred-core-runtime-SH57E3J3.js} +3 -3
  83. package/chunks/{earlyInputCapture-72FYHYRD.js → earlyInputCapture-B2JJ2HME.js} +3 -3
  84. package/chunks/{edit-SWVVWHXW.js → edit-7FTXENAN.js} +5 -3
  85. package/chunks/{enter-worktree-2HF6WQEO.js → enter-worktree-JPHV2PBG.js} +3 -3
  86. package/chunks/{enterPlanMode-OW6S7L4P.js → enterPlanMode-CGBJ3AHJ.js} +3 -3
  87. package/chunks/{environment-LRTBTDXH.js → environment-LXASZAHD.js} +6 -6
  88. package/chunks/{errors-4CO2DME6.js → errors-XIGVT2AD.js} +5 -5
  89. package/chunks/{exit-worktree-GHJEIRGL.js → exit-worktree-DKSGXW65.js} +3 -3
  90. package/chunks/{exitPlanMode-JVP4FNNK.js → exitPlanMode-THFL2HYN.js} +3 -3
  91. package/chunks/{fast-path-HCCY7GR2.js → fast-path-4NXAT5UL.js} +3 -3
  92. package/chunks/{fast-path-settings-MN5QQQET.js → fast-path-settings-RPAVBD7P.js} +2 -2
  93. package/chunks/{gemini-V3YVRKXU.js → gemini-B3N6FACU.js} +39 -44
  94. package/chunks/{geminiContentGenerator-LVPMQUWX.js → geminiContentGenerator-YYFE2HIE.js} +1 -1
  95. package/chunks/{glob-7HRXHYDR.js → glob-BPHSCFJP.js} +3 -3
  96. package/chunks/{grep-BITQUON5.js → grep-ROZIRFLU.js} +3 -3
  97. package/chunks/{handleAutoUpdate-DKFY454S.js → handleAutoUpdate-WV6SPZQB.js} +8 -7
  98. package/chunks/{i18n-53BQIQSH.js → i18n-YWJWPQKD.js} +8 -6
  99. package/chunks/{image-gen-H62FLDFB.js → image-gen-SISRZ6FS.js} +1 -1
  100. package/chunks/{initializer-Q7NUQRSU.js → initializer-66OAD6GO.js} +11 -9
  101. package/chunks/{installationInfo-BWFHT7WU.js → installationInfo-3YUGIP36.js} +4 -4
  102. package/chunks/{list-OWQKR6JK.js → list-VEYR66XB.js} +14 -12
  103. package/chunks/{loadedSettingsAdapter-HNPKQMFA.js → loadedSettingsAdapter-V2JCPCYD.js} +11 -9
  104. package/chunks/{loggingContentGenerator-A5I3VQUC.js → loggingContentGenerator-RBLNDREC.js} +1 -1
  105. package/chunks/{managed-npm-update-CUUJGUTV.js → managed-npm-update-C5ID5R4R.js} +4 -4
  106. package/chunks/{mcp-GJSC7ZPO.js → mcp-OZ54NZJQ.js} +11 -9
  107. package/chunks/{monitor-TZ2II7JM.js → monitor-7Y4TVFTK.js} +3 -3
  108. package/chunks/{nonInteractiveCli-22RS4EVH.js → nonInteractiveCli-QEK4LHAC.js} +35 -33
  109. package/chunks/{notebook-edit-YZC3YPY2.js → notebook-edit-OG35EBGY.js} +4 -3
  110. package/chunks/{openaiContentGenerator-OIGO5XNF.js → openaiContentGenerator-443BNRPJ.js} +1 -1
  111. package/chunks/{pidfile-QJQ65RJ2.js → pidfile-ZK4OLRZA.js} +3 -3
  112. package/chunks/{processUtils-V5VSDIKS.js → processUtils-4YGB4RUZ.js} +2 -2
  113. package/chunks/{qwenContentGenerator-HXM25BGB.js → qwenContentGenerator-D5C2LCSZ.js} +3 -3
  114. package/chunks/{qwenOAuth2-7MTMS2Z5.js → qwenOAuth2-Z4YQBMYN.js} +1 -1
  115. package/chunks/{read-file-PMGXB3ZB.js → read-file-EXTJLWMU.js} +1 -1
  116. package/chunks/{resumeHistoryUtils-YUTPLHUH.js → resumeHistoryUtils-UPCGRJUL.js} +7 -6
  117. package/chunks/{ripGrep-XUS66YIV.js → ripGrep-QBVIRCU4.js} +3 -3
  118. package/chunks/{run-qwen-serve-4NVSU75L.js → run-qwen-serve-ZYGJNE3E.js} +67 -51
  119. package/chunks/{runtime-QLRVP6HM.js → runtime-BZZ4LWCP.js} +12 -10
  120. package/chunks/{scheduler-PBB2NSOP.js → scheduler-YNQNOU2E.js} +131 -11
  121. package/chunks/{serve-BWKTRX72.js → serve-LJHAXDCH.js} +11 -9
  122. package/chunks/{server-E7CH7WPK.js → server-ADMLELR6.js} +256 -750
  123. package/chunks/{session-QEKSJ6YU.js → session-YKZXFFTM.js} +36 -34
  124. package/chunks/{settings-BRAOSJIM.js → settings-EQBUAQ7Y.js} +10 -8
  125. package/chunks/{shell-OF3CK4AT.js → shell-3QZOJGTT.js} +3 -3
  126. package/chunks/{skill-HLH2NO2H.js → skill-UWSSMXE7.js} +1 -1
  127. package/chunks/{skill-settings-DRPU7YI5.js → skill-settings-T6MLB7NU.js} +10 -8
  128. package/chunks/{spawnChannel-4KO7YTFM.js → spawnChannel-VS7ZFUFP.js} +3 -3
  129. package/chunks/{standalone-update-DJN2R3YW.js → standalone-update-2W26SRRO.js} +6 -5
  130. package/chunks/{startInteractiveUI-O3WQQ2WC.js → startInteractiveUI-CVS7K3D6.js} +55 -45
  131. package/chunks/{team-create-2E4ACBJD.js → team-create-4WFTNNUL.js} +3 -3
  132. package/chunks/{team-plan-approval-LWIDXYOA.js → team-plan-approval-DBYI33S3.js} +3 -3
  133. package/chunks/{terminal-image-renderer-PJM7663W.js → terminal-image-renderer-S5WPPQKH.js} +3 -3
  134. package/chunks/{theme-manager-FDQTM3RP.js → theme-manager-LI2RIOVR.js} +3 -3
  135. package/chunks/{tool-search-TL5ZXBF4.js → tool-search-4773EUQ4.js} +1 -1
  136. package/chunks/{total-session-admission-LS6EY5KT.js → total-session-admission-PAY5CH2Z.js} +4 -4
  137. package/chunks/{trustedFolders-5RWP5OB7.js → trustedFolders-FRSLE674.js} +4 -4
  138. package/chunks/{update-relaunch-HWQ4USKY.js → update-relaunch-ZSFQTU6M.js} +5 -5
  139. package/chunks/{updateCheck-EZMBTEIR.js → updateCheck-AXWSO7KA.js} +7 -6
  140. package/chunks/{useAutoAcceptIndicator-JDMI627A.js → useAutoAcceptIndicator-VHLXIA7U.js} +11 -9
  141. package/chunks/{validateNonInterActiveAuth-RRUHC5RO.js → validateNonInterActiveAuth-PDJECMFU.js} +32 -30
  142. package/chunks/{version-XS4UTKUX.js → version-RBN764QS.js} +1 -1
  143. package/chunks/{web-fetch-2JV7H6OM.js → web-fetch-7BJK42AF.js} +1 -1
  144. package/chunks/{web-search-RCTN2GAM.js → web-search-L2CILQXV.js} +2 -2
  145. package/chunks/{workflow-6MKLKQ6R.js → workflow-5VH2R74I.js} +4 -4
  146. package/chunks/{workspace-providers-status-YZ2IJ4DK.js → workspace-providers-status-OZTQ6JFH.js} +13 -11
  147. package/chunks/{workspace-registration-store-IYN72LBS.js → workspace-registration-store-IX5RJQS5.js} +1 -1
  148. package/chunks/{workspace-registry-7LFBZQLT.js → workspace-registry-73N4BGG4.js} +4 -4
  149. package/chunks/{workspace-service-2EHSPRJB.js → workspace-service-I5RUPSNV.js} +14 -12
  150. package/chunks/{workspace-skills-status-5VJ2D5HN.js → workspace-skills-status-DMK6VYDO.js} +11 -9
  151. package/chunks/{workspace-trust-reconciler-X2LZ6XCI.js → workspace-trust-reconciler-QX4RL3TC.js} +12 -10
  152. package/chunks/{write-file-CJK6SCCF.js → write-file-UGDD5UTS.js} +3 -3
  153. package/chunks/{zoom-image-BVW4RFYW.js → zoom-image-ZAHEO3YP.js} +1 -1
  154. package/cli.js +12 -12
  155. package/package.json +3 -3
  156. package/web-shell/assets/{arc-DDtoJrAW.js → arc-CHY4saMJ.js} +1 -1
  157. package/web-shell/assets/{architectureDiagram-3BPJPVTR-BAInIW4O.js → architectureDiagram-3BPJPVTR-Bu6CwvHj.js} +1 -1
  158. package/web-shell/assets/{blockDiagram-GPEHLZMM-ChPDk7fP.js → blockDiagram-GPEHLZMM-XGt6iGf_.js} +1 -1
  159. package/web-shell/assets/{c4Diagram-AAUBKEIU-Cd9BJuUy.js → c4Diagram-AAUBKEIU-CBbYl19W.js} +1 -1
  160. package/web-shell/assets/channel-B40srHOa.js +1 -0
  161. package/web-shell/assets/{chunk-2J33WTMH-COQkLp56.js → chunk-2J33WTMH-BEhmVrdx.js} +1 -1
  162. package/web-shell/assets/{chunk-4BX2VUAB-GUJshQ_l.js → chunk-4BX2VUAB-fQLyE0Bg.js} +1 -1
  163. package/web-shell/assets/{chunk-55IACEB6-Boaa7c10.js → chunk-55IACEB6-yGdtyx4a.js} +1 -1
  164. package/web-shell/assets/{chunk-727SXJPM-CcRXaly2.js → chunk-727SXJPM-DYbX2GLo.js} +1 -1
  165. package/web-shell/assets/{chunk-AQP2D5EJ-BY0OARHh.js → chunk-AQP2D5EJ-DyKTEsYn.js} +1 -1
  166. package/web-shell/assets/{chunk-FMBD7UC4-DLFQfv0S.js → chunk-FMBD7UC4-D8Uy_GzX.js} +1 -1
  167. package/web-shell/assets/{chunk-ND2GUHAM-C_S0u-D2.js → chunk-ND2GUHAM-C8wNR2K7.js} +1 -1
  168. package/web-shell/assets/{chunk-QZHKN3VN-DP9m64hw.js → chunk-QZHKN3VN-BnybNxnt.js} +1 -1
  169. package/web-shell/assets/classDiagram-4FO5ZUOK-qumcXQW_.js +1 -0
  170. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-qumcXQW_.js +1 -0
  171. package/web-shell/assets/{cose-bilkent-S5V4N54A-CGY6zGE1.js → cose-bilkent-S5V4N54A-jq4uiFRp.js} +1 -1
  172. package/web-shell/assets/{dagre-BM42HDAG-yB7whKNn.js → dagre-BM42HDAG-Bs7oye1U.js} +1 -1
  173. package/web-shell/assets/{diagram-2AECGRRQ-Bdlc59La.js → diagram-2AECGRRQ-BHGGJNyM.js} +1 -1
  174. package/web-shell/assets/{diagram-5GNKFQAL-BUClP18L.js → diagram-5GNKFQAL-BJezVLGT.js} +1 -1
  175. package/web-shell/assets/{diagram-KO2AKTUF-aZm08kjn.js → diagram-KO2AKTUF-5JzQN_rL.js} +1 -1
  176. package/web-shell/assets/{diagram-LMA3HP47-7DGwEkxC.js → diagram-LMA3HP47-BlPYOgY9.js} +1 -1
  177. package/web-shell/assets/{diagram-OG6HWLK6-CAGKayxx.js → diagram-OG6HWLK6-CtMHEaFK.js} +1 -1
  178. package/web-shell/assets/{erDiagram-TEJ5UH35-CptoHHQi.js → erDiagram-TEJ5UH35-CRNdq2AB.js} +1 -1
  179. package/web-shell/assets/{flowDiagram-I6XJVG4X-CNOH0s7Q.js → flowDiagram-I6XJVG4X-De1WwLzu.js} +1 -1
  180. package/web-shell/assets/{ganttDiagram-6RSMTGT7-CCQuCU3y.js → ganttDiagram-6RSMTGT7-YbWfL5Zn.js} +1 -1
  181. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-B7gv9f4E.js → gitGraphDiagram-PVQCEYII-DzCN8bmd.js} +1 -1
  182. package/web-shell/assets/index-BDOGGGaN.css +5 -0
  183. package/web-shell/assets/{index-BoUPVvpf.js → index-CocPvF9Q.js} +1 -1
  184. package/web-shell/assets/index-DSH2KrMc.js +1771 -0
  185. package/web-shell/assets/{infoDiagram-5YYISTIA-Bb3KYEbR.js → infoDiagram-5YYISTIA-DLHoopnE.js} +1 -1
  186. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-DWEzbAGi.js → ishikawaDiagram-YF4QCWOH-XnbU04SS.js} +1 -1
  187. package/web-shell/assets/{journeyDiagram-JHISSGLW-CmxwEqeb.js → journeyDiagram-JHISSGLW-CipPyEeJ.js} +1 -1
  188. package/web-shell/assets/{kanban-definition-UN3LZRKU-Ci0gDD8O.js → kanban-definition-UN3LZRKU-DrSeyE5d.js} +1 -1
  189. package/web-shell/assets/{linear-BqxZqGhS.js → linear-LrBKnAo_.js} +1 -1
  190. package/web-shell/assets/{mermaid.core-BDAFffHv.js → mermaid.core-C3U9UVmf.js} +5 -5
  191. package/web-shell/assets/{mindmap-definition-RKZ34NQL-Btvx-xvS.js → mindmap-definition-RKZ34NQL-DqRWgC9H.js} +1 -1
  192. package/web-shell/assets/{pieDiagram-4H26LBE5-CKAg7yG7.js → pieDiagram-4H26LBE5-BNXY5p6H.js} +1 -1
  193. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DIt8E1mC.js → quadrantDiagram-W4KKPZXB-Ccj9QzE4.js} +1 -1
  194. package/web-shell/assets/{requirementDiagram-4Y6WPE33-BA7mQWQJ.js → requirementDiagram-4Y6WPE33-CjPM2_gx.js} +1 -1
  195. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-D0JppnVU.js → sankeyDiagram-5OEKKPKP-C0RsvKbj.js} +1 -1
  196. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-29DIQFjB.js → sequenceDiagram-3UESZ5HK-ClN1P5z7.js} +1 -1
  197. package/web-shell/assets/{stateDiagram-AJRCARHV-iiXMdK--.js → stateDiagram-AJRCARHV-By0eiB2Y.js} +1 -1
  198. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-Ds0WlK3F.js +1 -0
  199. package/web-shell/assets/{timeline-definition-PNZ67QCA-CeF7ngSW.js → timeline-definition-PNZ67QCA-g_iaSQgv.js} +1 -1
  200. package/web-shell/assets/{vennDiagram-CIIHVFJN-Beilq8D6.js → vennDiagram-CIIHVFJN-y9ZqJ-TD.js} +1 -1
  201. package/web-shell/assets/{wardley-L42UT6IY-DOYjY4zO.js → wardley-L42UT6IY-BVVfaxpF.js} +1 -1
  202. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-Dtqp8o18.js → wardleyDiagram-YWT4CUSO-D3ooZKZT.js} +1 -1
  203. package/web-shell/assets/{xychartDiagram-2RQKCTM6-cdAc0Dfv.js → xychartDiagram-2RQKCTM6-6GXrY6M1.js} +1 -1
  204. package/web-shell/index.html +2 -2
  205. package/chunks/chunk-R4ZA6GBK.js +0 -208
  206. package/web-shell/assets/channel-0OQklTfP.js +0 -1
  207. package/web-shell/assets/classDiagram-4FO5ZUOK-CZ4-apsu.js +0 -1
  208. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CZ4-apsu.js +0 -1
  209. package/web-shell/assets/index-D1YQXYsB.css +0 -5
  210. package/web-shell/assets/index-J4N7zCmU.js +0 -1768
  211. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CEGK3l80.js +0 -1
@@ -26,7 +26,7 @@ import {
26
26
  shouldSuppressRememberErrorDetails,
27
27
  workspaceMemoryFailureCode,
28
28
  workspaceMemoryFailureDiagnostics
29
- } from "./chunk-OSVH4SMN.js";
29
+ } from "./chunk-FBMCDU63.js";
30
30
  import {
31
31
  SetupGithubError,
32
32
  collectSessionData,
@@ -38,12 +38,12 @@ import {
38
38
  toJson,
39
39
  toJsonl,
40
40
  toMarkdown
41
- } from "./chunk-5WZL724W.js";
41
+ } from "./chunk-P3RBMQ4P.js";
42
42
  import {
43
43
  OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
44
44
  ObservedChannelContactStore
45
45
  } from "./chunk-OWMAZHIX.js";
46
- import "./chunk-3KJQZEN3.js";
46
+ import "./chunk-UYAUA63Q.js";
47
47
  import {
48
48
  escapeAnsiCtrlCodes
49
49
  } from "./chunk-4NFY2S7N.js";
@@ -107,7 +107,8 @@ import {
107
107
  setRateLimiter,
108
108
  unsafeRevealSecret,
109
109
  validateMcpRuntimeServerName
110
- } from "./chunk-KMS57JDD.js";
110
+ } from "./chunk-KTKYGS2P.js";
111
+ import "./chunk-VGHZT6JR.js";
111
112
  import {
112
113
  isLoopbackBind,
113
114
  normalizeSessionIdForLookup,
@@ -127,14 +128,14 @@ import {
127
128
  validateWorkspaceSkillName,
128
129
  validateWorkspaceVoiceState,
129
130
  voiceSettingsScopeToWire
130
- } from "./chunk-7XX5IBXL.js";
131
+ } from "./chunk-46YJDYCU.js";
131
132
  import {
132
133
  PermissionRulesValidationError,
133
134
  buildPermissionSettings,
134
135
  isPermissionRuleType,
135
136
  normalizePermissionRules,
136
137
  readPermissionRuleSet
137
- } from "./chunk-NZMXUSKS.js";
138
+ } from "./chunk-BAMN6XSD.js";
138
139
  import {
139
140
  assertVoiceBaseUrlNetworkAllowed,
140
141
  isStreamingVoiceModel,
@@ -142,12 +143,12 @@ import {
142
143
  resolveVoiceTranscriptionConfig,
143
144
  sanitizeVoiceErrorMessage,
144
145
  transcribeVoiceAudio
145
- } from "./chunk-RYQMJCUO.js";
146
+ } from "./chunk-RBHQXGDK.js";
146
147
  import {
147
148
  isVoiceEnabled,
148
149
  isVoiceMode,
149
150
  readVoiceModel
150
- } from "./chunk-HDYQYYWB.js";
151
+ } from "./chunk-GAKGOXTC.js";
151
152
  import "./chunk-AOHJKPKL.js";
152
153
  import {
153
154
  createTotalSessionAdmissionController
@@ -165,26 +166,26 @@ import {
165
166
  } from "./chunk-4JRM2BSM.js";
166
167
  import {
167
168
  assertValidChannelSecretUpdates
168
- } from "./chunk-EUVOKP6Y.js";
169
+ } from "./chunk-QSNSL4R4.js";
169
170
  import {
170
171
  createDaemonStatusProvider
171
- } from "./chunk-UAB6J2IE.js";
172
+ } from "./chunk-ZTQSOV56.js";
172
173
  import "./chunk-NTTBXH7U.js";
173
- import "./chunk-2ASQDZSJ.js";
174
+ import "./chunk-7S4JBJLU.js";
174
175
  import "./chunk-3SH53ANB.js";
175
176
  import {
176
177
  createWorkspaceProvidersStatusProvider
177
- } from "./chunk-VHXPSL57.js";
178
+ } from "./chunk-3WDYBTTI.js";
178
179
  import {
179
180
  getAuthTypeFromEnv,
180
181
  resolveCliGenerationConfig
181
- } from "./chunk-HWXGX534.js";
182
+ } from "./chunk-KTQGGPGV.js";
182
183
  import {
183
184
  snapshotProcessEnv
184
- } from "./chunk-OR6R3IUW.js";
185
+ } from "./chunk-23VQTELM.js";
185
186
  import {
186
187
  createWorkspaceSkillsStatusProvider
187
- } from "./chunk-F6TUUA2U.js";
188
+ } from "./chunk-ZBXGWQ4S.js";
188
189
  import "./chunk-BGXZBI5B.js";
189
190
  import "./chunk-Z4X5MTRT.js";
190
191
  import {
@@ -203,12 +204,12 @@ import {
203
204
  import {
204
205
  evaluateDaemonWorkspaceTrust,
205
206
  readDaemonTrustPolicySnapshot
206
- } from "./chunk-FWWQIFDT.js";
207
+ } from "./chunk-G2TX5ZXC.js";
207
208
  import {
208
209
  daemonObservedContactsPath,
209
210
  loadChannelsConfig
210
- } from "./chunk-EISUQQPS.js";
211
- import "./chunk-TWFFY5BP.js";
211
+ } from "./chunk-ATMO54WE.js";
212
+ import "./chunk-HADWBW5R.js";
212
213
  import "./chunk-57OAHC2Y.js";
213
214
  import {
214
215
  parseChannelWebhookConfigLenient
@@ -227,7 +228,7 @@ import {
227
228
  SessionArtifactValidationError,
228
229
  createAcpSessionBridge,
229
230
  parseSessionSource
230
- } from "./chunk-4EOURKA4.js";
231
+ } from "./chunk-P4ZEZSJZ.js";
231
232
  import {
232
233
  EVENT_SCHEMA_VERSION,
233
234
  EventBus,
@@ -253,7 +254,7 @@ import {
253
254
  WorkspaceRegistrationStoreLimitError,
254
255
  normalizeWorkspaceDisplayName,
255
256
  workspaceRegistrationId
256
- } from "./chunk-H4JC7LZX.js";
257
+ } from "./chunk-W3FSZSF2.js";
257
258
  import {
258
259
  REQUESTED_SESSION_ID_META_KEY,
259
260
  gradeActiveWorkCoverage
@@ -333,23 +334,26 @@ import {
333
334
  getWritableScopes,
334
335
  loadSettings,
335
336
  validateSettingValue
336
- } from "./chunk-HKI3KHAO.js";
337
+ } from "./chunk-JUWS2Z5K.js";
338
+ import "./chunk-7GOYZQPR.js";
337
339
  import "./chunk-RKUWKYED.js";
338
340
  import "./chunk-GOXKNSDZ.js";
339
341
  import "./chunk-IDS7MSUP.js";
340
342
  import {
341
- SUPPORTED_LANGUAGES,
342
343
  detectSystemLanguage,
343
- resolveLanguageSetting,
344
+ resolveLanguageSetting
345
+ } from "./chunk-WP5VOXF7.js";
346
+ import {
347
+ SUPPORTED_LANGUAGES,
344
348
  resolveSupportedLanguage
345
- } from "./chunk-BL65MO72.js";
346
- import "./chunk-KP25NJNM.js";
347
- import "./chunk-R4ZA6GBK.js";
348
- import "./chunk-ZV7LTLFE.js";
349
+ } from "./chunk-5EJZE3FP.js";
350
+ import "./chunk-T6HEQR2Q.js";
351
+ import "./chunk-VFMASYQA.js";
352
+ import "./chunk-IOEZE2YT.js";
349
353
  import "./chunk-VJNBRRZG.js";
350
354
  import {
351
355
  getWorkspaceTrustStatus
352
- } from "./chunk-YR7ZQ4RD.js";
356
+ } from "./chunk-ZOSTTOUJ.js";
353
357
  import "./chunk-NPQ5ZKRP.js";
354
358
  import {
355
359
  isWithinRoot as isWithinRoot2
@@ -429,7 +433,7 @@ import {
429
433
  writeWorkspaceContextFile,
430
434
  writeWorktreeSession,
431
435
  writeWorktreeSessionMarker
432
- } from "./chunk-47ZUMGGY.js";
436
+ } from "./chunk-XX7QFP34.js";
433
437
  import "./chunk-GOFAQQZA.js";
434
438
  import "./chunk-5M6IDOMF.js";
435
439
  import "./chunk-TWPJO254.js";
@@ -442,7 +446,7 @@ import "./chunk-MVUQRLOH.js";
442
446
  import "./chunk-XCWO3SMQ.js";
443
447
  import "./chunk-7MH4J33A.js";
444
448
  import "./chunk-6PVPNMXU.js";
445
- import "./chunk-F3II4BTZ.js";
449
+ import "./chunk-K4ADGWHU.js";
446
450
  import {
447
451
  nextFireTime,
448
452
  parseCron
@@ -536,7 +540,7 @@ import "./chunk-FVKHVJZQ.js";
536
540
  import "./chunk-COBO5EBO.js";
537
541
  import "./chunk-6ZRFAKXK.js";
538
542
  import "./chunk-PYQADEFD.js";
539
- import "./chunk-E2T7FLDU.js";
543
+ import "./chunk-PVOGHGSF.js";
540
544
  import "./chunk-F6WFNA7U.js";
541
545
  import "./chunk-46UV252V.js";
542
546
  import "./chunk-ZBVS26BY.js";
@@ -1233,26 +1237,165 @@ function createWorkspaceFileSystemFactory(deps) {
1233
1237
  });
1234
1238
  const lowFs = new StandardFileSystemService();
1235
1239
  const pathLocks = deps.pathLocks ?? new PathMutexRegistry();
1240
+ const forRequest = /* @__PURE__ */ __name((ctx) => new WorkspaceFileSystemImpl({
1241
+ primaryWorkspace,
1242
+ workspaces,
1243
+ trusted: deps.trusted,
1244
+ audit,
1245
+ ctx,
1246
+ lowFs,
1247
+ pathLocks,
1248
+ generationGuard: deps.generationGuard
1249
+ }), "forRequest");
1236
1250
  return {
1237
1251
  assertCanWrite() {
1238
1252
  deps.generationGuard?.assertOpen();
1239
1253
  assertTrustedForIntent(deps.trusted, "write");
1240
1254
  },
1241
- forRequest(ctx) {
1242
- return new WorkspaceFileSystemImpl({
1243
- primaryWorkspace,
1244
- workspaces,
1245
- trusted: deps.trusted,
1246
- audit,
1247
- ctx,
1248
- lowFs,
1249
- pathLocks,
1250
- generationGuard: deps.generationGuard
1251
- });
1255
+ forRequest,
1256
+ async writeSameHostToolText(ctx, request2) {
1257
+ try {
1258
+ deps.generationGuard?.assertOpen();
1259
+ } catch (err) {
1260
+ throw recordSameHostToolWriteDenied(audit, ctx, request2.path, err);
1261
+ }
1262
+ let resolved;
1263
+ try {
1264
+ resolved = await resolveWithinWorkspace(
1265
+ request2.path,
1266
+ workspaces.map((workspace) => workspace.path),
1267
+ "write"
1268
+ );
1269
+ deps.generationGuard?.assertOpen();
1270
+ } catch (err) {
1271
+ if (!(err instanceof FsError && err.kind === "path_outside_workspace")) {
1272
+ throw recordSameHostToolWriteDenied(audit, ctx, request2.path, err);
1273
+ }
1274
+ try {
1275
+ await writeSameHostToolTextOutsideWorkspace({
1276
+ request: request2,
1277
+ trusted: deps.trusted,
1278
+ audit,
1279
+ ctx,
1280
+ pathLocks,
1281
+ generationGuard: deps.generationGuard
1282
+ });
1283
+ return;
1284
+ } catch (outsideErr) {
1285
+ throw recordSameHostToolWriteDenied(
1286
+ audit,
1287
+ ctx,
1288
+ request2.path,
1289
+ outsideErr
1290
+ );
1291
+ }
1292
+ }
1293
+ try {
1294
+ await forRequest(ctx).writeTextOverwrite(resolved, request2.content);
1295
+ } catch (err) {
1296
+ if (isWorkspaceGenerationClosedError(err)) {
1297
+ recordSameHostToolWriteDenied(audit, ctx, request2.path, err);
1298
+ }
1299
+ throw err;
1300
+ }
1252
1301
  }
1253
1302
  };
1254
1303
  }
1255
1304
  __name(createWorkspaceFileSystemFactory, "createWorkspaceFileSystemFactory");
1305
+ async function writeSameHostToolTextOutsideWorkspace(deps) {
1306
+ const start = performance.now();
1307
+ deps.generationGuard?.assertOpen();
1308
+ assertTrustedForIntent(deps.trusted, "write");
1309
+ enforceWriteSize(Buffer.byteLength(deps.request.content, "utf-8"));
1310
+ const target = await resolveSameHostToolWriteTarget(deps.request.path);
1311
+ await deps.pathLocks.runExclusive(target, async () => {
1312
+ deps.generationGuard?.assertOpen();
1313
+ const meta = mergeWriteMeta(void 0, deps.request.meta ?? {});
1314
+ const content = meta.bom && deps.request.content.charCodeAt(0) === 65279 ? deps.request.content.slice(1) : deps.request.content;
1315
+ const result = await atomicWriteTextResolvedFile({
1316
+ target,
1317
+ content,
1318
+ mode: "overwrite",
1319
+ meta,
1320
+ assertGenerationOpen: /* @__PURE__ */ __name(() => deps.generationGuard?.assertOpen(), "assertGenerationOpen")
1321
+ });
1322
+ deps.audit.recordAccess(deps.ctx, {
1323
+ intent: "write",
1324
+ absolute: target,
1325
+ durationMs: performance.now() - start,
1326
+ sizeBytes: result.sizeBytes
1327
+ });
1328
+ });
1329
+ }
1330
+ __name(writeSameHostToolTextOutsideWorkspace, "writeSameHostToolTextOutsideWorkspace");
1331
+ async function resolveSameHostToolWriteTarget(input) {
1332
+ if (!path4.isAbsolute(input)) {
1333
+ throw new FsError(
1334
+ "path_outside_workspace",
1335
+ `same-host external tool write requires an absolute path: ${input}`
1336
+ );
1337
+ }
1338
+ if (hasSuspiciousPathPattern(input)) {
1339
+ throw new FsError(
1340
+ "path_outside_workspace",
1341
+ `path contains suspicious pattern: ${input}`
1342
+ );
1343
+ }
1344
+ let leaf;
1345
+ try {
1346
+ leaf = await fsp2.lstat(input);
1347
+ } catch (err) {
1348
+ if (err?.code !== "ENOENT") {
1349
+ throw err;
1350
+ }
1351
+ const parent = await fsp2.realpath(path4.dirname(input));
1352
+ const parentStat = await fsp2.lstat(parent);
1353
+ if (!parentStat.isDirectory()) {
1354
+ throw new FsError(
1355
+ "parse_error",
1356
+ `parent path is not a directory: ${parent}`
1357
+ );
1358
+ }
1359
+ return path4.join(parent, path4.basename(input));
1360
+ }
1361
+ if (leaf.isSymbolicLink()) {
1362
+ throw new FsError(
1363
+ "symlink_escape",
1364
+ `path is a symlink and cannot be overwritten: ${input}`,
1365
+ { hint: "resolve the target explicitly before writing" }
1366
+ );
1367
+ }
1368
+ if (!leaf.isFile()) {
1369
+ throw new FsError("parse_error", `path is not a regular file: ${input}`);
1370
+ }
1371
+ const canonical = await fsp2.realpath(input);
1372
+ const canonicalStat = await fsp2.lstat(canonical);
1373
+ if (!canonicalStat.isFile()) {
1374
+ throw new FsError(
1375
+ "parse_error",
1376
+ `canonical path is not a regular file: ${canonical}`
1377
+ );
1378
+ }
1379
+ assertSameFile(leaf, canonicalStat, input, "write");
1380
+ return canonical;
1381
+ }
1382
+ __name(resolveSameHostToolWriteTarget, "resolveSameHostToolWriteTarget");
1383
+ function isWorkspaceGenerationClosedError(error2) {
1384
+ return error2 instanceof Error && "code" in error2 && error2.code === "workspace_generation_closed";
1385
+ }
1386
+ __name(isWorkspaceGenerationClosedError, "isWorkspaceGenerationClosedError");
1387
+ function recordSameHostToolWriteDenied(audit, ctx, input, error2) {
1388
+ const fsError = wrapAsFsError(error2);
1389
+ audit.recordDenied(ctx, {
1390
+ intent: "write",
1391
+ input,
1392
+ errorKind: fsError.kind,
1393
+ hint: fsError.hint,
1394
+ message: fsError.message
1395
+ });
1396
+ return isWorkspaceGenerationClosedError(error2) && error2 instanceof Error ? error2 : fsError;
1397
+ }
1398
+ __name(recordSameHostToolWriteDenied, "recordSameHostToolWriteDenied");
1256
1399
  function assertNoNestedWorkspaces(workspaces) {
1257
1400
  for (let i = 0; i < workspaces.length; i++) {
1258
1401
  const a = workspaces[i];
@@ -16422,690 +16565,10 @@ function registerDaemonStatusRoutes(app, deps) {
16422
16565
  }
16423
16566
  __name(registerDaemonStatusRoutes, "registerDaemonStatusRoutes");
16424
16567
 
16425
- // packages/cli/src/serve/routes/health-demo.ts
16426
- init_esbuild_shims();
16427
-
16428
- // packages/cli/src/serve/demo.ts
16568
+ // packages/cli/src/serve/routes/health.ts
16429
16569
  init_esbuild_shims();
16430
- function getDemoHtml(_port) {
16431
- return (
16432
- /* html */
16433
- `<!DOCTYPE html>
16434
- <html lang="en">
16435
- <head>
16436
- <meta charset="utf-8" />
16437
- <meta name="viewport" content="width=device-width, initial-scale=1" />
16438
- <title>Qwen Serve Demo</title>
16439
- <style>
16440
- :root { --bg: #1a1a2e; --surface: #16213e; --border: #0f3460; --accent: #e94560; --text: #eee; --text2: #aab; --ok: #4ade80; --warn: #fbbf24; --err: #f87171; }
16441
- * { box-sizing: border-box; margin: 0; padding: 0; }
16442
- body { font-family: 'SF Mono', 'Menlo', 'Consolas', monospace; font-size: 13px; background: var(--bg); color: var(--text); min-height: 100vh; }
16443
- .header { background: var(--surface); border-bottom: 1px solid var(--border); padding: 12px 20px; display: flex; align-items: center; gap: 12px; }
16444
- .header h1 { font-size: 16px; font-weight: 600; }
16445
- .header .badge { font-size: 11px; background: var(--accent); color: #fff; padding: 2px 8px; border-radius: 10px; }
16446
- .header .status { margin-left: auto; display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text2); }
16447
- .header .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--err); }
16448
- .header .dot.ok { background: var(--ok); }
16449
- .container { display: grid; grid-template-columns: 340px 1fr; height: calc(100vh - 49px); }
16450
- .sidebar { background: var(--surface); border-right: 1px solid var(--border); overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 12px; }
16451
- .panel { background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 12px; }
16452
- .panel h3 { font-size: 12px; color: var(--accent); margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.5px; }
16453
- .panel label { display: block; font-size: 11px; color: var(--text2); margin-bottom: 3px; }
16454
- .panel input, .panel textarea { width: 100%; background: var(--surface); border: 1px solid var(--border); color: var(--text); padding: 6px 8px; border-radius: 4px; font-family: inherit; font-size: 12px; margin-bottom: 8px; }
16455
- .panel input:focus, .panel textarea:focus { outline: none; border-color: var(--accent); }
16456
- .panel textarea { resize: vertical; min-height: 60px; }
16457
- .btn { display: inline-flex; align-items: center; gap: 4px; padding: 6px 14px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface); color: var(--text); font-family: inherit; font-size: 12px; cursor: pointer; transition: all 0.15s; }
16458
- .btn:hover { border-color: var(--accent); color: var(--accent); }
16459
- .btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
16460
- .btn.primary:hover { opacity: 0.85; }
16461
- .btn:disabled { opacity: 0.4; cursor: not-allowed; }
16462
- .btn-row { display: flex; gap: 6px; flex-wrap: wrap; }
16463
- .main { display: flex; flex-direction: column; overflow: hidden; }
16464
- .tabs { display: flex; background: var(--surface); border-bottom: 1px solid var(--border); }
16465
- .tab { padding: 8px 16px; font-size: 12px; color: var(--text2); cursor: pointer; border-bottom: 2px solid transparent; }
16466
- .tab.active { color: var(--accent); border-bottom-color: var(--accent); }
16467
- .tab-content { flex: 1; overflow: hidden; display: none; flex-direction: column; }
16468
- .tab-content.active { display: flex; }
16469
- .log { flex: 1; overflow-y: auto; padding: 12px; font-size: 12px; line-height: 1.6; }
16470
- .log-entry { padding: 3px 0; border-bottom: 1px solid rgba(255,255,255,0.03); word-break: break-all; }
16471
- .log-entry .ts { color: var(--text2); margin-right: 8px; font-size: 11px; }
16472
- .log-entry .tag { display: inline-block; padding: 0 5px; border-radius: 3px; font-size: 10px; margin-right: 6px; }
16473
- .tag-info { background: #1e40af; color: #93c5fd; }
16474
- .tag-event { background: #065f46; color: #6ee7b7; }
16475
- .tag-error { background: #7f1d1d; color: #fca5a5; }
16476
- .tag-response { background: #713f12; color: #fde68a; }
16477
- .tag-thought { background: #4c1d95; color: #c4b5fd; }
16478
- .tag-message { background: #164e63; color: #67e8f9; }
16479
- .chat { flex: 1; overflow-y: auto; padding: 16px; }
16480
- .chat-msg { margin-bottom: 12px; max-width: 85%; }
16481
- .chat-msg.user { margin-left: auto; }
16482
- .chat-msg .bubble { padding: 8px 12px; border-radius: 8px; line-height: 1.5; white-space: pre-wrap; }
16483
- .chat-msg.user .bubble { background: var(--accent); color: #fff; border-bottom-right-radius: 2px; }
16484
- .chat-msg.assistant .bubble { background: var(--surface); border: 1px solid var(--border); border-bottom-left-radius: 2px; }
16485
- .chat-msg .meta { font-size: 10px; color: var(--text2); margin-top: 3px; }
16486
- .chat-input { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--border); background: var(--surface); }
16487
- .chat-input input { flex: 1; }
16488
- .session-info { font-size: 11px; color: var(--text2); padding: 4px 0; }
16489
- .session-info span { color: var(--ok); }
16490
- .empty-hint { color: var(--text2); text-align: center; padding: 40px 20px; font-size: 12px; }
16491
- .permission-card { background: var(--surface); border: 1px solid var(--warn); border-radius: 6px; padding: 10px 12px; margin: 8px 0; }
16492
- .permission-card h4 { color: var(--warn); font-size: 12px; margin-bottom: 6px; }
16493
- .permission-card .opt-btn { margin-right: 4px; margin-top: 4px; }
16494
- </style>
16495
- </head>
16496
- <body>
16497
-
16498
- <div class="header">
16499
- <h1>Qwen Serve</h1>
16500
- <span class="badge">Demo</span>
16501
- <div class="status">
16502
- <span class="dot" id="statusDot"></span>
16503
- <span id="statusText">Connecting...</span>
16504
- </div>
16505
- </div>
16506
-
16507
- <div class="container">
16508
- <div class="sidebar">
16509
- <div class="panel">
16510
- <h3>Session</h3>
16511
- <label>Working Directory (cwd)</label>
16512
- <input type="text" id="cwdInput" placeholder="/path/to/project" />
16513
- <div class="btn-row">
16514
- <button class="btn primary" id="btnCreateSession">Create / Attach</button>
16515
- <button class="btn" id="btnListSessions">List</button>
16516
- </div>
16517
- <div class="session-info" id="sessionInfo" style="display:none">
16518
- Session: <span id="sessionIdDisplay"></span>
16519
- </div>
16520
- <div class="session-info" id="contextUsage" style="display:none"></div>
16521
- </div>
16522
-
16523
- <div class="panel">
16524
- <h3>Prompt</h3>
16525
- <textarea id="promptInput" placeholder="Type your prompt here..."></textarea>
16526
- <div class="btn-row">
16527
- <button class="btn primary" id="btnSendPrompt" disabled>Send</button>
16528
- <button class="btn" id="btnCancel" disabled>Cancel</button>
16529
- </div>
16530
- </div>
16531
-
16532
- <div class="panel">
16533
- <h3>Model</h3>
16534
- <input type="text" id="modelInput" placeholder="Model ID (e.g. qwen3-coder)" />
16535
- <button class="btn" id="btnSetModel" disabled>Switch Model</button>
16536
- </div>
16537
-
16538
- <div class="panel">
16539
- <h3>Auth Token</h3>
16540
- <label>Bearer Token (if --token is set)</label>
16541
- <input type="password" id="tokenInput" placeholder="Optional bearer token" />
16542
- </div>
16543
-
16544
- <div class="panel">
16545
- <h3>Quick Actions</h3>
16546
- <div class="btn-row">
16547
- <button class="btn" id="btnHealth">Health</button>
16548
- <button class="btn" id="btnHealthDeep">Health (deep)</button>
16549
- <button class="btn" id="btnCaps">Capabilities</button>
16550
- </div>
16551
- </div>
16552
-
16553
- <div class="panel" id="permissionPanel" style="display:none">
16554
- <h3>Pending Permissions</h3>
16555
- <div id="permissionList"></div>
16556
- </div>
16557
- </div>
16558
-
16559
- <div class="main">
16560
- <div class="tabs">
16561
- <div class="tab active" data-tab="chat">Chat</div>
16562
- <div class="tab" data-tab="events">Events</div>
16563
- <div class="tab" data-tab="requests">API Log</div>
16564
- </div>
16565
-
16566
- <div class="tab-content active" id="tab-chat">
16567
- <div class="chat" id="chatArea">
16568
- <div class="empty-hint">Create a session to start chatting</div>
16569
- </div>
16570
- <div class="chat-input">
16571
- <input type="text" id="chatInput" placeholder="Send a message..." disabled />
16572
- <button class="btn primary" id="btnChatSend" disabled>Send</button>
16573
- </div>
16574
- </div>
16575
-
16576
- <div class="tab-content" id="tab-events">
16577
- <div class="log" id="eventLog"></div>
16578
- </div>
16579
-
16580
- <div class="tab-content" id="tab-requests">
16581
- <div class="log" id="requestLog"></div>
16582
- </div>
16583
- </div>
16584
- </div>
16585
-
16586
- <script>
16587
- (function() {
16588
- const BASE = '';
16589
- let sessionId = null;
16590
- let eventSource = null;
16591
- let currentAssistantBubble = null;
16592
- let currentThought = '';
16593
-
16594
- // --- DOM refs ---
16595
- const $ = (s) => document.querySelector(s);
16596
- const statusDot = $('#statusDot');
16597
- const statusText = $('#statusText');
16598
- const cwdInput = $('#cwdInput');
16599
- const promptInput = $('#promptInput');
16600
- const modelInput = $('#modelInput');
16601
- const tokenInput = $('#tokenInput');
16602
- const chatArea = $('#chatArea');
16603
- const chatInput = $('#chatInput');
16604
- const eventLog = $('#eventLog');
16605
- const requestLog = $('#requestLog');
16606
- const sessionInfo = $('#sessionInfo');
16607
- const sessionIdDisplay = $('#sessionIdDisplay');
16608
- const contextUsage = $('#contextUsage');
16609
- let lastLoggedContextPct = -1;
16610
- const permissionPanel = $('#permissionPanel');
16611
- const permissionList = $('#permissionList');
16612
-
16613
- // --- Tabs ---
16614
- document.querySelectorAll('.tab').forEach(tab => {
16615
- tab.addEventListener('click', () => {
16616
- document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
16617
- document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
16618
- tab.classList.add('active');
16619
- $('#tab-' + tab.dataset.tab).classList.add('active');
16620
- });
16621
- });
16622
-
16623
- // --- Logging ---
16624
- function ts() {
16625
- return new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
16626
- }
16627
- const MAX_LOG_ENTRIES = 500;
16628
- function addLog(container, tag, tagClass, msg) {
16629
- const el = document.createElement('div');
16630
- el.className = 'log-entry';
16631
- const text = typeof msg === 'object' ? JSON.stringify(msg, null, 2) : msg;
16632
- const tsSpan = document.createElement('span');
16633
- tsSpan.className = 'ts';
16634
- tsSpan.textContent = ts();
16635
- const tagSpan = document.createElement('span');
16636
- tagSpan.className = 'tag ' + tagClass;
16637
- tagSpan.textContent = tag;
16638
- el.appendChild(tsSpan);
16639
- el.appendChild(tagSpan);
16640
- el.appendChild(document.createTextNode(text));
16641
- container.appendChild(el);
16642
- while (container.children.length > MAX_LOG_ENTRIES) {
16643
- container.removeChild(container.firstChild);
16644
- }
16645
- container.scrollTop = container.scrollHeight;
16646
- }
16647
- function logEvent(tag, msg) { addLog(eventLog, tag, 'tag-event', msg); }
16648
- function logRequest(tag, msg) { addLog(requestLog, tag, 'tag-info', msg); }
16649
- function logResponse(tag, msg) { addLog(requestLog, tag, 'tag-response', msg); }
16650
- function logError(tag, msg) { addLog(requestLog, tag, 'tag-error', msg); }
16651
-
16652
- function escHtml(s) {
16653
- const d = document.createElement('div');
16654
- d.textContent = String(s);
16655
- return d.innerHTML;
16656
- }
16657
-
16658
- // --- 401 token hint ---
16659
- let tokenHintTimer = null;
16660
- function highlightTokenInput(msg) {
16661
- tokenInput.style.borderColor = 'var(--warn)';
16662
- tokenInput.focus();
16663
- // Show hint text below the input
16664
- let hint = document.getElementById('tokenHint');
16665
- if (!hint) {
16666
- hint = document.createElement('div');
16667
- hint.id = 'tokenHint';
16668
- hint.style.cssText = 'font-size:11px;color:var(--warn);margin-top:-4px;margin-bottom:4px;';
16669
- tokenInput.parentNode.insertBefore(hint, tokenInput.nextSibling);
16670
- }
16671
- hint.textContent = msg;
16672
- if (tokenHintTimer) clearTimeout(tokenHintTimer);
16673
- tokenHintTimer = setTimeout(() => {
16674
- tokenInput.style.borderColor = '';
16675
- hint.textContent = '';
16676
- }, 6000);
16677
- }
16678
-
16679
- // --- API helpers ---
16680
- function authHeaders() {
16681
- const token = tokenInput.value.trim();
16682
- return token ? { 'Authorization': 'Bearer ' + token } : {};
16683
- }
16684
-
16685
- async function api(method, path, body) {
16686
- const opts = { method, headers: { ...authHeaders() } };
16687
- if (body !== undefined) {
16688
- opts.headers['Content-Type'] = 'application/json';
16689
- opts.body = JSON.stringify(body);
16690
- }
16691
- logRequest(method, path + (body ? ' ' + JSON.stringify(body) : ''));
16692
- try {
16693
- const res = await fetch(BASE + path, opts);
16694
- const text = await res.text();
16695
- let data;
16696
- try { data = JSON.parse(text); } catch { data = text; }
16697
- if (!res.ok) {
16698
- logError(res.status, JSON.stringify(data));
16699
- if (res.status === 401) {
16700
- highlightTokenInput('API returned 401 \u2014 enter your bearer token below');
16701
- }
16702
- return { ok: false, status: res.status, data };
16703
- }
16704
- logResponse(res.status, JSON.stringify(data));
16705
- return { ok: true, status: res.status, data };
16706
- } catch (err) {
16707
- logError('ERR', err.message);
16708
- return { ok: false, status: 0, data: { error: err.message } };
16709
- }
16710
- }
16711
-
16712
- // --- Health check on load ---
16713
- async function checkHealth() {
16714
- const r = await api('GET', '/health');
16715
- if (r.ok) {
16716
- statusDot.classList.add('ok');
16717
- statusText.textContent = 'Connected';
16718
- } else {
16719
- statusDot.classList.remove('ok');
16720
- statusText.textContent = 'Disconnected';
16721
- }
16722
- }
16723
-
16724
- // --- Session ---
16725
- async function createSession() {
16726
- const cwd = cwdInput.value.trim();
16727
- if (!cwd) { alert('Please enter a working directory'); return; }
16728
- const r = await api('POST', '/session', { cwd });
16729
- if (r.ok) {
16730
- sessionId = r.data.sessionId;
16731
- sessionInfo.style.display = 'block';
16732
- sessionIdDisplay.textContent = sessionId;
16733
- contextUsage.style.display = 'none';
16734
- lastLoggedContextPct = -1;
16735
- enablePrompt(true);
16736
- chatArea.innerHTML = '';
16737
- currentAssistantBubble = null;
16738
- pendingPerms.clear();
16739
- renderPermissions();
16740
- if (r.data.attached) {
16741
- addChatMeta('Attached to existing session');
16742
- } else {
16743
- addChatMeta('New session created');
16744
- }
16745
- connectSSE();
16746
- } else {
16747
- const msg = r.data.error || 'session creation failed (' + r.status + ')';
16748
- addChatMeta('Error: ' + msg);
16749
- if (r.status === 401) highlightTokenInput('Token required or invalid');
16750
- }
16751
- }
16752
-
16753
- function enablePrompt(on) {
16754
- $('#btnSendPrompt').disabled = !on;
16755
- $('#btnCancel').disabled = !on;
16756
- $('#btnSetModel').disabled = !on;
16757
- chatInput.disabled = !on;
16758
- $('#btnChatSend').disabled = !on;
16759
- }
16760
-
16761
- // --- SSE ---
16762
- function connectSSE() {
16763
- if (eventSource) { eventSource.close(); }
16764
- const url = BASE + '/session/' + sessionId + '/events';
16765
- logEvent('SSE', 'Connecting to ' + url);
16766
-
16767
- // Use fetch-based SSE to avoid Origin header issues with EventSource
16768
- const abort = new AbortController();
16769
- eventSource = { close: () => abort.abort() };
16770
-
16771
- (async function readSSE() {
16772
- try {
16773
- const hdrs = authHeaders();
16774
- const res = await fetch(url, { signal: abort.signal, headers: hdrs });
16775
- if (!res.ok) {
16776
- logEvent('SSE-ERR', 'HTTP ' + res.status);
16777
- statusDot.classList.remove('ok');
16778
- statusText.textContent = 'SSE failed (' + res.status + ')';
16779
- enablePrompt(false);
16780
- if (res.status === 401) {
16781
- highlightTokenInput('SSE returned 401 \u2014 enter your bearer token and recreate the session');
16782
- }
16783
- return;
16784
- }
16785
- const reader = res.body.getReader();
16786
- const decoder = new TextDecoder();
16787
- let buffer = '';
16788
- let currentEvent = {};
16789
-
16790
- while (true) {
16791
- const { done, value } = await reader.read();
16792
- if (done) break;
16793
- buffer += decoder.decode(value, { stream: true });
16794
-
16795
- const lines = buffer.split('\\n');
16796
- buffer = lines.pop();
16797
-
16798
- for (const line of lines) {
16799
- if (line.startsWith('data: ')) {
16800
- currentEvent.data = line.slice(6);
16801
- } else if (line.startsWith('event: ')) {
16802
- currentEvent.event = line.slice(7);
16803
- } else if (line.startsWith('id: ')) {
16804
- currentEvent.id = line.slice(4);
16805
- } else if (line === '') {
16806
- if (currentEvent.data) {
16807
- handleSSEMessage(currentEvent);
16808
- }
16809
- currentEvent = {};
16810
- }
16811
- }
16812
- }
16813
- // Process any remaining buffered data
16814
- if (currentEvent.data) handleSSEMessage(currentEvent);
16815
- statusDot.classList.remove('ok');
16816
- statusText.textContent = 'SSE stream ended';
16817
- enablePrompt(false);
16818
- logEvent('SSE', 'Stream ended by server');
16819
- } catch (err) {
16820
- if (err.name !== 'AbortError') {
16821
- logEvent('SSE-ERR', err.message);
16822
- statusDot.classList.remove('ok');
16823
- statusText.textContent = 'SSE error';
16824
- enablePrompt(false);
16825
- }
16826
- }
16827
- })();
16828
- }
16829
-
16830
- function handleSSEMessage(msg) {
16831
- let data;
16832
- try { data = JSON.parse(msg.data); } catch { data = msg.data; }
16833
- const type = data.type || msg.event || 'unknown';
16834
-
16835
- if (type === 'session_update' && data.data) {
16836
- const update = data.data.update || data.data;
16837
- const kind = update.sessionUpdate;
16838
-
16839
- if (kind === 'agent_message_chunk') {
16840
- const text = update.content?.text || '';
16841
- if (text) appendAssistantChunk(text);
16842
- if (update._meta?.usage) {
16843
- const u = update._meta.usage;
16844
- addChatMeta('tokens: in=' + u.inputTokens + ' out=' + u.outputTokens + ' | ' + (update._meta.durationMs || 0) + 'ms');
16845
- currentAssistantBubble = null;
16846
- }
16847
- logEvent('MSG', text || '(usage meta)');
16848
- } else if (kind === 'agent_thought_chunk') {
16849
- const text = update.content?.text || '';
16850
- currentThought += text;
16851
- logEvent('THINK', text);
16852
- } else if (kind === 'usage_update') {
16853
- // One frame per model round: a long agentic turn (/review) emits
16854
- // hundreds, and the raw-JSON fallthrough below turned the Events tab
16855
- // into a scroll of identical lines. Render an in-place meter instead,
16856
- // and log only when the integer percentage moves \u2014 the transitions
16857
- // stay on record without the flood.
16858
- const used = update.used;
16859
- const size = update.size;
16860
- if (typeof used === 'number' && typeof size === 'number' && size > 0) {
16861
- const pct = Math.round((used / size) * 100);
16862
- const label = used + ' / ' + size + ' (' + pct + '%)';
16863
- contextUsage.style.display = 'block';
16864
- contextUsage.textContent = 'Context: ' + label;
16865
- if (pct !== lastLoggedContextPct) {
16866
- lastLoggedContextPct = pct;
16867
- logEvent('CTX', label);
16868
- }
16869
- }
16870
- } else {
16871
- logEvent(kind || type, JSON.stringify(update));
16872
- }
16873
- } else if (type === 'permission_request') {
16874
- handlePermissionRequest(data);
16875
- logEvent('PERM', JSON.stringify(data.data));
16876
- } else if (type === 'permission_resolved') {
16877
- logEvent('PERM-OK', JSON.stringify(data.data));
16878
- removePermission(data.data?.requestId);
16879
- } else if (type === 'session_died') {
16880
- addChatMeta('Session died: ' + JSON.stringify(data.data));
16881
- logEvent('DIED', JSON.stringify(data.data));
16882
- enablePrompt(false);
16883
- } else if (type === 'model_switched') {
16884
- addChatMeta('Model switched: ' + JSON.stringify(data.data));
16885
- logEvent('MODEL', JSON.stringify(data.data));
16886
- } else {
16887
- logEvent(type, JSON.stringify(data));
16888
- }
16889
- }
16890
-
16891
- // --- Chat UI ---
16892
- function addUserMessage(text) {
16893
- currentAssistantBubble = null;
16894
- currentThought = '';
16895
- const el = document.createElement('div');
16896
- el.className = 'chat-msg user';
16897
- el.innerHTML = '<div class="bubble">' + escHtml(text) + '</div>';
16898
- chatArea.appendChild(el);
16899
- chatArea.scrollTop = chatArea.scrollHeight;
16900
- }
16901
-
16902
- function appendAssistantChunk(text) {
16903
- if (!currentAssistantBubble) {
16904
- if (currentThought) {
16905
- const te = document.createElement('div');
16906
- te.className = 'chat-msg assistant';
16907
- te.innerHTML = '<div class="bubble" style="color:var(--text2);font-style:italic;border-color:var(--border)">Thinking: ' + escHtml(currentThought) + '</div>';
16908
- chatArea.appendChild(te);
16909
- currentThought = '';
16910
- }
16911
- const el = document.createElement('div');
16912
- el.className = 'chat-msg assistant';
16913
- el.innerHTML = '<div class="bubble"></div>';
16914
- chatArea.appendChild(el);
16915
- currentAssistantBubble = el.querySelector('.bubble');
16916
- }
16917
- currentAssistantBubble.textContent += text;
16918
- chatArea.scrollTop = chatArea.scrollHeight;
16919
- }
16920
-
16921
- function addChatMeta(text) {
16922
- const el = document.createElement('div');
16923
- el.className = 'chat-msg assistant';
16924
- el.innerHTML = '<div class="meta">' + escHtml(text) + '</div>';
16925
- chatArea.appendChild(el);
16926
- chatArea.scrollTop = chatArea.scrollHeight;
16927
- }
16928
-
16929
- // --- Prompt ---
16930
- let promptInFlight = false;
16931
- async function sendPrompt(text) {
16932
- if (!sessionId || !text.trim() || promptInFlight) return;
16933
- promptInFlight = true;
16934
- enablePrompt(false);
16935
- addUserMessage(text.trim());
16936
- promptInput.value = '';
16937
- chatInput.value = '';
16938
- try {
16939
- const r = await api('POST', '/session/' + sessionId + '/prompt', {
16940
- prompt: [{ type: 'text', text: text.trim() }]
16941
- });
16942
- if (r.ok) {
16943
- addChatMeta('stopReason: ' + (r.data.stopReason || 'unknown'));
16944
- } else {
16945
- addChatMeta('Error: ' + (r.data.error || 'prompt failed (' + r.status + ')'));
16946
- }
16947
- } finally {
16948
- promptInFlight = false;
16949
- if (sessionId) enablePrompt(true);
16950
- }
16951
- }
16952
-
16953
- // --- Permission handling ---
16954
- const pendingPerms = new Map();
16955
-
16956
- function handlePermissionRequest(data) {
16957
- const req = data.data;
16958
- const requestId = req?.requestId;
16959
- if (!requestId) return;
16960
- pendingPerms.set(requestId, req);
16961
- renderPermissions();
16962
-
16963
- addChatMeta('Permission requested: ' + requestId);
16964
- }
16965
-
16966
- function removePermission(requestId) {
16967
- pendingPerms.delete(requestId);
16968
- renderPermissions();
16969
- }
16970
-
16971
- function renderPermissions() {
16972
- if (pendingPerms.size === 0) {
16973
- permissionPanel.style.display = 'none';
16974
- return;
16975
- }
16976
- permissionPanel.style.display = 'block';
16977
- permissionList.innerHTML = '';
16978
- for (const [id, req] of pendingPerms) {
16979
- const card = document.createElement('div');
16980
- card.className = 'permission-card';
16981
-
16982
- const h4 = document.createElement('h4');
16983
- h4.textContent = req.tool?.name || 'Permission';
16984
- card.appendChild(h4);
16985
-
16986
- const idDiv = document.createElement('div');
16987
- idDiv.style.cssText = 'font-size:11px;color:var(--text2);margin-bottom:6px';
16988
- idDiv.textContent = id;
16989
- card.appendChild(idDiv);
16990
-
16991
- // Show toolCall context (command, input, path, etc.) when available
16992
- const tc = req.toolCall || req.tool;
16993
- if (tc) {
16994
- const detail = document.createElement('pre');
16995
- detail.style.cssText = 'font-size:11px;color:var(--text2);margin-bottom:6px;white-space:pre-wrap;word-break:break-all;max-height:120px;overflow-y:auto;background:var(--bg);padding:6px;border-radius:4px;border:1px solid var(--border)';
16996
- const parts = [];
16997
- if (tc.command) parts.push('command: ' + tc.command);
16998
- if (tc.input) parts.push('input: ' + (typeof tc.input === 'string' ? tc.input : JSON.stringify(tc.input, null, 2)));
16999
- if (tc.path) parts.push('path: ' + tc.path);
17000
- if (tc.diff) parts.push('diff: ' + tc.diff);
17001
- if (tc.serverUrl) parts.push('url: ' + tc.serverUrl);
17002
- if (parts.length === 0 && tc.name) parts.push('tool: ' + tc.name);
17003
- if (parts.length > 0) {
17004
- detail.textContent = parts.join('\\n');
17005
- card.appendChild(detail);
17006
- }
17007
- }
17008
-
17009
- function makePermBtn(reqId, optId, label, isCancel) {
17010
- const btn = document.createElement('button');
17011
- btn.className = 'btn opt-btn';
17012
- btn.textContent = label;
17013
- btn.dataset.req = reqId;
17014
- if (isCancel) {
17015
- btn.dataset.cancel = '1';
17016
- btn.style.borderColor = 'var(--err)';
17017
- btn.style.color = 'var(--err)';
17018
- } else {
17019
- btn.dataset.opt = optId;
17020
- }
17021
- btn.addEventListener('click', async () => {
17022
- let outcome;
17023
- if (isCancel) {
17024
- outcome = { outcome: 'cancelled' };
17025
- } else {
17026
- outcome = { outcome: 'selected', optionId: optId };
17027
- }
17028
- const result = await api('POST', '/permission/' + reqId, { outcome });
17029
- if (result.ok) {
17030
- removePermission(reqId);
17031
- } else {
17032
- logError('PERM-ERR', 'Failed to resolve permission ' + reqId + ': ' + JSON.stringify(result.data));
17033
- }
17034
- });
17035
- return btn;
17036
- }
17037
-
17038
- if (req.options && Array.isArray(req.options)) {
17039
- for (const opt of req.options) {
17040
- card.appendChild(makePermBtn(id, opt.optionId, opt.name || opt.optionId, false));
17041
- }
17042
- }
17043
- card.appendChild(makePermBtn(id, null, 'Cancel', true));
17044
- permissionList.appendChild(card);
17045
- }
17046
- }
17047
-
17048
- // --- Button bindings ---
17049
- $('#btnCreateSession').addEventListener('click', createSession);
17050
- $('#btnListSessions').addEventListener('click', async () => {
17051
- const cwd = cwdInput.value.trim();
17052
- if (!cwd) { alert('Enter a cwd first'); return; }
17053
- await api('GET', '/workspace/' + encodeURIComponent(cwd) + '/sessions');
17054
- });
17055
- $('#btnSendPrompt').addEventListener('click', () => sendPrompt(promptInput.value));
17056
- $('#btnChatSend').addEventListener('click', () => sendPrompt(chatInput.value));
17057
- chatInput.addEventListener('keydown', (e) => {
17058
- if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendPrompt(chatInput.value); }
17059
- });
17060
- promptInput.addEventListener('keydown', (e) => {
17061
- if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendPrompt(promptInput.value); }
17062
- });
17063
- $('#btnCancel').addEventListener('click', async () => {
17064
- if (!sessionId) return;
17065
- await api('POST', '/session/' + sessionId + '/cancel', {});
17066
- });
17067
- $('#btnSetModel').addEventListener('click', async () => {
17068
- if (!sessionId) return;
17069
- const mid = modelInput.value.trim();
17070
- if (!mid) { alert('Enter a model ID'); return; }
17071
- await api('POST', '/session/' + sessionId + '/model', { modelId: mid });
17072
- });
17073
- $('#btnHealth').addEventListener('click', () => api('GET', '/health'));
17074
- $('#btnHealthDeep').addEventListener('click', () => api('GET', '/health?deep=1'));
17075
- $('#btnCaps').addEventListener('click', () => api('GET', '/capabilities'));
17076
-
17077
- // --- Init ---
17078
- checkHealth();
17079
- })();
17080
- </script>
17081
- </body>
17082
- </html>`
17083
- );
17084
- }
17085
- __name(getDemoHtml, "getDemoHtml");
17086
-
17087
- // packages/cli/src/serve/routes/health-demo.ts
17088
- function createHealthDemoRoutes(deps) {
17089
- const {
17090
- opts,
17091
- getPort,
17092
- workspaceRegistry,
17093
- getActiveSseCount: getActiveSseCount2,
17094
- getRateLimiter
17095
- } = deps;
17096
- const demoHandler = /* @__PURE__ */ __name((_req, res) => {
17097
- try {
17098
- res.type("html").set("X-Frame-Options", "DENY").set(
17099
- "Content-Security-Policy",
17100
- "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'self'; frame-ancestors 'none'"
17101
- ).send(getDemoHtml(getPort()));
17102
- } catch (err) {
17103
- writeStderrLine(
17104
- `qwen serve: /demo render failed: ${err instanceof Error ? err.message : String(err)}`
17105
- );
17106
- res.status(500).json({ error: "Failed to render demo page" });
17107
- }
17108
- }, "demoHandler");
16570
+ function createHealthRoutes(deps) {
16571
+ const { opts, workspaceRegistry, getActiveSseCount: getActiveSseCount2, getRateLimiter } = deps;
17109
16572
  const healthHandler = /* @__PURE__ */ __name((req, res) => {
17110
16573
  if (!isDeepHealthQuery(req.query["deep"])) {
17111
16574
  res.status(200).json({ status: "ok" });
@@ -17195,11 +16658,10 @@ function createHealthDemoRoutes(deps) {
17195
16658
  exposeHealthPreAuth,
17196
16659
  register(app) {
17197
16660
  app.get("/health", healthHandler);
17198
- app.get("/demo", demoHandler);
17199
16661
  }
17200
16662
  };
17201
16663
  }
17202
- __name(createHealthDemoRoutes, "createHealthDemoRoutes");
16664
+ __name(createHealthRoutes, "createHealthRoutes");
17203
16665
 
17204
16666
  // packages/cli/src/serve/routes/workspace-auth.ts
17205
16667
  init_esbuild_shims();
@@ -39862,11 +39324,13 @@ var execFileAsync3 = promisify3(execFile3);
39862
39324
  var LIVE_HOST_BUNDLE_ID2 = "com.alibaba.qwen-code.live-host";
39863
39325
  var LIVE_HOST_TEAM_IDENTIFIER = "NF4574S59H";
39864
39326
  var LIVE_HOST_APP_PATH = "/Applications/Qwen Live Host.app";
39327
+ var LIVE_HOST_OSS_BASE_URL = "https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/live-host";
39865
39328
  var LIVE_HOST_RELEASE_BASE_URL = "https://github.com/QwenLM/qwen-code/releases/download/live-host-latest";
39866
39329
  var LIVE_HOST_MANIFEST_NAME = "Qwen-Live-Host-manifest.json";
39330
+ var LIVE_HOST_MANIFEST_FETCH_TIMEOUT_MS = 5 * 60 * 1e3;
39331
+ var LIVE_HOST_DOWNLOAD_TIMEOUT_MS = 60 * 60 * 1e3;
39867
39332
  var LIVE_HOST_APP_NAME = "Qwen Live Host.app";
39868
39333
  var MAX_DOWNLOAD_BYTES = 512 * 1024 * 1024;
39869
- var FETCH_TIMEOUT_MS = 5 * 60 * 1e3;
39870
39334
  var COMMAND_TIMEOUT_MS = 2 * 60 * 1e3;
39871
39335
  var SHA256_PATTERN = /^[a-f0-9]{64}$/;
39872
39336
  var VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
@@ -39982,11 +39446,24 @@ async function inspectInstalledHost() {
39982
39446
  }
39983
39447
  }
39984
39448
  __name(inspectInstalledHost, "inspectInstalledHost");
39985
- async function fetchManifest() {
39986
- const response = await fetch(
39987
- `${LIVE_HOST_RELEASE_BASE_URL}/${LIVE_HOST_MANIFEST_NAME}`,
39988
- { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) }
39989
- );
39449
+ function resolveLiveHostManifestUrls() {
39450
+ return [
39451
+ `${LIVE_HOST_OSS_BASE_URL}/latest/${LIVE_HOST_MANIFEST_NAME}`,
39452
+ `${LIVE_HOST_RELEASE_BASE_URL}/${LIVE_HOST_MANIFEST_NAME}`
39453
+ ];
39454
+ }
39455
+ __name(resolveLiveHostManifestUrls, "resolveLiveHostManifestUrls");
39456
+ function resolveLiveHostAssetUrls(version, assetName) {
39457
+ return [
39458
+ `${LIVE_HOST_OSS_BASE_URL}/v${version}/${assetName}`,
39459
+ `${LIVE_HOST_RELEASE_BASE_URL}/${assetName}`
39460
+ ];
39461
+ }
39462
+ __name(resolveLiveHostAssetUrls, "resolveLiveHostAssetUrls");
39463
+ async function fetchManifest(url, fetchImpl) {
39464
+ const response = await fetchImpl(url, {
39465
+ signal: AbortSignal.timeout(LIVE_HOST_MANIFEST_FETCH_TIMEOUT_MS)
39466
+ });
39990
39467
  if (!response.ok) {
39991
39468
  await response.body?.cancel().catch(() => {
39992
39469
  });
@@ -39995,9 +39472,9 @@ async function fetchManifest() {
39995
39472
  return parseLiveHostReleaseManifest(await response.json());
39996
39473
  }
39997
39474
  __name(fetchManifest, "fetchManifest");
39998
- async function downloadAsset(asset, destination, onProgress) {
39999
- const response = await fetch(`${LIVE_HOST_RELEASE_BASE_URL}/${asset.name}`, {
40000
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
39475
+ async function downloadAsset(asset, url, destination, onProgress, fetchImpl) {
39476
+ const response = await fetchImpl(url, {
39477
+ signal: AbortSignal.timeout(LIVE_HOST_DOWNLOAD_TIMEOUT_MS)
40001
39478
  });
40002
39479
  if (!response.ok || !response.body) {
40003
39480
  await response.body?.cancel().catch(() => {
@@ -40034,13 +39511,36 @@ async function downloadAsset(asset, destination, onProgress) {
40034
39511
  }
40035
39512
  }
40036
39513
  __name(downloadAsset, "downloadAsset");
39514
+ async function downloadLiveHostRelease(currentArchitecture, destination, onProgress, fetchImpl = fetch) {
39515
+ const manifestUrls = resolveLiveHostManifestUrls();
39516
+ const labels = ["OSS", "GitHub"];
39517
+ const errors = [];
39518
+ for (let index = 0; index < manifestUrls.length; index += 1) {
39519
+ try {
39520
+ await fsp5.rm(destination, { force: true });
39521
+ const manifest = await fetchManifest(manifestUrls[index], fetchImpl);
39522
+ const asset = manifest.assets[currentArchitecture];
39523
+ const assetUrl = resolveLiveHostAssetUrls(manifest.version, asset.name)[index];
39524
+ await downloadAsset(asset, assetUrl, destination, onProgress, fetchImpl);
39525
+ return { manifest, asset };
39526
+ } catch (error2) {
39527
+ errors.push(
39528
+ new Error(`${labels[index]}: ${errorMessage3(error2)}`, { cause: error2 })
39529
+ );
39530
+ }
39531
+ }
39532
+ await fsp5.rm(destination, { force: true });
39533
+ throw new AggregateError(
39534
+ errors,
39535
+ `Qwen Live Host download failed. ${errors.map((error2) => error2.message).join(" ")}`
39536
+ );
39537
+ }
39538
+ __name(downloadLiveHostRelease, "downloadLiveHostRelease");
40037
39539
  async function installLatestHost(currentArchitecture, onStatus) {
40038
- const manifest = await fetchManifest();
40039
- const asset = manifest.assets[currentArchitecture];
40040
39540
  const temporaryDirectory = await fsp5.mkdtemp(
40041
39541
  path14.join(os2.tmpdir(), "qwen-live-host-")
40042
39542
  );
40043
- const archivePath = path14.join(temporaryDirectory, asset.name);
39543
+ const archivePath = path14.join(temporaryDirectory, "Qwen-Live-Host.zip");
40044
39544
  const extractedPath = path14.join(temporaryDirectory, "extracted");
40045
39545
  const candidatePath = path14.join(extractedPath, LIVE_HOST_APP_NAME);
40046
39546
  const stagingPath = `/Applications/.Qwen Live Host.install-${randomUUID11()}.app`;
@@ -40049,9 +39549,13 @@ async function installLatestHost(currentArchitecture, onStatus) {
40049
39549
  let installedCandidate = false;
40050
39550
  try {
40051
39551
  onStatus({ state: "downloading", progress: 0 });
40052
- await downloadAsset(asset, archivePath, (progress) => {
40053
- onStatus({ state: "downloading", progress });
40054
- });
39552
+ const { manifest } = await downloadLiveHostRelease(
39553
+ currentArchitecture,
39554
+ archivePath,
39555
+ (progress) => {
39556
+ onStatus({ state: "downloading", progress });
39557
+ }
39558
+ );
40055
39559
  onStatus({ state: "verifying" });
40056
39560
  await fsp5.mkdir(extractedPath, { mode: 448 });
40057
39561
  await run("/usr/bin/ditto", ["-x", "-k", archivePath, extractedPath]);
@@ -43116,9 +42620,12 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
43116
42620
  // that don't inject `deps.bridge` get daemon env + preflight cells.
43117
42621
  statusProvider,
43118
42622
  delegateReadTextFileToClient: false,
43119
- // Final ACP text writes remain delegated through WorkspaceFileSystem.
42623
+ // Final ACP text writes remain delegated. Workspace writes use WFS;
42624
+ // marked same-host tool writes may use the factory's host writer.
43120
42625
  // Unexpected delegated reads still fail closed at the WFS boundary.
43121
- fileSystem: createBridgeFileSystemAdapter(fsFactory),
42626
+ fileSystem: createBridgeFileSystemAdapter(fsFactory, {
42627
+ allowSameHostToolWritesOutsideWorkspace: deps.fsFactory === void 0
42628
+ }),
43122
42629
  // Reverse tool channel: answer the child's `client_mcp/message`
43123
42630
  // ext-method by reaching the WS connection that hosts the named server.
43124
42631
  clientMcpSender: clientMcpSenderRegistry.lookup
@@ -43555,15 +43062,14 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
43555
43062
  mount: false,
43556
43063
  workspaceQualifiedAcpEnabled
43557
43064
  });
43558
- const healthDemoRoutes = createHealthDemoRoutes({
43065
+ const healthRoutes = createHealthRoutes({
43559
43066
  opts,
43560
- getPort,
43561
43067
  workspaceRegistry,
43562
43068
  getActiveSseCount,
43563
43069
  getRateLimiter: /* @__PURE__ */ __name(() => rateLimiter, "getRateLimiter")
43564
43070
  });
43565
- if (healthDemoRoutes.exposeHealthPreAuth) {
43566
- healthDemoRoutes.register(app);
43071
+ if (healthRoutes.exposeHealthPreAuth) {
43072
+ healthRoutes.register(app);
43567
43073
  }
43568
43074
  installAccessLogMiddleware(app, daemonLog);
43569
43075
  const webShellDir = opts.serveWebShell !== false ? deps.webShellDir : void 0;
@@ -43610,8 +43116,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
43610
43116
  if (rateLimiter) {
43611
43117
  app.use(rateLimiter.middleware);
43612
43118
  }
43613
- if (!healthDemoRoutes.exposeHealthPreAuth) {
43614
- healthDemoRoutes.register(app);
43119
+ if (!healthRoutes.exposeHealthPreAuth) {
43120
+ healthRoutes.register(app);
43615
43121
  }
43616
43122
  installJsonBodyParser(app);
43617
43123
  const mutate = createMutationGate({