@qwen-code/qwen-code 0.19.6-nightly.20260707.bcdb44c5d → 0.19.6-preview.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
  2. package/bundled/qc-helper/docs/features/channels/overview.md +17 -9
  3. package/bundled/qc-helper/docs/features/channels/wecom.md +111 -0
  4. package/bundled/qc-helper/docs/features/code-review.md +0 -4
  5. package/bundled/review/DESIGN.md +0 -4
  6. package/bundled/review/SKILL.md +2 -29
  7. package/chunks/{MaxSizedBox-EFDCCPYQ.js → MaxSizedBox-2JOX4MMR.js} +11 -9
  8. package/chunks/{StandaloneSessionPicker-5TQG34MY.js → StandaloneSessionPicker-Z2G37ETA.js} +24 -21
  9. package/chunks/{acpAgent-KQT52XWB.js → acpAgent-MQJT2H4Y.js} +74 -49
  10. package/chunks/{agent-RL2YOM2V.js → agent-HEVJ76EO.js} +6 -6
  11. package/chunks/{agent-headless-SCVFLRZ3.js → agent-headless-UNB5SWYC.js} +6 -6
  12. package/chunks/{anthropicContentGenerator-PPPLABT5.js → anthropicContentGenerator-AKYPSZIV.js} +3 -3
  13. package/chunks/{artifact-tool-H2TNPNP5.js → artifact-tool-D233YJFH.js} +25 -6
  14. package/chunks/{bridge-G3LFYH2D.js → bridge-GX2LGQDS.js} +11 -9
  15. package/chunks/{channel-worker-supervisor-B7MSMB5K.js → channel-worker-supervisor-CRCVYQIE.js} +1 -1
  16. package/chunks/{chunk-XUYYEFCM.js → chunk-27QGW3BK.js} +5 -5
  17. package/chunks/{chunk-HLJMZYTD.js → chunk-2D5Q33PT.js} +3 -3
  18. package/chunks/{chunk-TNIZ2HCQ.js → chunk-2MDHTI6A.js} +2 -2
  19. package/chunks/{chunk-VCKMHAEZ.js → chunk-2MJAXDFK.js} +6 -6
  20. package/chunks/{chunk-WSVZFWN4.js → chunk-2NPS2UDH.js} +305 -97
  21. package/chunks/{chunk-WAVK7GV6.js → chunk-2X3ZVAAT.js} +2 -2
  22. package/chunks/chunk-332PWN27.js +19 -0
  23. package/chunks/{chunk-FVMWEHWU.js → chunk-3B26UVCX.js} +114 -12
  24. package/chunks/{chunk-XZ2LJL4O.js → chunk-43W4YSO6.js} +1 -12
  25. package/chunks/{chunk-DLHOIROF.js → chunk-44NROQYV.js} +4 -2
  26. package/chunks/{chunk-65P5ZXUE.js → chunk-4XV2MRNK.js} +1 -1
  27. package/chunks/{chunk-DS6NG7SB.js → chunk-5HMMLTUD.js} +11 -11
  28. package/chunks/{chunk-A2CS67WK.js → chunk-5IGNZP2J.js} +1 -1
  29. package/chunks/{chunk-N7BUPX4V.js → chunk-6GHEZDDX.js} +1 -1
  30. package/chunks/{chunk-QU6OLW25.js → chunk-7O6DD2ES.js} +1 -1
  31. package/chunks/{chunk-RXDYWLOG.js → chunk-7R62CLMI.js} +4 -4
  32. package/chunks/{chunk-2BJWUJCW.js → chunk-7SAH6M3Y.js} +3 -3
  33. package/chunks/{chunk-OGAC66WF.js → chunk-7VCI24VZ.js} +4 -107
  34. package/chunks/chunk-A2X3KLC3.js +3807 -0
  35. package/chunks/chunk-A3ZQMFO6.js +949 -0
  36. package/chunks/{chunk-AY7CP32Q.js → chunk-A7UKINBT.js} +7 -7
  37. package/chunks/{chunk-72DDO73Z.js → chunk-ADO6IDOZ.js} +8 -8
  38. package/chunks/{chunk-UOGOM4NJ.js → chunk-AJ3CEJRJ.js} +10 -5
  39. package/chunks/{chunk-NCFY7PWS.js → chunk-CCGOFQV3.js} +51 -2
  40. package/chunks/{chunk-YFE4YEDW.js → chunk-DB7CZERZ.js} +1 -1
  41. package/chunks/{chunk-UECJ7AG2.js → chunk-DF74IL3R.js} +4 -4
  42. package/chunks/{chunk-7YLLBKDB.js → chunk-FCEHOKYP.js} +5 -5
  43. package/chunks/{chunk-JO6RDLLE.js → chunk-FRR5I3SQ.js} +1 -1
  44. package/chunks/{chunk-2NL7ED5Q.js → chunk-FV7425LN.js} +22 -1
  45. package/chunks/{chunk-NCOLCOA6.js → chunk-GPLKAQUX.js} +8 -8
  46. package/chunks/{chunk-AKGA72ZM.js → chunk-GV2S4F6Q.js} +5 -3
  47. package/chunks/{chunk-V63Q7BVE.js → chunk-GW67O5SO.js} +1 -1
  48. package/chunks/{chunk-2A6XOMBQ.js → chunk-HW4N45EE.js} +0 -44
  49. package/chunks/{chunk-S6PM5JQZ.js → chunk-IFDJAMJW.js} +484 -1222
  50. package/chunks/{chunk-B2FUQ22Z.js → chunk-ILFQAFWH.js} +1 -1
  51. package/chunks/chunk-JYFZFWSL.js +167 -0
  52. package/chunks/{chunk-CA373SPN.js → chunk-K56RTEBN.js} +1 -1
  53. package/chunks/chunk-LGFAYIKX.js +115 -0
  54. package/chunks/{chunk-6JESGXWU.js → chunk-LLTFLVFK.js} +4 -4
  55. package/chunks/{chunk-3A4MUHRP.js → chunk-MZWODTEA.js} +5 -13
  56. package/chunks/{chunk-IPKM25FZ.js → chunk-N33JAGJ7.js} +505 -62
  57. package/chunks/{chunk-B2NCNYBK.js → chunk-NVQVIJMO.js} +112 -42
  58. package/chunks/{chunk-INNPK6XG.js → chunk-O6T7PBUM.js} +30 -6
  59. package/chunks/{chunk-RN36CE4M.js → chunk-P452E6XF.js} +2 -2
  60. package/chunks/chunk-PS2NG7KU.js +262 -0
  61. package/chunks/{chunk-FTEFJT6V.js → chunk-QM4FKX7H.js} +2 -2
  62. package/chunks/chunk-RODQXLGZ.js +28 -0
  63. package/chunks/{chunk-KSPVDFE4.js → chunk-SAIILPQ3.js} +0 -3
  64. package/chunks/{chunk-EKDTGEX4.js → chunk-SJ3QRPN2.js} +14 -8
  65. package/chunks/{chunk-R57UD732.js → chunk-SKO6VJHG.js} +16 -4
  66. package/chunks/{chunk-66KNL43D.js → chunk-TBAZMRW3.js} +1 -1
  67. package/chunks/{chunk-H2UZO2II.js → chunk-TPTG52XG.js} +1 -1
  68. package/chunks/chunk-UIDXQNMV.js +13 -0
  69. package/chunks/chunk-VP2FB7OC.js +8223 -0
  70. package/chunks/{chunk-32KIF557.js → chunk-WKBA74DD.js} +1 -1
  71. package/chunks/{chunk-IEFMDFCG.js → chunk-WKTLDGD6.js} +1 -1
  72. package/chunks/{chunk-HT553O4R.js → chunk-WRLMLPWI.js} +3 -3
  73. package/chunks/{chunk-CYXPEKVN.js → chunk-XXICIIS5.js} +5 -5
  74. package/chunks/{chunk-5GSUPP7K.js → chunk-Y3QQV7WE.js} +2 -2
  75. package/chunks/{chunk-CKBRK552.js → chunk-ZKX7IBXU.js} +4 -4
  76. package/chunks/{chunk-CCPKBMZ4.js → chunk-ZOSL7K3L.js} +203 -38
  77. package/chunks/{chunk-KD4KV6XW.js → chunk-ZWFS7YCB.js} +4505 -3850
  78. package/chunks/{computer-use-NKJX6RTG.js → computer-use-IQ46C3YP.js} +6 -6
  79. package/chunks/{contextCommand-BCABFW4A.js → contextCommand-TTT6AP2W.js} +10 -9
  80. package/chunks/{cron-create-DDYU4DIR.js → cron-create-JSXEIPVS.js} +1 -1
  81. package/chunks/{cron-delete-DFKOUZWN.js → cron-delete-OIFVEPGU.js} +1 -1
  82. package/chunks/{cron-list-ME5QGAR5.js → cron-list-D4ZX4IOE.js} +1 -1
  83. package/chunks/{daemon-XWG2EGFX.js → daemon-F3I2RXP6.js} +23 -3
  84. package/chunks/{daemon-status-provider-V7BMA4EH.js → daemon-status-provider-5GAWK65R.js} +13 -12
  85. package/chunks/dist-573HNSVO.js +3217 -0
  86. package/chunks/{dist-VHBP2PIG.js → dist-FQ5WRJPL.js} +2 -2
  87. package/chunks/{dist-LPVU3L2M.js → dist-IMFFBMAT.js} +6 -3792
  88. package/chunks/{dist-7GU63KI5.js → dist-OT7G2WNM.js} +1 -1
  89. package/chunks/{dist-H4HHZYCI.js → dist-PKFTNUHO.js} +2 -2
  90. package/chunks/{dist-3UDX5T4T.js → dist-YTRKAVUB.js} +1 -1
  91. package/chunks/{earlyInputCapture-TVECMHWI.js → earlyInputCapture-LAGZUGGV.js} +6 -6
  92. package/chunks/{edit-VKUCEX2N.js → edit-Q5BUQC2S.js} +6 -6
  93. package/chunks/{en-AXARKOWO.js → en-GA2RMXY5.js} +5 -1
  94. package/chunks/{enter-worktree-TF6N7GA7.js → enter-worktree-DC4FHMVF.js} +6 -6
  95. package/chunks/{enterPlanMode-XXQGZP5T.js → enterPlanMode-5BGJBWIY.js} +6 -6
  96. package/chunks/{errors-LLC2B5D6.js → errors-EGX5DECS.js} +8 -8
  97. package/chunks/{exit-worktree-YBOMMZLI.js → exit-worktree-2EOSZNZI.js} +6 -6
  98. package/chunks/{exitPlanMode-74D7EOBH.js → exitPlanMode-JAQ35ELJ.js} +6 -6
  99. package/chunks/{fast-path-OGY4P74O.js → fast-path-QEWDA6O6.js} +5 -2
  100. package/chunks/{fr-MBMNQSQ6.js → fr-GWNQG4XH.js} +4 -0
  101. package/chunks/{gemini-IL6H4VNW.js → gemini-TQ5XANRS.js} +64 -187
  102. package/chunks/{geminiContentGenerator-O7OCAUQU.js → geminiContentGenerator-DCM2XGDQ.js} +1 -1
  103. package/chunks/{glob-X5XFJTAC.js → glob-7JLTQ4IQ.js} +6 -6
  104. package/chunks/{grep-53GLRSNS.js → grep-CAUXEO7Q.js} +6 -6
  105. package/chunks/handleAutoUpdate-XKXULZQX.js +65 -0
  106. package/chunks/{initializer-YBUEYP6D.js → initializer-3NRWU5JV.js} +12 -10
  107. package/chunks/{ja-HFV5QCHR.js → ja-2HOTA47X.js} +4 -0
  108. package/chunks/{list-2F3FSN46.js → list-NWO6QBDQ.js} +12 -12
  109. package/chunks/{loadedSettingsAdapter-AJBE627U.js → loadedSettingsAdapter-PJ77LGFS.js} +10 -10
  110. package/chunks/{loop-wakeup-ZW5P6VPY.js → loop-wakeup-OHWEMFP5.js} +2 -2
  111. package/chunks/{mcp-SEE2Z7TA.js → mcp-VFEHVF5A.js} +10 -10
  112. package/chunks/{monitor-YQW2M3DL.js → monitor-FY2ITVSC.js} +14 -9
  113. package/chunks/{nonInteractiveCli-TGWJDY47.js → nonInteractiveCli-KPCXTVWY.js} +41 -36
  114. package/chunks/{notebook-edit-O5G3EBYN.js → notebook-edit-BSJMXIWX.js} +6 -6
  115. package/chunks/{openaiContentGenerator-WAO7PPR6.js → openaiContentGenerator-BA6NWY4S.js} +5 -5
  116. package/chunks/{pidfile-XMDB2SF7.js → pidfile-WXMRN6QF.js} +6 -6
  117. package/chunks/{qwenContentGenerator-5NZ5EHRA.js → qwenContentGenerator-U4ZSLGFN.js} +8 -8
  118. package/chunks/{read-file-KJTMBLFF.js → read-file-VMVHNOMA.js} +2 -2
  119. package/chunks/{ripGrep-BCDYVQQR.js → ripGrep-NC6MUWXN.js} +6 -6
  120. package/chunks/{run-qwen-serve-LIWM3CMV.js → run-qwen-serve-NQH6LQTH.js} +124 -31
  121. package/chunks/{scheduler-VETDW3HX.js → scheduler-35T3E2UQ.js} +6 -6
  122. package/chunks/{serve-XKFTUZET.js → serve-C36LOB5N.js} +10 -10
  123. package/chunks/{server-W64GXOEJ.js → server-TDFPIDC3.js} +858 -105
  124. package/chunks/{session-GXNRZGVF.js → session-STHNQGRJ.js} +42 -37
  125. package/chunks/{settings-TIQCDHBZ.js → settings-GIE22AYF.js} +9 -9
  126. package/chunks/{shell-3ZZLLA35.js → shell-JD52AIMU.js} +6 -6
  127. package/chunks/{skill-TOX5QGBX.js → skill-L4IFKRQ5.js} +14 -4
  128. package/chunks/{spawnChannel-JBLAIP7L.js → spawnChannel-HGMOEPM7.js} +8 -8
  129. package/chunks/{src-Q7BIRWUP.js → src-3SNF3G3V.js} +15 -7
  130. package/chunks/{startInteractiveUI-PP72WI64.js → startInteractiveUI-C7DCDHGF.js} +4981 -13173
  131. package/chunks/{team-create-S44Z3N62.js → team-create-NYL7KAMA.js} +6 -6
  132. package/chunks/{team-plan-approval-2YPLSLO5.js → team-plan-approval-LH65JBEH.js} +6 -6
  133. package/chunks/{theme-manager-4MJVYHPB.js → theme-manager-ANKQO5DR.js} +6 -6
  134. package/chunks/{tool-search-4LSRQ24Z.js → tool-search-WZEGJFO4.js} +4 -21
  135. package/chunks/{trustedFolders-XMKLRQDH.js → trustedFolders-HECAG3S3.js} +7 -7
  136. package/chunks/updateCheck-72BBAE5V.js +65 -0
  137. package/chunks/{validateNonInterActiveAuth-MMMRF6WS.js → validateNonInterActiveAuth-PDQCPSNA.js} +38 -33
  138. package/chunks/{version-6HMEMR4K.js → version-VSEUTPNM.js} +2 -1
  139. package/chunks/{workflow-VYBLLOLC.js → workflow-DPF2CL7U.js} +7 -7
  140. package/chunks/{workspace-providers-status-5LSCQPWQ.js → workspace-providers-status-TQ23DQ2D.js} +12 -12
  141. package/chunks/{workspace-service-HBMBWJ4K.js → workspace-service-D34UDMEY.js} +14 -14
  142. package/chunks/{workspace-skills-status-TLBAQWKQ.js → workspace-skills-status-4DR5UNNC.js} +11 -11
  143. package/chunks/{write-file-QMAWLWCT.js → write-file-VFNAKGYM.js} +6 -6
  144. package/chunks/{zh-RS3HZHFH.js → zh-7XVVRTDH.js} +5 -1
  145. package/chunks/{zh-TW-L5GRQ4S4.js → zh-TW-DPH554OG.js} +5 -1
  146. package/cli.js +11 -11
  147. package/locales/en.js +8 -2
  148. package/locales/fr.js +6 -0
  149. package/locales/ja.js +6 -0
  150. package/locales/zh-TW.js +8 -2
  151. package/locales/zh.js +8 -2
  152. package/node_modules/@qwen-code/audio-capture/package.json +1 -1
  153. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
  154. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
  155. package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
  156. package/package.json +3 -3
  157. package/web-shell/assets/{arc-CqwzD3ok.js → arc-C7hjaa7g.js} +1 -1
  158. package/web-shell/assets/{architectureDiagram-3BPJPVTR-BfA-P0-O.js → architectureDiagram-3BPJPVTR-pm9KtMZY.js} +1 -1
  159. package/web-shell/assets/{blockDiagram-GPEHLZMM-DNTzkXRp.js → blockDiagram-GPEHLZMM-CApElKsU.js} +1 -1
  160. package/web-shell/assets/{c4Diagram-AAUBKEIU-D5axQoXQ.js → c4Diagram-AAUBKEIU-BeDe0-9N.js} +1 -1
  161. package/web-shell/assets/channel-BNf1dW-j.js +1 -0
  162. package/web-shell/assets/{chunk-2J33WTMH-CV0P48eN.js → chunk-2J33WTMH-DJEkmLdl.js} +1 -1
  163. package/web-shell/assets/{chunk-4BX2VUAB-CghJNPCS.js → chunk-4BX2VUAB-DXX8gdpe.js} +1 -1
  164. package/web-shell/assets/{chunk-55IACEB6-BrD-776x.js → chunk-55IACEB6-DORmk1kQ.js} +1 -1
  165. package/web-shell/assets/{chunk-727SXJPM-DLKkI5Yu.js → chunk-727SXJPM-DWmO4mCZ.js} +1 -1
  166. package/web-shell/assets/{chunk-AQP2D5EJ-C0HWhZNK.js → chunk-AQP2D5EJ-C7LRaYw2.js} +1 -1
  167. package/web-shell/assets/{chunk-FMBD7UC4-Cg6PsiNL.js → chunk-FMBD7UC4-CCdXgyC5.js} +1 -1
  168. package/web-shell/assets/{chunk-ND2GUHAM-B1pCuSlf.js → chunk-ND2GUHAM-SyL_xvWc.js} +1 -1
  169. package/web-shell/assets/{chunk-QZHKN3VN-CkE8llI2.js → chunk-QZHKN3VN-BzOuCKxa.js} +1 -1
  170. package/web-shell/assets/classDiagram-4FO5ZUOK-uOIGlzgi.js +1 -0
  171. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-uOIGlzgi.js +1 -0
  172. package/web-shell/assets/{cose-bilkent-S5V4N54A-Btr-W-vN.js → cose-bilkent-S5V4N54A-BMPWyDKc.js} +1 -1
  173. package/web-shell/assets/{dagre-BM42HDAG-CAhjVa5L.js → dagre-BM42HDAG-B_GnPWik.js} +1 -1
  174. package/web-shell/assets/{diagram-2AECGRRQ-eUQodUXw.js → diagram-2AECGRRQ-fJqMc3S_.js} +1 -1
  175. package/web-shell/assets/{diagram-5GNKFQAL-BiPKbH6E.js → diagram-5GNKFQAL-ximV3O9D.js} +1 -1
  176. package/web-shell/assets/{diagram-KO2AKTUF-DxuwR-Pu.js → diagram-KO2AKTUF-2vVyjzqw.js} +1 -1
  177. package/web-shell/assets/{diagram-LMA3HP47-nz9SQ3Az.js → diagram-LMA3HP47-Dckcx1sT.js} +1 -1
  178. package/web-shell/assets/{diagram-OG6HWLK6-UBbYk-Jq.js → diagram-OG6HWLK6-BAVv47ga.js} +1 -1
  179. package/web-shell/assets/{erDiagram-TEJ5UH35-BLpRQmgi.js → erDiagram-TEJ5UH35-Bn3nf5J0.js} +1 -1
  180. package/web-shell/assets/{flowDiagram-I6XJVG4X-C5Qqg1hx.js → flowDiagram-I6XJVG4X-BIbGF9JT.js} +1 -1
  181. package/web-shell/assets/{ganttDiagram-6RSMTGT7-BMdf3kjL.js → ganttDiagram-6RSMTGT7-CDbhb3AH.js} +1 -1
  182. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-D9qG7BKD.js → gitGraphDiagram-PVQCEYII-CbKG1a_w.js} +1 -1
  183. package/web-shell/assets/index-CnE2ur2L.js +779 -0
  184. package/web-shell/assets/index-hSKXrlSE.css +5 -0
  185. package/web-shell/assets/{infoDiagram-5YYISTIA-CtDBPJM8.js → infoDiagram-5YYISTIA-DUFxTy8m.js} +1 -1
  186. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BQaS7H3_.js → ishikawaDiagram-YF4QCWOH-D69hrBG8.js} +1 -1
  187. package/web-shell/assets/{journeyDiagram-JHISSGLW-CEEujCNX.js → journeyDiagram-JHISSGLW-DsvEw51Y.js} +1 -1
  188. package/web-shell/assets/{kanban-definition-UN3LZRKU-B3QqyyNi.js → kanban-definition-UN3LZRKU-lFFjZEYd.js} +1 -1
  189. package/web-shell/assets/{linear-DC2Azd_6.js → linear-Bo5bWzvo.js} +1 -1
  190. package/web-shell/assets/{mermaid.core-DL5PRmh-.js → mermaid.core-C_HKMJx5.js} +5 -5
  191. package/web-shell/assets/{mindmap-definition-RKZ34NQL-DGlkd_fb.js → mindmap-definition-RKZ34NQL-DlV-NUTs.js} +1 -1
  192. package/web-shell/assets/{pieDiagram-4H26LBE5-Dew4R8DT.js → pieDiagram-4H26LBE5-B2e6FH2a.js} +1 -1
  193. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-Bk02Tejc.js → quadrantDiagram-W4KKPZXB-D75kSk-b.js} +1 -1
  194. package/web-shell/assets/{requirementDiagram-4Y6WPE33-BkWJE-6M.js → requirementDiagram-4Y6WPE33-CQ6xakhM.js} +1 -1
  195. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-BM9bZAuM.js → sankeyDiagram-5OEKKPKP-J_XTKrcY.js} +1 -1
  196. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-IaE2rOTu.js → sequenceDiagram-3UESZ5HK-D7jTcBtf.js} +1 -1
  197. package/web-shell/assets/{stateDiagram-AJRCARHV-CQH-ENFJ.js → stateDiagram-AJRCARHV-CrlM_OT3.js} +1 -1
  198. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-Bs4TK_84.js +1 -0
  199. package/web-shell/assets/{timeline-definition-PNZ67QCA-DVH5FaeF.js → timeline-definition-PNZ67QCA-5oZi76Ef.js} +1 -1
  200. package/web-shell/assets/{vennDiagram-CIIHVFJN-ChT6J8JT.js → vennDiagram-CIIHVFJN-DO5YptPK.js} +1 -1
  201. package/web-shell/assets/{wardley-L42UT6IY-D9W5AEjE.js → wardley-L42UT6IY-4t1eJDvM.js} +1 -1
  202. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-cNYKmuIA.js → wardleyDiagram-YWT4CUSO-DKZc661S.js} +1 -1
  203. package/web-shell/assets/{xychartDiagram-2RQKCTM6-BleLm4BJ.js → xychartDiagram-2RQKCTM6-su9hp08G.js} +1 -1
  204. package/web-shell/index.html +2 -2
  205. package/web-shell/assets/channel-EyH7BS8F.js +0 -1
  206. package/web-shell/assets/classDiagram-4FO5ZUOK-CPWvwYMM.js +0 -1
  207. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CPWvwYMM.js +0 -1
  208. package/web-shell/assets/index-CgttHpqB.js +0 -763
  209. package/web-shell/assets/index-sVELoa_9.css +0 -5
  210. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CFqBlFdE.js +0 -1
@@ -11,7 +11,7 @@ import {
11
11
  openQwenAsrRealtimeStream,
12
12
  openVoiceStream,
13
13
  openVoiceStreamWithRetry
14
- } from "./chunk-65P5ZXUE.js";
14
+ } from "./chunk-4XV2MRNK.js";
15
15
  import {
16
16
  SetupGithubError,
17
17
  collectSessionData,
@@ -22,24 +22,25 @@ import {
22
22
  toJson,
23
23
  toJsonl,
24
24
  toMarkdown
25
- } from "./chunk-UOGOM4NJ.js";
25
+ } from "./chunk-AJ3CEJRJ.js";
26
+ import "./chunk-7VCI24VZ.js";
27
+ import "./chunk-LGFAYIKX.js";
26
28
  import "./chunk-54YZOP7P.js";
27
- import "./chunk-OGAC66WF.js";
28
29
  import {
29
30
  createDaemonStatusProvider
30
- } from "./chunk-2BJWUJCW.js";
31
- import "./chunk-HLJMZYTD.js";
31
+ } from "./chunk-7SAH6M3Y.js";
32
+ import "./chunk-2D5Q33PT.js";
32
33
  import "./chunk-KHDZHZMH.js";
33
34
  import {
34
35
  createWorkspaceProvidersStatusProvider
35
- } from "./chunk-XUYYEFCM.js";
36
+ } from "./chunk-27QGW3BK.js";
36
37
  import {
37
38
  getAuthTypeFromEnv,
38
39
  resolveCliGenerationConfig
39
- } from "./chunk-FTEFJT6V.js";
40
+ } from "./chunk-QM4FKX7H.js";
40
41
  import {
41
42
  createWorkspaceSkillsStatusProvider
42
- } from "./chunk-HT553O4R.js";
43
+ } from "./chunk-WRLMLPWI.js";
43
44
  import "./chunk-6IAWPIQ6.js";
44
45
  import {
45
46
  EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
@@ -51,14 +52,14 @@ import {
51
52
  transcribeWorkspaceVoiceAudio,
52
53
  validateWorkspaceVoiceState,
53
54
  voiceSettingsScopeToWire
54
- } from "./chunk-AY7CP32Q.js";
55
+ } from "./chunk-A7UKINBT.js";
55
56
  import {
56
57
  PermissionRulesValidationError,
57
58
  buildPermissionSettings,
58
59
  isPermissionRuleType,
59
60
  normalizePermissionRules,
60
61
  readPermissionRuleSet
61
- } from "./chunk-N7BUPX4V.js";
62
+ } from "./chunk-6GHEZDDX.js";
62
63
  import {
63
64
  assertVoiceBaseUrlNetworkAllowed,
64
65
  isStreamingVoiceModel,
@@ -66,12 +67,12 @@ import {
66
67
  resolveVoiceTranscriptionConfig,
67
68
  sanitizeVoiceErrorMessage,
68
69
  transcribeVoiceAudio
69
- } from "./chunk-IEFMDFCG.js";
70
+ } from "./chunk-WKTLDGD6.js";
70
71
  import {
71
72
  isVoiceEnabled,
72
73
  isVoiceMode,
73
74
  readVoiceModel
74
- } from "./chunk-B2FUQ22Z.js";
75
+ } from "./chunk-ILFQAFWH.js";
75
76
  import "./chunk-E7KNELIZ.js";
76
77
  import {
77
78
  WorkspacePermissionRulesSessionRequiredError,
@@ -134,16 +135,16 @@ import {
134
135
  getSettingDefinition,
135
136
  loadSettings,
136
137
  validateSettingValue
137
- } from "./chunk-INNPK6XG.js";
138
+ } from "./chunk-O6T7PBUM.js";
138
139
  import {
139
140
  SUPPORTED_LANGUAGES
140
- } from "./chunk-VCKMHAEZ.js";
141
+ } from "./chunk-2MJAXDFK.js";
141
142
  import "./chunk-TLRYABYP.js";
142
143
  import "./chunk-4RQIB5UZ.js";
143
144
  import {
144
145
  SessionArtifactValidationError,
145
146
  createAcpSessionBridge
146
- } from "./chunk-R57UD732.js";
147
+ } from "./chunk-SKO6VJHG.js";
147
148
  import "./chunk-P7M4GA57.js";
148
149
  import {
149
150
  BranchWhilePromptActiveError,
@@ -185,18 +186,19 @@ import {
185
186
  SubscriberLimitExceededError
186
187
  } from "./chunk-G7ZG7CA6.js";
187
188
  import "./chunk-VRDMOSQS.js";
188
- import "./chunk-V63Q7BVE.js";
189
+ import "./chunk-GW67O5SO.js";
189
190
  import "./chunk-EXPMGZZV.js";
190
191
  import {
191
192
  STATUS_SCHEMA_VERSION,
192
193
  createIdleWorkspaceMemoryStatus,
193
194
  mapDomainErrorToErrorKind
194
- } from "./chunk-QU6OLW25.js";
195
+ } from "./chunk-7O6DD2ES.js";
195
196
  import "./chunk-HLKG6CZN.js";
196
- import "./chunk-XZ2LJL4O.js";
197
+ import "./chunk-RODQXLGZ.js";
198
+ import "./chunk-43W4YSO6.js";
197
199
  import {
198
200
  getWorkspaceTrustStatus
199
- } from "./chunk-32KIF557.js";
201
+ } from "./chunk-WKBA74DD.js";
200
202
  import {
201
203
  writeStderrLine
202
204
  } from "./chunk-Y6Z2O3WR.js";
@@ -234,14 +236,16 @@ import {
234
236
  parseInstallSource,
235
237
  redactUrlCredentials,
236
238
  shouldShowStep,
239
+ stripTerminalControlSequences,
237
240
  writeWorkspaceContextFile
238
- } from "./chunk-KD4KV6XW.js";
241
+ } from "./chunk-ZWFS7YCB.js";
239
242
  import "./chunk-5P5XGNYH.js";
240
243
  import "./chunk-SKAZWEV5.js";
241
244
  import "./chunk-K5PGHDBN.js";
242
245
  import {
243
- MAX_JOBS
244
- } from "./chunk-FVMWEHWU.js";
246
+ MAX_JOBS,
247
+ nextDurableFireMs
248
+ } from "./chunk-3B26UVCX.js";
245
249
  import "./chunk-W7EEOR7D.js";
246
250
  import "./chunk-42XGFRJS.js";
247
251
  import "./chunk-X2XNQQJI.js";
@@ -252,11 +256,12 @@ import {
252
256
  } from "./chunk-2MPVVENX.js";
253
257
  import "./chunk-ZTQ26VBE.js";
254
258
  import {
259
+ appendCronRun,
255
260
  generateCronTaskId,
261
+ getCronFilePath,
256
262
  readCronTasks,
257
- removeCronTasks,
258
263
  updateCronTasks
259
- } from "./chunk-2NL7ED5Q.js";
264
+ } from "./chunk-FV7425LN.js";
260
265
  import "./chunk-MLZQVCF3.js";
261
266
  import "./chunk-LQ7TMOCE.js";
262
267
  import "./chunk-E5A7LHNN.js";
@@ -283,7 +288,7 @@ import {
283
288
  recordDaemonHttpRequest,
284
289
  recordDaemonHttpResponse,
285
290
  withDaemonRequestSpan
286
- } from "./chunk-IPKM25FZ.js";
291
+ } from "./chunk-N33JAGJ7.js";
287
292
  import "./chunk-E6US47KI.js";
288
293
  import "./chunk-UWCTAVOD.js";
289
294
  import "./chunk-OFEVLU4C.js";
@@ -305,8 +310,8 @@ import "./chunk-AHNJGLFV.js";
305
310
  import "./chunk-22IFUCVR.js";
306
311
  import "./chunk-7LTB54MK.js";
307
312
  import "./chunk-SIUQ3YYX.js";
308
- import "./chunk-2A6XOMBQ.js";
309
- import "./chunk-NCFY7PWS.js";
313
+ import "./chunk-HW4N45EE.js";
314
+ import "./chunk-CCGOFQV3.js";
310
315
  import "./chunk-IRJWHZWU.js";
311
316
  import "./chunk-SYCJMSIJ.js";
312
317
  import "./chunk-55ZMG67I.js";
@@ -4893,6 +4898,67 @@ __name(createSessionOrganizationService, "createSessionOrganizationService");
4893
4898
 
4894
4899
  // packages/cli/src/serve/server/session-archive.ts
4895
4900
  init_esbuild_shims();
4901
+
4902
+ // packages/cli/src/serve/scheduled-task-session-lifecycle.ts
4903
+ init_esbuild_shims();
4904
+ function isBoundTask(task) {
4905
+ return typeof task.sessionId === "string" && task.sessionId.length > 0;
4906
+ }
4907
+ __name(isBoundTask, "isBoundTask");
4908
+ async function disableTasksForSessions(projectRoot, sessionIds) {
4909
+ if (sessionIds.length === 0) return;
4910
+ const targets = new Set(sessionIds);
4911
+ await updateCronTasks(projectRoot, (tasks) => {
4912
+ let changed = false;
4913
+ const next = tasks.map((task) => {
4914
+ if (isBoundTask(task) && targets.has(task.sessionId) && task.enabled !== false) {
4915
+ changed = true;
4916
+ return { ...task, enabled: false, disabledByArchive: true };
4917
+ }
4918
+ return task;
4919
+ });
4920
+ return changed ? next : tasks;
4921
+ });
4922
+ }
4923
+ __name(disableTasksForSessions, "disableTasksForSessions");
4924
+ async function enableTasksForSessions(projectRoot, sessionIds, now = Date.now()) {
4925
+ if (sessionIds.length === 0) return;
4926
+ const targets = new Set(sessionIds);
4927
+ await updateCronTasks(projectRoot, (tasks) => {
4928
+ let changed = false;
4929
+ const next = tasks.map((task) => {
4930
+ if (isBoundTask(task) && targets.has(task.sessionId) && task.enabled === false && task.disabledByArchive === true) {
4931
+ changed = true;
4932
+ const resumed = { ...task, enabled: true };
4933
+ delete resumed.disabledByArchive;
4934
+ const minute = now - now % 6e4;
4935
+ if (resumed.recurring) {
4936
+ resumed.lastFiredAt = minute;
4937
+ } else {
4938
+ resumed.createdAt = now;
4939
+ resumed.lastFiredAt = minute;
4940
+ }
4941
+ return resumed;
4942
+ }
4943
+ return task;
4944
+ });
4945
+ return changed ? next : tasks;
4946
+ });
4947
+ }
4948
+ __name(enableTasksForSessions, "enableTasksForSessions");
4949
+ async function removeTasksForSessions(projectRoot, sessionIds) {
4950
+ if (sessionIds.length === 0) return;
4951
+ const targets = new Set(sessionIds);
4952
+ await updateCronTasks(projectRoot, (tasks) => {
4953
+ const next = tasks.filter(
4954
+ (task) => !isBoundTask(task) || !targets.has(task.sessionId)
4955
+ );
4956
+ return next.length === tasks.length ? tasks : next;
4957
+ });
4958
+ }
4959
+ __name(removeTasksForSessions, "removeTasksForSessions");
4960
+
4961
+ // packages/cli/src/serve/server/session-archive.ts
4896
4962
  var SessionArchiveCoordinator = class {
4897
4963
  static {
4898
4964
  __name(this, "SessionArchiveCoordinator");
@@ -4995,6 +5061,13 @@ async function deleteDaemonSessions(params) {
4995
5061
  }
4996
5062
  })
4997
5063
  );
5064
+ await removeTasksForSessions(service.getProjectRoot(), removed).catch(
5065
+ (err) => {
5066
+ logSessionArchiveWarning(
5067
+ `removeTasksForSessions failed for [${removed.join(", ")}]: ${err instanceof Error ? err.message : String(err)}`
5068
+ );
5069
+ }
5070
+ );
4998
5071
  return { removed, notFound, errors: [...closeErrors, ...removeErrors] };
4999
5072
  }
5000
5073
  __name(deleteDaemonSessions, "deleteDaemonSessions");
@@ -5151,6 +5224,13 @@ async function archiveDaemonSessions(params) {
5151
5224
  notFound,
5152
5225
  errors
5153
5226
  });
5227
+ await disableTasksForSessions(service.getProjectRoot(), archived).catch(
5228
+ (err) => {
5229
+ logSessionArchiveWarning(
5230
+ `disableTasksForSessions failed for [${archived.join(", ")}]: ${err instanceof Error ? err.message : String(err)} \u2014 bound tasks may keep firing until reconciled`
5231
+ );
5232
+ }
5233
+ );
5154
5234
  return { archived, alreadyArchived, notFound, errors };
5155
5235
  }
5156
5236
  __name(archiveDaemonSessions, "archiveDaemonSessions");
@@ -5197,6 +5277,17 @@ async function unarchiveDaemonSessions(params) {
5197
5277
  notFound,
5198
5278
  errors
5199
5279
  });
5280
+ const resumeSessionIds = [.../* @__PURE__ */ new Set([...unarchived, ...alreadyActive])];
5281
+ try {
5282
+ await enableTasksForSessions(service.getProjectRoot(), resumeSessionIds);
5283
+ } catch (err) {
5284
+ logSessionArchiveWarning(
5285
+ `enableTasksForSessions failed for [${resumeSessionIds.join(", ")}]: ${err instanceof Error ? err.message : String(err)}`
5286
+ );
5287
+ for (const sessionId of resumeSessionIds) {
5288
+ errors.push({ sessionId, error: err });
5289
+ }
5290
+ }
5200
5291
  return { unarchived, alreadyActive, notFound, errors };
5201
5292
  }
5202
5293
  __name(unarchiveDaemonSessions, "unarchiveDaemonSessions");
@@ -9798,10 +9889,10 @@ function isCdpInboundFrame(frame) {
9798
9889
  }
9799
9890
  __name(isCdpInboundFrame, "isCdpInboundFrame");
9800
9891
  var CdpReverseLink = class {
9801
- constructor(sendToExtension, commandTimeoutMs = DEFAULT_COMMAND_TIMEOUT_MS, log) {
9892
+ constructor(sendToExtension, commandTimeoutMs = DEFAULT_COMMAND_TIMEOUT_MS, log2) {
9802
9893
  this.sendToExtension = sendToExtension;
9803
9894
  this.commandTimeoutMs = commandTimeoutMs;
9804
- this.log = log;
9895
+ this.log = log2;
9805
9896
  }
9806
9897
  static {
9807
9898
  __name(this, "CdpReverseLink");
@@ -10243,10 +10334,10 @@ var CdpBrowserEmulator = class {
10243
10334
  var CLOSE_NO_BRIDGE = 1011;
10244
10335
  var CLOSE_NORMAL = 1e3;
10245
10336
  var CDP_WS_HEARTBEAT_MS = 15e3;
10246
- function attachCdpClient(ws, registry, log) {
10337
+ function attachCdpClient(ws, registry, log2) {
10247
10338
  const bridge = registry.getActive();
10248
10339
  if (!bridge) {
10249
- log("qwen serve: /cdp rejected \u2014 no extension bridge connected");
10340
+ log2("qwen serve: /cdp rejected \u2014 no extension bridge connected");
10250
10341
  try {
10251
10342
  ws.close(
10252
10343
  CLOSE_NO_BRIDGE,
@@ -10257,7 +10348,7 @@ function attachCdpClient(ws, registry, log) {
10257
10348
  return;
10258
10349
  }
10259
10350
  if (bridge.cdpBound) {
10260
- log("qwen serve: /cdp rejected \u2014 a puppeteer client is already bound");
10351
+ log2("qwen serve: /cdp rejected \u2014 a puppeteer client is already bound");
10261
10352
  try {
10262
10353
  ws.close(CLOSE_NO_BRIDGE, "A CDP client is already connected");
10263
10354
  } catch {
@@ -10268,19 +10359,19 @@ function attachCdpClient(ws, registry, log) {
10268
10359
  const link = new CdpReverseLink(
10269
10360
  (frame) => bridge.send(frame),
10270
10361
  void 0,
10271
- log
10362
+ log2
10272
10363
  );
10273
10364
  const emulator = new CdpBrowserEmulator({
10274
10365
  reply: /* @__PURE__ */ __name((frame) => {
10275
10366
  safeWsSend(ws, JSON.stringify(frame), "CDP");
10276
10367
  }, "reply"),
10277
10368
  forwardToTab: link.forwardToTab,
10278
- log
10369
+ log: log2
10279
10370
  });
10280
10371
  link.bindEmulator(emulator);
10281
10372
  bridge.routeInbound = (frame) => link.handleInbound(frame);
10282
10373
  link.onDetach = (reason) => {
10283
- log(`qwen serve: /cdp tab detached (${reason}); closing puppeteer socket`);
10374
+ log2(`qwen serve: /cdp tab detached (${reason}); closing puppeteer socket`);
10284
10375
  try {
10285
10376
  ws.close(CLOSE_NORMAL, `tab detached: ${reason}`);
10286
10377
  } catch {
@@ -10291,7 +10382,7 @@ function attachCdpClient(ws, registry, log) {
10291
10382
  const heartbeat = setInterval(() => {
10292
10383
  if (disposed) return;
10293
10384
  if (!heartbeatAlive) {
10294
- log("qwen serve: /cdp heartbeat missed; closing puppeteer socket");
10385
+ log2("qwen serve: /cdp heartbeat missed; closing puppeteer socket");
10295
10386
  dispose("puppeteer /cdp heartbeat missed");
10296
10387
  try {
10297
10388
  ws.close(CLOSE_NORMAL, "cdp heartbeat missed");
@@ -10303,7 +10394,7 @@ function attachCdpClient(ws, registry, log) {
10303
10394
  try {
10304
10395
  ws.ping();
10305
10396
  } catch (err) {
10306
- log(
10397
+ log2(
10307
10398
  `qwen serve: /cdp heartbeat ping failed: ${err instanceof Error ? err.message : String(err)}`
10308
10399
  );
10309
10400
  dispose("puppeteer /cdp heartbeat ping failed");
@@ -10321,11 +10412,11 @@ function attachCdpClient(ws, registry, log) {
10321
10412
  if (notifyExtension && registry.getActive() === bridge) {
10322
10413
  try {
10323
10414
  bridge.send({ type: CDP_FRAME_TYPES.release });
10324
- log(
10415
+ log2(
10325
10416
  `qwen serve: /cdp sent release to extension (puppeteer disconnected: ${reason})`
10326
10417
  );
10327
10418
  } catch (err) {
10328
- log(
10419
+ log2(
10329
10420
  `qwen serve: /cdp release send failed: ${err instanceof Error ? err.message : String(err)}`
10330
10421
  );
10331
10422
  }
@@ -10338,7 +10429,7 @@ function attachCdpClient(ws, registry, log) {
10338
10429
  }
10339
10430
  }, "dispose");
10340
10431
  link.onAttachFailure = (reason) => {
10341
- log(`qwen serve: /cdp attach failed (${reason}); closing puppeteer socket`);
10432
+ log2(`qwen serve: /cdp attach failed (${reason}); closing puppeteer socket`);
10342
10433
  dispose(`cdp_attach failed: ${reason}`, false);
10343
10434
  try {
10344
10435
  ws.close(CLOSE_NO_BRIDGE, "cdp attach failed");
@@ -10349,7 +10440,7 @@ function attachCdpClient(ws, registry, log) {
10349
10440
  heartbeatAlive = true;
10350
10441
  });
10351
10442
  bridge.onExtensionGone = () => {
10352
- log("qwen serve: extension /acp dropped; closing puppeteer /cdp socket");
10443
+ log2("qwen serve: extension /acp dropped; closing puppeteer /cdp socket");
10353
10444
  dispose("extension /acp disconnected", false);
10354
10445
  try {
10355
10446
  ws.close(CLOSE_NORMAL, "extension disconnected");
@@ -10365,19 +10456,19 @@ function attachCdpClient(ws, registry, log) {
10365
10456
  return;
10366
10457
  }
10367
10458
  void emulator.handleFromClient(frame).catch((err) => {
10368
- log(
10459
+ log2(
10369
10460
  `qwen serve: /cdp emulator error: ${err instanceof Error ? err.message : String(err)}`
10370
10461
  );
10371
10462
  });
10372
10463
  });
10373
10464
  ws.on("close", () => dispose("puppeteer /cdp socket closed"));
10374
10465
  ws.on("error", (err) => {
10375
- log(
10466
+ log2(
10376
10467
  `qwen serve: /cdp WS error: ${err instanceof Error ? err.message : String(err)}`
10377
10468
  );
10378
10469
  dispose("puppeteer /cdp socket error");
10379
10470
  });
10380
- log("qwen serve: /cdp puppeteer client bound to extension bridge");
10471
+ log2("qwen serve: /cdp puppeteer client bound to extension bridge");
10381
10472
  }
10382
10473
  __name(attachCdpClient, "attachCdpClient");
10383
10474
 
@@ -10516,7 +10607,7 @@ var MAX_INFLIGHT_MCP_DISPATCH = 8;
10516
10607
  function mountAcpHttp(app, bridge, opts) {
10517
10608
  const enabled = opts.enabled ?? process.env["QWEN_SERVE_ACP_HTTP"] !== "0";
10518
10609
  if (!enabled) return void 0;
10519
- const path13 = opts.path ?? "/acp";
10610
+ const path14 = opts.path ?? "/acp";
10520
10611
  const dispatcherRef = {};
10521
10612
  const registry = new ConnectionRegistry(
10522
10613
  (req, clientId) => {
@@ -10653,7 +10744,7 @@ function mountAcpHttp(app, bridge, opts) {
10653
10744
  opts.archiveCoordinator ?? new SessionArchiveCoordinator()
10654
10745
  );
10655
10746
  dispatcherRef.current = dispatcher;
10656
- app.post(path13, async (req, res) => {
10747
+ app.post(path14, async (req, res) => {
10657
10748
  const ct = req.headers["content-type"];
10658
10749
  if (!ct || !ct.startsWith("application/json")) {
10659
10750
  res.status(415).json({ error: "Content-Type must be application/json" });
@@ -10757,7 +10848,7 @@ function mountAcpHttp(app, bridge, opts) {
10757
10848
  );
10758
10849
  });
10759
10850
  });
10760
- app.get(path13, (req, res) => {
10851
+ app.get(path14, (req, res) => {
10761
10852
  const accept = req.headers["accept"] ?? "";
10762
10853
  if (!accept.includes("text/event-stream")) {
10763
10854
  res.status(406).json({ error: "Accept header must include text/event-stream" });
@@ -10843,7 +10934,7 @@ function mountAcpHttp(app, bridge, opts) {
10843
10934
  onPumpSettled();
10844
10935
  });
10845
10936
  });
10846
- app.delete(path13, (req, res) => {
10937
+ app.delete(path14, (req, res) => {
10847
10938
  const connectionId = headerOf(req, ACP_CONNECTION_HEADER);
10848
10939
  if (!connectionId) {
10849
10940
  res.status(400).json({ error: "Missing Acp-Connection-Id" });
@@ -10906,7 +10997,7 @@ function mountAcpHttp(app, bridge, opts) {
10906
10997
  const extraRoute = opts.extraWsRoutes?.find(
10907
10998
  (route) => route.path === url.pathname
10908
10999
  );
10909
- if (url.pathname !== path13 && !isCdpPath && !extraRoute) {
11000
+ if (url.pathname !== path14 && !isCdpPath && !extraRoute) {
10910
11001
  logReject(`unknown-path ${url.pathname}`);
10911
11002
  socket.destroy();
10912
11003
  return;
@@ -11303,7 +11394,7 @@ function mountAcpHttp(app, bridge, opts) {
11303
11394
  });
11304
11395
  }, "upgradeListener");
11305
11396
  httpServer.on("upgrade", upgradeListener);
11306
- writeStderrLine(`qwen serve: /acp WebSocket transport enabled on ${path13}`);
11397
+ writeStderrLine(`qwen serve: /acp WebSocket transport enabled on ${path14}`);
11307
11398
  }
11308
11399
  __name(setupWebSocket, "setupWebSocket");
11309
11400
  return {
@@ -16084,6 +16175,24 @@ var MAX_SCHEDULED_TASKS = MAX_JOBS;
16084
16175
  var MAX_PROMPT_LENGTH = 1e5;
16085
16176
  var MAX_NAME_LENGTH2 = 200;
16086
16177
  var MAX_CRON_LENGTH = 200;
16178
+ var MAX_SESSION_NAME_LENGTH = 60;
16179
+ function scheduledTaskSessionName(label) {
16180
+ const cleaned = stripTerminalControlSequences(label).replace(/[\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/g, "").trim().replace(/\s+/g, " ");
16181
+ let short = cleaned;
16182
+ if (cleaned.length > MAX_SESSION_NAME_LENGTH) {
16183
+ let cut = MAX_SESSION_NAME_LENGTH - 1;
16184
+ const boundary = cleaned.charCodeAt(cut - 1);
16185
+ if (boundary >= 55296 && boundary <= 56319) cut -= 1;
16186
+ short = `${cleaned.slice(0, cut)}\u2026`;
16187
+ }
16188
+ return `\u23F0 ${short}`;
16189
+ }
16190
+ __name(scheduledTaskSessionName, "scheduledTaskSessionName");
16191
+ function computeNextRunAt(task) {
16192
+ if (task.enabled === false) return null;
16193
+ return nextDurableFireMs(task);
16194
+ }
16195
+ __name(computeNextRunAt, "computeNextRunAt");
16087
16196
  function toView(task) {
16088
16197
  return {
16089
16198
  id: task.id,
@@ -16094,7 +16203,14 @@ function toView(task) {
16094
16203
  // Absent enabled defaults to enabled — tool-created tasks never write it.
16095
16204
  enabled: task.enabled !== false,
16096
16205
  createdAt: task.createdAt,
16097
- lastFiredAt: task.lastFiredAt
16206
+ lastFiredAt: task.lastFiredAt,
16207
+ nextRunAt: computeNextRunAt(task),
16208
+ // The task's bound session (its run-history transcript), or null for an
16209
+ // unbound tool-created/legacy task.
16210
+ sessionId: typeof task.sessionId === "string" && task.sessionId.length > 0 ? task.sessionId : null,
16211
+ // Absent runs (tool-created / never-fired) normalizes to [] so the client
16212
+ // never special-cases undefined.
16213
+ runs: Array.isArray(task.runs) ? task.runs : []
16098
16214
  };
16099
16215
  }
16100
16216
  __name(toView, "toView");
@@ -16108,8 +16224,26 @@ function validateCron(cron) {
16108
16224
  }
16109
16225
  }
16110
16226
  __name(validateCron, "validateCron");
16227
+ function canonicalCron(cron) {
16228
+ try {
16229
+ const f = parseCron(cron);
16230
+ const s = /* @__PURE__ */ __name((set) => [...set].sort((a, b) => a - b).join(","), "s");
16231
+ return [
16232
+ s(f.minute),
16233
+ s(f.hour),
16234
+ s(f.dayOfMonth),
16235
+ s(f.month),
16236
+ s(f.dayOfWeek),
16237
+ f.domIsWild ? "W" : "",
16238
+ f.dowIsWild ? "W" : ""
16239
+ ].join("|");
16240
+ } catch {
16241
+ return null;
16242
+ }
16243
+ }
16244
+ __name(canonicalCron, "canonicalCron");
16111
16245
  function registerScheduledTasksRoutes(app, deps) {
16112
- const { boundWorkspace, mutate, safeBody: safeBody2 } = deps;
16246
+ const { boundWorkspace, mutate, safeBody: safeBody2, bridge } = deps;
16113
16247
  app.get("/scheduled-tasks", async (_req, res) => {
16114
16248
  try {
16115
16249
  const tasks = await readCronTasks(boundWorkspace);
@@ -16182,6 +16316,41 @@ function registerScheduledTasksRoutes(app, deps) {
16182
16316
  }
16183
16317
  const recurring = body["recurring"] !== false;
16184
16318
  const enabled = body["enabled"] !== false;
16319
+ let boundSessionId;
16320
+ if (bridge) {
16321
+ try {
16322
+ if ((await readCronTasks(boundWorkspace)).length >= MAX_SCHEDULED_TASKS) {
16323
+ res.status(409).json({
16324
+ error: `Maximum number of scheduled tasks (${MAX_SCHEDULED_TASKS}) reached`,
16325
+ code: "max_tasks_reached"
16326
+ });
16327
+ return;
16328
+ }
16329
+ } catch {
16330
+ }
16331
+ try {
16332
+ const session = await bridge.spawnOrAttach({
16333
+ workspaceCwd: boundWorkspace,
16334
+ sessionScope: "thread"
16335
+ });
16336
+ boundSessionId = session.sessionId;
16337
+ try {
16338
+ bridge.updateSessionMetadata(boundSessionId, {
16339
+ displayName: scheduledTaskSessionName(nameResult.value ?? prompt)
16340
+ });
16341
+ } catch {
16342
+ }
16343
+ } catch (err) {
16344
+ writeStderrLine(
16345
+ `qwen serve: POST /scheduled-tasks failed to create the task's session: ${err instanceof Error ? err.message : String(err)}`
16346
+ );
16347
+ res.status(500).json({
16348
+ error: "Failed to create the task's session",
16349
+ code: "scheduled_tasks_session_failed"
16350
+ });
16351
+ return;
16352
+ }
16353
+ }
16185
16354
  const now = Date.now();
16186
16355
  const task = {
16187
16356
  id: generateCronTaskId(),
@@ -16193,8 +16362,17 @@ function registerScheduledTasksRoutes(app, deps) {
16193
16362
  // minute the task was created — same guard cronScheduler.create uses.
16194
16363
  lastFiredAt: now - now % 6e4,
16195
16364
  enabled,
16365
+ ...boundSessionId !== void 0 ? { sessionId: boundSessionId } : {},
16196
16366
  ...nameResult.value !== void 0 ? { name: nameResult.value } : {}
16197
16367
  };
16368
+ const rollbackSession = /* @__PURE__ */ __name(async () => {
16369
+ if (boundSessionId !== void 0 && bridge) {
16370
+ await bridge.closeSession(boundSessionId).catch(() => {
16371
+ });
16372
+ await new SessionService(boundWorkspace).removeSession(boundSessionId).catch(() => {
16373
+ });
16374
+ }
16375
+ }, "rollbackSession");
16198
16376
  let overCap = false;
16199
16377
  try {
16200
16378
  await updateCronTasks(boundWorkspace, (tasks) => {
@@ -16205,6 +16383,7 @@ function registerScheduledTasksRoutes(app, deps) {
16205
16383
  return [...tasks, task];
16206
16384
  });
16207
16385
  } catch (err) {
16386
+ await rollbackSession();
16208
16387
  writeStderrLine(
16209
16388
  `qwen serve: POST /scheduled-tasks failed: ${err instanceof Error ? err.message : String(err)}`
16210
16389
  );
@@ -16215,6 +16394,7 @@ function registerScheduledTasksRoutes(app, deps) {
16215
16394
  return;
16216
16395
  }
16217
16396
  if (overCap) {
16397
+ await rollbackSession();
16218
16398
  res.status(409).json({
16219
16399
  error: `Maximum number of scheduled tasks (${MAX_SCHEDULED_TASKS}) reached`,
16220
16400
  code: "max_tasks_reached"
@@ -16300,17 +16480,32 @@ function registerScheduledTasksRoutes(app, deps) {
16300
16480
  }
16301
16481
  let found = false;
16302
16482
  let updated;
16483
+ let blockedByArchive = false;
16303
16484
  try {
16304
16485
  await updateCronTasks(boundWorkspace, (tasks) => {
16305
16486
  const idx = tasks.findIndex((t) => t.id === id);
16306
16487
  if (idx === -1) return tasks;
16307
16488
  found = true;
16308
16489
  const current = tasks[idx];
16490
+ if (patch.enabled === true && current.disabledByArchive === true) {
16491
+ blockedByArchive = true;
16492
+ return tasks;
16493
+ }
16309
16494
  const next = { ...current, ...patch };
16310
16495
  if (clearName) delete next.name;
16311
- if (current.enabled === false && patch.enabled === true && next.recurring) {
16496
+ const justReEnabled = current.enabled === false && patch.enabled === true;
16497
+ const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
16498
+ const becameRecurring = patch.recurring === true && current.recurring !== true;
16499
+ const becameOneShot = patch.recurring === false && current.recurring !== false;
16500
+ {
16312
16501
  const now = Date.now();
16313
- next.lastFiredAt = now - now % 6e4;
16502
+ const minute = now - now % 6e4;
16503
+ if (next.recurring && (justReEnabled || cronChanged || becameRecurring)) {
16504
+ next.lastFiredAt = minute;
16505
+ } else if (!next.recurring && (justReEnabled || cronChanged || becameOneShot)) {
16506
+ next.createdAt = now;
16507
+ next.lastFiredAt = minute;
16508
+ }
16314
16509
  }
16315
16510
  updated = next;
16316
16511
  return tasks.map((t, i) => i === idx ? next : t);
@@ -16325,10 +16520,26 @@ function registerScheduledTasksRoutes(app, deps) {
16325
16520
  });
16326
16521
  return;
16327
16522
  }
16523
+ if (blockedByArchive) {
16524
+ res.status(409).json({
16525
+ error: "This task was disabled by archiving its session; unarchive the session to re-enable it.",
16526
+ code: "task_session_archived"
16527
+ });
16528
+ return;
16529
+ }
16328
16530
  if (!found || !updated) {
16329
16531
  res.status(404).json({ error: "Task not found", code: "task_not_found" });
16330
16532
  return;
16331
16533
  }
16534
+ const effectiveLabelChanged = patch.name !== void 0 || clearName || patch.prompt !== void 0 && updated.name === void 0;
16535
+ if (bridge && updated.sessionId && effectiveLabelChanged) {
16536
+ try {
16537
+ bridge.updateSessionMetadata(updated.sessionId, {
16538
+ displayName: scheduledTaskSessionName(updated.name ?? updated.prompt)
16539
+ });
16540
+ } catch {
16541
+ }
16542
+ }
16332
16543
  res.status(200).json(toView(updated));
16333
16544
  });
16334
16545
  app.delete("/scheduled-tasks/:id", mutate(), async (req, res) => {
@@ -16337,9 +16548,19 @@ function registerScheduledTasksRoutes(app, deps) {
16337
16548
  res.status(400).json({ error: "Task id is required", code: "invalid_id" });
16338
16549
  return;
16339
16550
  }
16340
- let removed;
16551
+ let boundSessionId;
16552
+ let removed = false;
16341
16553
  try {
16342
- removed = await removeCronTasks(boundWorkspace, [id]);
16554
+ await updateCronTasks(boundWorkspace, (tasks) => {
16555
+ const idx = tasks.findIndex((t) => t.id === id);
16556
+ if (idx === -1) return tasks;
16557
+ const match = tasks[idx].sessionId;
16558
+ if (typeof match === "string" && match.length > 0) {
16559
+ boundSessionId = match;
16560
+ }
16561
+ removed = true;
16562
+ return tasks.filter((_, i) => i !== idx);
16563
+ });
16343
16564
  } catch (err) {
16344
16565
  writeStderrLine(
16345
16566
  `qwen serve: DELETE /scheduled-tasks/${id} failed: ${err instanceof Error ? err.message : String(err)}`
@@ -16350,12 +16571,76 @@ function registerScheduledTasksRoutes(app, deps) {
16350
16571
  });
16351
16572
  return;
16352
16573
  }
16353
- if (removed === 0) {
16574
+ if (!removed) {
16354
16575
  res.status(404).json({ error: "Task not found", code: "task_not_found" });
16355
16576
  return;
16356
16577
  }
16578
+ if (boundSessionId && bridge) {
16579
+ await bridge.closeSession(boundSessionId).catch(() => {
16580
+ });
16581
+ }
16357
16582
  res.status(200).json({ deleted: true, id });
16358
16583
  });
16584
+ app.post("/scheduled-tasks/:id/run", mutate(), async (req, res) => {
16585
+ const id = typeof req.params["id"] === "string" ? req.params["id"] : "";
16586
+ if (id.length === 0) {
16587
+ res.status(400).json({ error: "Task id is required", code: "invalid_id" });
16588
+ return;
16589
+ }
16590
+ const now = Date.now();
16591
+ let found = false;
16592
+ let blockedDisabled = false;
16593
+ let updated;
16594
+ try {
16595
+ await updateCronTasks(boundWorkspace, (tasks) => {
16596
+ const idx = tasks.findIndex((t) => t.id === id);
16597
+ if (idx === -1) return tasks;
16598
+ found = true;
16599
+ const current = tasks[idx];
16600
+ if (current.enabled === false) {
16601
+ blockedDisabled = true;
16602
+ return tasks;
16603
+ }
16604
+ const next = {
16605
+ ...current,
16606
+ lastFiredAt: now,
16607
+ runs: appendCronRun(current.runs, {
16608
+ at: now,
16609
+ kind: "manual",
16610
+ ...current.sessionId ? { sessionId: current.sessionId } : {}
16611
+ })
16612
+ };
16613
+ updated = next;
16614
+ if (!current.recurring) {
16615
+ return tasks.filter((_, i) => i !== idx);
16616
+ }
16617
+ return tasks.map((t, i) => i === idx ? next : t);
16618
+ });
16619
+ } catch (err) {
16620
+ writeStderrLine(
16621
+ `qwen serve: POST /scheduled-tasks/${id}/run failed: ${err instanceof Error ? err.message : String(err)}`
16622
+ );
16623
+ res.status(500).json({
16624
+ error: "Failed to record scheduled task run",
16625
+ code: "scheduled_tasks_write_failed"
16626
+ });
16627
+ return;
16628
+ }
16629
+ if (blockedDisabled) {
16630
+ res.status(409).json({
16631
+ error: "Cannot run a disabled task; enable it first (unarchive its session if it was archived).",
16632
+ code: "task_disabled"
16633
+ });
16634
+ return;
16635
+ }
16636
+ if (!found || !updated) {
16637
+ res.status(404).json({ error: "Task not found", code: "task_not_found" });
16638
+ return;
16639
+ }
16640
+ const view = toView(updated);
16641
+ if (!updated.recurring) view.nextRunAt = null;
16642
+ res.status(200).json(view);
16643
+ });
16359
16644
  }
16360
16645
  __name(registerScheduledTasksRoutes, "registerScheduledTasksRoutes");
16361
16646
  function parseNameField(raw) {
@@ -16430,6 +16715,320 @@ function registerUsageStatsRoutes(app, deps = {}) {
16430
16715
  }
16431
16716
  __name(registerUsageStatsRoutes, "registerUsageStatsRoutes");
16432
16717
 
16718
+ // packages/cli/src/serve/scheduled-task-keepalive.ts
16719
+ init_esbuild_shims();
16720
+ import * as fsSync from "node:fs";
16721
+ import * as path11 from "node:path";
16722
+ var log = createDebugLogger("SCHED_KEEPALIVE");
16723
+ function collectBoundSessionIds(tasks) {
16724
+ const seen = /* @__PURE__ */ new Set();
16725
+ const ids = [];
16726
+ for (const task of tasks) {
16727
+ const sessionId = task.sessionId;
16728
+ if (task.enabled === false || // disabled (e.g. archived) — let it be reaped
16729
+ typeof sessionId !== "string" || sessionId.length === 0 || seen.has(sessionId)) {
16730
+ continue;
16731
+ }
16732
+ seen.add(sessionId);
16733
+ ids.push(sessionId);
16734
+ }
16735
+ return ids;
16736
+ }
16737
+ __name(collectBoundSessionIds, "collectBoundSessionIds");
16738
+ var KEEPALIVE_REVIVE_TIMEOUT_MS = 3e4;
16739
+ var KEEPALIVE_SPAWN_TIMEOUT_MS = 3e4;
16740
+ var MAX_REVIVE_BACKOFF_MS = 30 * 6e4;
16741
+ async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawnTimeoutMs, binding) {
16742
+ const unbound = tasks.filter(
16743
+ (t) => !t.sessionId && t.enabled !== false && !binding.has(t.id)
16744
+ );
16745
+ const needsName = tasks.filter(
16746
+ (t) => t.sessionId && t.enabled !== false && !renamed.has(t.sessionId)
16747
+ );
16748
+ for (const task of unbound) {
16749
+ let spawnedSessionId;
16750
+ try {
16751
+ binding.add(task.id);
16752
+ const rawSpawn = bridge.spawnOrAttach({
16753
+ workspaceCwd: boundWorkspace,
16754
+ sessionScope: "thread"
16755
+ });
16756
+ let timedOut = false;
16757
+ rawSpawn.then(({ sessionId: sessionId2 }) => {
16758
+ if (timedOut) {
16759
+ log.debug(
16760
+ "keepalive: late spawn resolved, cleaning up",
16761
+ task.id,
16762
+ sessionId2
16763
+ );
16764
+ bridge.closeSession(sessionId2).catch(() => {
16765
+ });
16766
+ new SessionService(boundWorkspace).removeSession(sessionId2).catch(() => {
16767
+ });
16768
+ }
16769
+ }).catch(() => {
16770
+ }).finally(() => {
16771
+ binding.delete(task.id);
16772
+ });
16773
+ const { sessionId } = await withTimeout(
16774
+ rawSpawn,
16775
+ spawnTimeoutMs,
16776
+ `spawnOrAttach(${task.id})`
16777
+ ).catch((err) => {
16778
+ timedOut = true;
16779
+ throw err;
16780
+ });
16781
+ spawnedSessionId = sessionId;
16782
+ try {
16783
+ bridge.updateSessionMetadata(sessionId, {
16784
+ displayName: scheduledTaskSessionName(task.prompt)
16785
+ });
16786
+ renamed.add(sessionId);
16787
+ } catch {
16788
+ }
16789
+ let matched = false;
16790
+ await updateCronTasks(boundWorkspace, (list) => {
16791
+ if (!list.some(
16792
+ (t) => t.id === task.id && !t.sessionId && t.enabled !== false
16793
+ )) {
16794
+ return list;
16795
+ }
16796
+ const result = list.map(
16797
+ (t) => t.id === task.id && !t.sessionId && t.enabled !== false ? { ...t, sessionId } : t
16798
+ );
16799
+ matched = true;
16800
+ return result;
16801
+ });
16802
+ if (!matched) {
16803
+ throw new Error(`task ${task.id} no longer on disk`);
16804
+ }
16805
+ log.debug(
16806
+ "keepalive: bound task",
16807
+ task.id,
16808
+ "to dedicated session",
16809
+ sessionId
16810
+ );
16811
+ } catch (err) {
16812
+ log.debug("keepalive: failed to bind task", task.id, err);
16813
+ if (spawnedSessionId !== void 0) {
16814
+ await bridge.closeSession(spawnedSessionId).catch(() => {
16815
+ });
16816
+ await new SessionService(boundWorkspace).removeSession(spawnedSessionId).catch(() => {
16817
+ });
16818
+ }
16819
+ }
16820
+ }
16821
+ for (const task of needsName) {
16822
+ const sessionId = task.sessionId;
16823
+ try {
16824
+ bridge.updateSessionMetadata(sessionId, {
16825
+ displayName: scheduledTaskSessionName(task.prompt)
16826
+ });
16827
+ renamed.add(sessionId);
16828
+ } catch (err) {
16829
+ log.debug("keepalive: failed to name session", sessionId, err);
16830
+ }
16831
+ }
16832
+ }
16833
+ __name(bindAndNameSessions, "bindAndNameSessions");
16834
+ function startScheduledTaskKeepalive(opts) {
16835
+ const { bridge, boundWorkspace, intervalMs } = opts;
16836
+ const reviveTimeoutMs = opts.reviveTimeoutMs ?? KEEPALIVE_REVIVE_TIMEOUT_MS;
16837
+ const spawnTimeoutMs = opts.spawnTimeoutMs ?? KEEPALIVE_SPAWN_TIMEOUT_MS;
16838
+ const reviveState = /* @__PURE__ */ new Map();
16839
+ const reviving = /* @__PURE__ */ new Set();
16840
+ const binding = /* @__PURE__ */ new Set();
16841
+ const renamed = /* @__PURE__ */ new Set();
16842
+ const tick = /* @__PURE__ */ __name(async () => {
16843
+ let tasks;
16844
+ try {
16845
+ tasks = await readCronTasks(boundWorkspace);
16846
+ } catch (err) {
16847
+ log.debug("keepalive: readCronTasks failed, skipping this pass", err);
16848
+ return;
16849
+ }
16850
+ for (const sessionId of collectBoundSessionIds(tasks)) {
16851
+ try {
16852
+ bridge.recordHeartbeat(sessionId);
16853
+ reviveState.delete(sessionId);
16854
+ } catch (err) {
16855
+ const state = reviveState.get(sessionId);
16856
+ if (reviving.has(sessionId)) {
16857
+ continue;
16858
+ }
16859
+ if (state && Date.now() < state.nextAttemptAt) {
16860
+ continue;
16861
+ }
16862
+ log.debug("keepalive: recordHeartbeat failed for", sessionId, err);
16863
+ const load = bridge.loadSession({
16864
+ sessionId,
16865
+ workspaceCwd: boundWorkspace,
16866
+ historyReplay: "response"
16867
+ });
16868
+ reviving.add(sessionId);
16869
+ void load.catch(() => {
16870
+ }).finally(() => {
16871
+ reviving.delete(sessionId);
16872
+ });
16873
+ try {
16874
+ await withTimeout(load, reviveTimeoutMs, `loadSession(${sessionId})`);
16875
+ log.debug("keepalive: revived non-resident session", sessionId);
16876
+ reviveState.delete(sessionId);
16877
+ } catch (loadErr) {
16878
+ const failures = (state?.failures ?? 0) + 1;
16879
+ const backoff = Math.min(
16880
+ intervalMs * 2 ** Math.min(failures - 1, 6),
16881
+ MAX_REVIVE_BACKOFF_MS
16882
+ );
16883
+ reviveState.set(sessionId, {
16884
+ failures,
16885
+ nextAttemptAt: Date.now() + backoff
16886
+ });
16887
+ log.debug(
16888
+ "keepalive: failed to revive session",
16889
+ sessionId,
16890
+ `(failure ${failures}, next retry in ${backoff}ms)`,
16891
+ loadErr
16892
+ );
16893
+ }
16894
+ }
16895
+ }
16896
+ if (reviveState.size > 0 || renamed.size > 0) {
16897
+ const live = new Set(tasks.map((t) => t.sessionId));
16898
+ for (const id of reviveState.keys()) {
16899
+ if (!live.has(id)) reviveState.delete(id);
16900
+ }
16901
+ for (const id of renamed) {
16902
+ if (!live.has(id)) renamed.delete(id);
16903
+ }
16904
+ }
16905
+ await bindAndNameSessions(
16906
+ bridge,
16907
+ boundWorkspace,
16908
+ tasks,
16909
+ renamed,
16910
+ spawnTimeoutMs,
16911
+ binding
16912
+ );
16913
+ }, "tick");
16914
+ let running = false;
16915
+ const timer = setInterval(() => {
16916
+ if (running) return;
16917
+ running = true;
16918
+ void tick().finally(() => {
16919
+ running = false;
16920
+ });
16921
+ }, intervalMs);
16922
+ timer.unref?.();
16923
+ let bindDebounce;
16924
+ const cronFilePath = getCronFilePath(boundWorkspace);
16925
+ const cronDir = path11.dirname(cronFilePath);
16926
+ const cronFileName = path11.basename(cronFilePath);
16927
+ let fileWatcher;
16928
+ try {
16929
+ fsSync.mkdirSync(cronDir, { recursive: true });
16930
+ fileWatcher = fsSync.watch(
16931
+ cronDir,
16932
+ { persistent: false },
16933
+ (_event, filename) => {
16934
+ if (filename !== null && filename !== cronFileName) return;
16935
+ if (bindDebounce) clearTimeout(bindDebounce);
16936
+ bindDebounce = setTimeout(() => {
16937
+ if (running) return;
16938
+ running = true;
16939
+ void tick().finally(() => {
16940
+ running = false;
16941
+ });
16942
+ }, 500);
16943
+ bindDebounce.unref?.();
16944
+ }
16945
+ );
16946
+ fileWatcher.on("error", () => {
16947
+ });
16948
+ } catch {
16949
+ }
16950
+ let stopped = false;
16951
+ return {
16952
+ stop: /* @__PURE__ */ __name(() => {
16953
+ if (stopped) return;
16954
+ stopped = true;
16955
+ clearInterval(timer);
16956
+ if (bindDebounce) clearTimeout(bindDebounce);
16957
+ fileWatcher?.close();
16958
+ }, "stop"),
16959
+ tick
16960
+ };
16961
+ }
16962
+ __name(startScheduledTaskKeepalive, "startScheduledTaskKeepalive");
16963
+ var REHYDRATE_LOAD_TIMEOUT_MS = 3e4;
16964
+ var REHYDRATE_MAX_CONCURRENCY = 4;
16965
+ async function rehydrateScheduledTaskSessions(deps) {
16966
+ const { bridge, boundWorkspace } = deps;
16967
+ const timeoutMs = deps.loadTimeoutMs ?? REHYDRATE_LOAD_TIMEOUT_MS;
16968
+ let tasks;
16969
+ try {
16970
+ tasks = await readCronTasks(boundWorkspace);
16971
+ } catch (err) {
16972
+ log.debug("rehydrate: readCronTasks failed", err);
16973
+ return { loaded: [], failed: [] };
16974
+ }
16975
+ const sessionIds = collectBoundSessionIds(tasks);
16976
+ const loaded = [];
16977
+ const failed = [];
16978
+ const loadOne = /* @__PURE__ */ __name(async (sessionId) => {
16979
+ const load = bridge.loadSession({
16980
+ sessionId,
16981
+ workspaceCwd: boundWorkspace,
16982
+ historyReplay: "response"
16983
+ });
16984
+ void load.catch(() => {
16985
+ });
16986
+ try {
16987
+ await withTimeout(load, timeoutMs, `loadSession(${sessionId})`);
16988
+ loaded.push(sessionId);
16989
+ } catch (err) {
16990
+ failed.push(sessionId);
16991
+ try {
16992
+ deps.onError?.(sessionId, err);
16993
+ } catch {
16994
+ }
16995
+ }
16996
+ }, "loadOne");
16997
+ const queue = sessionIds.slice();
16998
+ const worker = /* @__PURE__ */ __name(async () => {
16999
+ for (let sessionId = queue.shift(); sessionId !== void 0; sessionId = queue.shift()) {
17000
+ await loadOne(sessionId);
17001
+ }
17002
+ }, "worker");
17003
+ await Promise.all(
17004
+ Array.from(
17005
+ { length: Math.min(REHYDRATE_MAX_CONCURRENCY, queue.length) },
17006
+ () => worker()
17007
+ )
17008
+ );
17009
+ return { loaded, failed };
17010
+ }
17011
+ __name(rehydrateScheduledTaskSessions, "rehydrateScheduledTaskSessions");
17012
+ function withTimeout(p, ms, label) {
17013
+ return new Promise((resolve4, reject) => {
17014
+ const timer = setTimeout(() => {
17015
+ reject(new Error(`${label} timed out after ${ms}ms`));
17016
+ }, ms);
17017
+ if (typeof timer.unref === "function") timer.unref();
17018
+ p.then(
17019
+ (v) => {
17020
+ clearTimeout(timer);
17021
+ resolve4(v);
17022
+ },
17023
+ (e) => {
17024
+ clearTimeout(timer);
17025
+ reject(e);
17026
+ }
17027
+ );
17028
+ });
17029
+ }
17030
+ __name(withTimeout, "withTimeout");
17031
+
16433
17032
  // packages/cli/src/serve/routes/workspace-status.ts
16434
17033
  init_esbuild_shims();
16435
17034
  function registerWorkspaceStatusRoutes(app, deps) {
@@ -17579,7 +18178,7 @@ __name(registerSseEventsRoutes, "registerSseEventsRoutes");
17579
18178
  // packages/cli/src/serve/routes/a2ui-action.ts
17580
18179
  init_esbuild_shims();
17581
18180
  import * as fsp4 from "node:fs/promises";
17582
- import * as path11 from "node:path";
18181
+ import * as path12 from "node:path";
17583
18182
  var A2UI_MIME = "application/a2ui+json";
17584
18183
  var ACTION_TOOL = "action";
17585
18184
  var CALL_TIMEOUT_MS = 15e3;
@@ -17599,7 +18198,7 @@ __name(usableServerConfig, "usableServerConfig");
17599
18198
  async function findFromSettingsFile(workspaceCwd) {
17600
18199
  try {
17601
18200
  const raw = await fsp4.readFile(
17602
- path11.join(workspaceCwd, ".qwen", "settings.json"),
18201
+ path12.join(workspaceCwd, ".qwen", "settings.json"),
17603
18202
  "utf8"
17604
18203
  );
17605
18204
  const settings = JSON.parse(raw);
@@ -17724,7 +18323,7 @@ __name(registerA2uiActionRoutes, "registerA2uiActionRoutes");
17724
18323
 
17725
18324
  // packages/cli/src/serve/server/fs-factory.ts
17726
18325
  init_esbuild_shims();
17727
- import * as path12 from "node:path";
18326
+ import * as path13 from "node:path";
17728
18327
  var IDE_WORKSPACE_PATH_ENV_VAR = "QWEN_CODE_IDE_WORKSPACE_PATH";
17729
18328
  function createDefaultFsAuditEmit() {
17730
18329
  const WARN_EVERY = 100;
@@ -17798,14 +18397,14 @@ function parseIdeWorkspacePathEnv(value) {
17798
18397
  const parsed = JSON.parse(value);
17799
18398
  if (Array.isArray(parsed) && parsed.every((item) => typeof item === "string")) {
17800
18399
  return parsed.filter(
17801
- (workspace) => workspace.length > 0 && path12.isAbsolute(workspace)
18400
+ (workspace) => workspace.length > 0 && path13.isAbsolute(workspace)
17802
18401
  );
17803
18402
  }
17804
18403
  throw new Error("IDE workspace path JSON must be a string array");
17805
18404
  } catch {
17806
18405
  }
17807
18406
  }
17808
- return value.split(path12.delimiter).filter((workspace) => workspace.length > 0 && path12.isAbsolute(workspace));
18407
+ return value.split(path13.delimiter).filter((workspace) => workspace.length > 0 && path13.isAbsolute(workspace));
17809
18408
  }
17810
18409
  __name(parseIdeWorkspacePathEnv, "parseIdeWorkspacePathEnv");
17811
18410
  function dropNestedWorkspacesPreservingPrimary(workspaces) {
@@ -17831,17 +18430,17 @@ __name(dropNestedWorkspacesPreservingPrimary, "dropNestedWorkspacesPreservingPri
17831
18430
  // packages/cli/src/serve/server/telemetry.ts
17832
18431
  init_esbuild_shims();
17833
18432
  function resolveDaemonTelemetryRoute(req) {
17834
- const path13 = req.path.replace(/\/$/, "") || "/";
17835
- if (req.method === "POST" && path13 === "/session") {
18433
+ const path14 = req.path.replace(/\/$/, "") || "/";
18434
+ if (req.method === "POST" && path14 === "/session") {
17836
18435
  return { route: "POST /session" };
17837
18436
  }
17838
- if (req.method === "POST" && path13 === "/sessions/delete") {
18437
+ if (req.method === "POST" && path14 === "/sessions/delete") {
17839
18438
  return { route: "POST /sessions/delete" };
17840
18439
  }
17841
- if (req.method === "GET" && path13 === "/daemon/status") {
18440
+ if (req.method === "GET" && path14 === "/daemon/status") {
17842
18441
  return { route: "GET /daemon/status" };
17843
18442
  }
17844
- const sessionAction = path13.match(
18443
+ const sessionAction = path14.match(
17845
18444
  /^\/session\/([^/]+)\/(load|resume|prompt|cancel|recap|btw|mid-turn-message|model|shell|detach|rewind|approval-mode|language|a2ui-action)$/
17846
18445
  );
17847
18446
  const sessionActionId = sessionAction?.[1];
@@ -17852,14 +18451,14 @@ function resolveDaemonTelemetryRoute(req) {
17852
18451
  sessionId: sessionActionId
17853
18452
  };
17854
18453
  }
17855
- const sessionMetadata = path13.match(/^\/session\/([^/]+)\/metadata$/);
18454
+ const sessionMetadata = path14.match(/^\/session\/([^/]+)\/metadata$/);
17856
18455
  if (sessionMetadata?.[1] && req.method === "PATCH") {
17857
18456
  return {
17858
18457
  route: "PATCH /session/:id/metadata",
17859
18458
  sessionId: sessionMetadata[1]
17860
18459
  };
17861
18460
  }
17862
- const sessionArtifacts = path13.match(/^\/session\/([^/]+)\/artifacts$/);
18461
+ const sessionArtifacts = path14.match(/^\/session\/([^/]+)\/artifacts$/);
17863
18462
  if (sessionArtifacts?.[1]) {
17864
18463
  if (req.method === "GET") {
17865
18464
  return {
@@ -17874,7 +18473,7 @@ function resolveDaemonTelemetryRoute(req) {
17874
18473
  };
17875
18474
  }
17876
18475
  }
17877
- const sessionArtifact = path13.match(
18476
+ const sessionArtifact = path14.match(
17878
18477
  /^\/session\/([^/]+)\/artifacts\/([^/]+)$/
17879
18478
  );
17880
18479
  if (sessionArtifact?.[1] && req.method === "DELETE") {
@@ -17883,7 +18482,7 @@ function resolveDaemonTelemetryRoute(req) {
17883
18482
  sessionId: sessionArtifact[1]
17884
18483
  };
17885
18484
  }
17886
- const sessionPermission = path13.match(
18485
+ const sessionPermission = path14.match(
17887
18486
  /^\/session\/([^/]+)\/permission\/([^/]+)$/
17888
18487
  );
17889
18488
  if (sessionPermission?.[1] && sessionPermission?.[2] && req.method === "POST") {
@@ -17894,7 +18493,7 @@ function resolveDaemonTelemetryRoute(req) {
17894
18493
  ...rawRequestId.length <= MAX_CLIENT_ID_LENGTH && CLIENT_ID_RE.test(rawRequestId) ? { permissionRequestId: rawRequestId } : {}
17895
18494
  };
17896
18495
  }
17897
- const globalPermission = path13.match(/^\/permission\/([^/]+)$/);
18496
+ const globalPermission = path14.match(/^\/permission\/([^/]+)$/);
17898
18497
  if (globalPermission?.[1] && req.method === "POST") {
17899
18498
  const rawRequestId = globalPermission[1];
17900
18499
  return {
@@ -17902,66 +18501,66 @@ function resolveDaemonTelemetryRoute(req) {
17902
18501
  ...rawRequestId.length <= MAX_CLIENT_ID_LENGTH && CLIENT_ID_RE.test(rawRequestId) ? { permissionRequestId: rawRequestId } : {}
17903
18502
  };
17904
18503
  }
17905
- const deleteSession = path13.match(/^\/session\/([^/]+)$/);
18504
+ const deleteSession = path14.match(/^\/session\/([^/]+)$/);
17906
18505
  const deleteSessionId = deleteSession?.[1];
17907
18506
  if (deleteSessionId && req.method === "DELETE") {
17908
18507
  return { route: "DELETE /session/:id", sessionId: deleteSessionId };
17909
18508
  }
17910
- if (req.method === "GET" && /^\/workspace\/[^/]+\/sessions$/.test(path13)) {
18509
+ if (req.method === "GET" && /^\/workspace\/[^/]+\/sessions$/.test(path14)) {
17911
18510
  return { route: "GET /workspace/:id/sessions" };
17912
18511
  }
17913
- if (req.method === "POST" && path13 === "/workspace/init") {
18512
+ if (req.method === "POST" && path14 === "/workspace/init") {
17914
18513
  return { route: "POST /workspace/init" };
17915
18514
  }
17916
- if (req.method === "POST" && path13 === "/workspace/setup-github") {
18515
+ if (req.method === "POST" && path14 === "/workspace/setup-github") {
17917
18516
  return { route: "POST /workspace/setup-github" };
17918
18517
  }
17919
- if (req.method === "POST" && path13 === "/workspace/reload") {
18518
+ if (req.method === "POST" && path14 === "/workspace/reload") {
17920
18519
  return { route: "POST /workspace/reload" };
17921
18520
  }
17922
- const mcpRestart = path13.match(/^\/workspace\/mcp\/([^/]+)\/restart$/);
18521
+ const mcpRestart = path14.match(/^\/workspace\/mcp\/([^/]+)\/restart$/);
17923
18522
  if (mcpRestart?.[1] && req.method === "POST") {
17924
18523
  return { route: "POST /workspace/mcp/:server/restart" };
17925
18524
  }
17926
- if (req.method === "POST" && path13 === "/workspace/mcp/servers") {
18525
+ if (req.method === "POST" && path14 === "/workspace/mcp/servers") {
17927
18526
  return { route: "POST /workspace/mcp/servers" };
17928
18527
  }
17929
- const mcpDelete = path13.match(/^\/workspace\/mcp\/servers\/([^/]+)$/);
18528
+ const mcpDelete = path14.match(/^\/workspace\/mcp\/servers\/([^/]+)$/);
17930
18529
  if (mcpDelete?.[1] && req.method === "DELETE") {
17931
18530
  return { route: "DELETE /workspace/mcp/servers/:name" };
17932
18531
  }
17933
- if (req.method === "POST" && path13 === "/workspace/auth/device-flow") {
18532
+ if (req.method === "POST" && path14 === "/workspace/auth/device-flow") {
17934
18533
  return { route: "POST /workspace/auth/device-flow" };
17935
18534
  }
17936
- const deviceFlowDelete = path13.match(
18535
+ const deviceFlowDelete = path14.match(
17937
18536
  /^\/workspace\/auth\/device-flow\/([^/]+)$/
17938
18537
  );
17939
18538
  if (deviceFlowDelete?.[1] && req.method === "DELETE") {
17940
18539
  return { route: "DELETE /workspace/auth/device-flow/:id" };
17941
18540
  }
17942
- const toolEnable = path13.match(/^\/workspace\/tools\/([^/]+)\/enable$/);
18541
+ const toolEnable = path14.match(/^\/workspace\/tools\/([^/]+)\/enable$/);
17943
18542
  if (toolEnable?.[1] && req.method === "POST") {
17944
18543
  return { route: "POST /workspace/tools/:name/enable" };
17945
18544
  }
17946
- if (path13 === "/workspace/settings") {
18545
+ if (path14 === "/workspace/settings") {
17947
18546
  if (req.method === "GET") return { route: "GET /workspace/settings" };
17948
18547
  if (req.method === "POST") return { route: "POST /workspace/settings" };
17949
18548
  }
17950
- if (path13 === "/workspace/permissions") {
18549
+ if (path14 === "/workspace/permissions") {
17951
18550
  if (req.method === "GET") return { route: "GET /workspace/permissions" };
17952
18551
  if (req.method === "POST") return { route: "POST /workspace/permissions" };
17953
18552
  }
17954
- if (path13 === "/workspace/trust") {
18553
+ if (path14 === "/workspace/trust") {
17955
18554
  if (req.method === "GET") return { route: "GET /workspace/trust" };
17956
18555
  }
17957
- if (req.method === "POST" && path13 === "/workspace/trust/request") {
18556
+ if (req.method === "POST" && path14 === "/workspace/trust/request") {
17958
18557
  return { route: "POST /workspace/trust/request" };
17959
18558
  }
17960
- if (path13 === "/workspace/voice") {
18559
+ if (path14 === "/workspace/voice") {
17961
18560
  if (req.method === "GET") return { route: "GET /workspace/voice" };
17962
18561
  if (req.method === "POST") return { route: "POST /workspace/voice" };
17963
18562
  }
17964
- if (req.method === "POST" && path13 === "/workspace/voice/transcribe") {
18563
+ if (req.method === "POST" && path14 === "/workspace/voice/transcribe") {
17965
18564
  return { route: "POST /workspace/voice/transcribe" };
17966
18565
  }
17967
18566
  return void 0;
@@ -18329,10 +18928,10 @@ function installRateLimiter(app, opts, daemonLog) {
18329
18928
  { tier, key: key.slice(0, 64) }
18330
18929
  );
18331
18930
  } : void 0,
18332
- onError: daemonLog ? (err, path13) => {
18931
+ onError: daemonLog ? (err, path14) => {
18333
18932
  daemonLog.warn(
18334
18933
  `rate limiter error (fail-open): ${err instanceof Error ? err.message : String(err)}`,
18335
- { path: path13 }
18934
+ { path: path14 }
18336
18935
  );
18337
18936
  } : void 0
18338
18937
  });
@@ -18385,14 +18984,69 @@ __name(installSelfOriginStripMiddleware, "installSelfOriginStripMiddleware");
18385
18984
 
18386
18985
  // packages/cli/src/serve/workspace-registry.ts
18387
18986
  init_esbuild_shims();
18388
- function createSingleWorkspaceRegistry(runtime) {
18389
- const runtimes = Object.freeze([runtime]);
18987
+ function createWorkspaceRegistry(inputRuntimes) {
18988
+ if (inputRuntimes.length === 0) {
18989
+ throw new Error(
18990
+ "WorkspaceRegistry requires at least one workspace runtime."
18991
+ );
18992
+ }
18993
+ const primaryRuntimes = inputRuntimes.filter((runtime) => runtime.primary);
18994
+ if (primaryRuntimes.length !== 1) {
18995
+ throw new Error(
18996
+ "WorkspaceRegistry requires exactly one primary workspace runtime."
18997
+ );
18998
+ }
18999
+ const byCwd = /* @__PURE__ */ new Map();
19000
+ const byId = /* @__PURE__ */ new Map();
19001
+ for (const runtime of inputRuntimes) {
19002
+ if (byCwd.has(runtime.workspaceCwd)) {
19003
+ throw new Error(
19004
+ `Duplicate workspace runtime cwd ${JSON.stringify(
19005
+ runtime.workspaceCwd
19006
+ )}.`
19007
+ );
19008
+ }
19009
+ byCwd.set(runtime.workspaceCwd, runtime);
19010
+ if (byId.has(runtime.workspaceId)) {
19011
+ throw new Error(
19012
+ `Duplicate workspace runtime id ${JSON.stringify(
19013
+ runtime.workspaceId
19014
+ )}.`
19015
+ );
19016
+ }
19017
+ byId.set(runtime.workspaceId, runtime);
19018
+ }
19019
+ const runtimes = Object.freeze([...inputRuntimes]);
19020
+ const primary = primaryRuntimes[0];
18390
19021
  return {
18391
- primary: runtime,
19022
+ primary,
18392
19023
  list: /* @__PURE__ */ __name(() => runtimes, "list"),
18393
- getByWorkspaceCwd: /* @__PURE__ */ __name((workspaceCwd) => workspaceCwd === runtime.workspaceCwd ? runtime : void 0, "getByWorkspaceCwd")
19024
+ getByWorkspaceCwd: /* @__PURE__ */ __name((workspaceCwd) => byCwd.get(workspaceCwd), "getByWorkspaceCwd"),
19025
+ getByWorkspaceId: /* @__PURE__ */ __name((workspaceId) => byId.get(workspaceId), "getByWorkspaceId"),
19026
+ resolveWorkspaceCwd: /* @__PURE__ */ __name((workspaceCwd) => workspaceCwd === void 0 ? primary : byCwd.get(workspaceCwd), "resolveWorkspaceCwd"),
19027
+ resolveLiveSessionOwner: /* @__PURE__ */ __name((sessionId) => {
19028
+ const matches = [];
19029
+ for (const runtime of runtimes) {
19030
+ try {
19031
+ runtime.bridge.getSessionSummary(sessionId);
19032
+ matches.push(runtime);
19033
+ } catch (err) {
19034
+ if (err instanceof SessionNotFoundError) continue;
19035
+ throw err;
19036
+ }
19037
+ }
19038
+ if (matches.length === 0) return { kind: "not_found" };
19039
+ if (matches.length === 1) {
19040
+ return { kind: "found", runtime: matches[0] };
19041
+ }
19042
+ return { kind: "ambiguous", runtimes: matches };
19043
+ }, "resolveLiveSessionOwner")
18394
19044
  };
18395
19045
  }
19046
+ __name(createWorkspaceRegistry, "createWorkspaceRegistry");
19047
+ function createSingleWorkspaceRegistry(runtime) {
19048
+ return createWorkspaceRegistry([runtime]);
19049
+ }
18396
19050
  __name(createSingleWorkspaceRegistry, "createSingleWorkspaceRegistry");
18397
19051
 
18398
19052
  // packages/cli/src/serve/routes/workspace-lifecycle.ts
@@ -18693,37 +19347,101 @@ __name(registerWorkspaceToolsRoutes, "registerWorkspaceToolsRoutes");
18693
19347
 
18694
19348
  // packages/cli/src/serve/server.ts
18695
19349
  var warnedDefaultTrust = false;
19350
+ function describeRegistryPrimaryForConflict(registry) {
19351
+ return `registry primary cwd=${JSON.stringify(registry.primary.workspaceCwd)}, workspaceId=${JSON.stringify(registry.primary.workspaceId)}`;
19352
+ }
19353
+ __name(describeRegistryPrimaryForConflict, "describeRegistryPrimaryForConflict");
19354
+ var DEFAULT_SESSION_IDLE_TIMEOUT_MS = 30 * 6e4;
19355
+ var KEEPALIVE_MIN_INTERVAL_MS = 3e4;
19356
+ var KEEPALIVE_MAX_INTERVAL_MS = 10 * 6e4;
19357
+ function computeKeepaliveIntervalMs(idleTimeoutMs) {
19358
+ if (idleTimeoutMs <= 0) return KEEPALIVE_MAX_INTERVAL_MS;
19359
+ const target = Math.min(
19360
+ Math.max(KEEPALIVE_MIN_INTERVAL_MS, Math.floor(idleTimeoutMs / 3)),
19361
+ KEEPALIVE_MAX_INTERVAL_MS
19362
+ );
19363
+ return Math.max(1, Math.min(target, Math.floor(idleTimeoutMs / 2)));
19364
+ }
19365
+ __name(computeKeepaliveIntervalMs, "computeKeepaliveIntervalMs");
18696
19366
  function createServeApp(opts, getPort = () => opts.port, deps = {}) {
18697
19367
  const app = (0, import_express4.default)();
18698
- const boundWorkspace = deps.boundWorkspace ?? canonicalizeWorkspace(opts.workspace ?? process.cwd());
18699
- if (!deps.fsFactory && !deps.bridge && !warnedDefaultTrust) {
19368
+ const injectedWorkspaceRegistry = deps.workspaceRegistry;
19369
+ const boundWorkspace = injectedWorkspaceRegistry?.primary.workspaceCwd ?? deps.boundWorkspace ?? canonicalizeWorkspace(opts.workspace ?? process.cwd());
19370
+ if (injectedWorkspaceRegistry) {
19371
+ const primary = injectedWorkspaceRegistry.primary;
19372
+ const registryConflictCandidates = [
19373
+ {
19374
+ depName: "deps.boundWorkspace",
19375
+ depValue: deps.boundWorkspace,
19376
+ registryValue: primary.workspaceCwd,
19377
+ detail: `deps.boundWorkspace=${JSON.stringify(deps.boundWorkspace)}`
19378
+ },
19379
+ {
19380
+ depName: "deps.bridge",
19381
+ depValue: deps.bridge,
19382
+ registryValue: primary.bridge,
19383
+ detail: "deps.bridge is a different object"
19384
+ },
19385
+ {
19386
+ depName: "deps.workspace",
19387
+ depValue: deps.workspace,
19388
+ registryValue: primary.workspaceService,
19389
+ detail: "deps.workspace is a different object"
19390
+ },
19391
+ {
19392
+ depName: "deps.fsFactory",
19393
+ depValue: deps.fsFactory,
19394
+ registryValue: primary.routeFileSystemFactory,
19395
+ detail: "deps.fsFactory is a different object"
19396
+ },
19397
+ {
19398
+ depName: "deps.clientMcpSenderRegistry",
19399
+ depValue: deps.clientMcpSenderRegistry,
19400
+ registryValue: primary.clientMcpSenderRegistry,
19401
+ detail: "deps.clientMcpSenderRegistry is a different object"
19402
+ }
19403
+ ];
19404
+ for (const candidate of registryConflictCandidates) {
19405
+ if (candidate.depValue === void 0 || candidate.depValue === candidate.registryValue) {
19406
+ continue;
19407
+ }
19408
+ throw new Error(
19409
+ `createServeApp: workspaceRegistry conflicts with ${candidate.depName}: ${describeRegistryPrimaryForConflict(
19410
+ injectedWorkspaceRegistry
19411
+ )}; ${candidate.detail}.`
19412
+ );
19413
+ }
19414
+ }
19415
+ if (!injectedWorkspaceRegistry && !deps.fsFactory && !deps.bridge && !warnedDefaultTrust) {
18700
19416
  warnedDefaultTrust = true;
18701
19417
  process.stderr.write(
18702
19418
  "qwen serve: createServeApp default fsFactory uses trusted=false \u2014 agent ACP writeTextFile calls will reject with untrusted_workspace. Inject deps.fsFactory (with explicit trust) or deps.bridge to override.\n"
18703
19419
  );
18704
19420
  }
18705
- const fsFactory = resolveBridgeFsFactory({
19421
+ const fsFactory = injectedWorkspaceRegistry?.primary.routeFileSystemFactory ?? resolveBridgeFsFactory({
18706
19422
  boundWorkspaces: [boundWorkspace],
18707
19423
  injected: deps.fsFactory,
18708
19424
  trusted: false
18709
19425
  });
18710
19426
  const tokenConfigured = typeof opts.token === "string" && opts.token.length > 0;
18711
19427
  const sessionShellCommandEnabled = opts.enableSessionShell === true && tokenConfigured;
18712
- if (opts.clientMcpOverWs === true && deps.bridge && !deps.clientMcpSenderRegistry) {
19428
+ if (opts.clientMcpOverWs === true && deps.bridge && !injectedWorkspaceRegistry && !deps.clientMcpSenderRegistry) {
18713
19429
  throw new Error(
18714
19430
  "createServeApp: deps.bridge requires deps.clientMcpSenderRegistry when clientMcpOverWs is enabled (the bridge is already wired to its own sender; a fresh registry here would be an orphan)."
18715
19431
  );
18716
19432
  }
18717
- const clientMcpSenderRegistry = deps.clientMcpSenderRegistry ?? new ClientMcpSenderRegistry();
19433
+ const clientMcpSenderRegistry = injectedWorkspaceRegistry?.primary.clientMcpSenderRegistry ?? deps.clientMcpSenderRegistry ?? new ClientMcpSenderRegistry();
18718
19434
  const { languageCodes, currentServeFeatures, invalidateServeFeaturesCache } = createServeFeatures({
18719
19435
  opts,
18720
19436
  boundWorkspace,
18721
19437
  persistSettingAvailable: deps.persistSetting !== void 0,
18722
- reloadAvailable: deps.workspace !== void 0,
19438
+ // Registry injection supplies the primary workspace service through the
19439
+ // runtime, so it has the same reload surface as legacy deps.workspace.
19440
+ reloadAvailable: deps.workspace !== void 0 || injectedWorkspaceRegistry !== void 0,
18723
19441
  sessionShellCommandEnabled
18724
19442
  });
18725
19443
  const statusProvider = deps.statusProvider ?? createDaemonStatusProvider();
18726
- const bridge = deps.bridge ?? createAcpSessionBridge({
19444
+ const bridge = injectedWorkspaceRegistry?.primary.bridge ?? deps.bridge ?? createAcpSessionBridge({
18727
19445
  maxSessions: opts.maxSessions,
18728
19446
  maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession,
18729
19447
  eventRingSize: opts.eventRingSize,
@@ -18753,7 +19471,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
18753
19471
  const { daemonLog } = deps;
18754
19472
  const sendBridgeError2 = /* @__PURE__ */ __name((res, err, ctx) => sendBridgeError(res, err, ctx, daemonLog), "sendBridgeError");
18755
19473
  const sendPermissionVoteError2 = /* @__PURE__ */ __name((res, err, ctx) => sendPermissionVoteError(res, err, ctx, daemonLog), "sendPermissionVoteError");
18756
- const workspace = deps.workspace ?? createDaemonWorkspaceService({
19474
+ const workspace = injectedWorkspaceRegistry?.primary.workspaceService ?? deps.workspace ?? createDaemonWorkspaceService({
18757
19475
  boundWorkspace,
18758
19476
  contextFilename: deps.contextFilename ?? "QWEN.md",
18759
19477
  statusProvider,
@@ -18777,8 +19495,12 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
18777
19495
  bridge.publishWorkspaceEvent(event);
18778
19496
  }, "publishWorkspaceEvent")
18779
19497
  });
18780
- const workspaceRegistry = createSingleWorkspaceRegistry({
19498
+ const workspaceRegistry = injectedWorkspaceRegistry ?? createSingleWorkspaceRegistry({
19499
+ workspaceId: hashDaemonWorkspace(boundWorkspace),
18781
19500
  workspaceCwd: boundWorkspace,
19501
+ primary: true,
19502
+ trusted: deps.primaryWorkspaceTrusted ?? false,
19503
+ env: { mode: "parent-process", overlayKeys: [] },
18782
19504
  bridge,
18783
19505
  workspaceService: workspace,
18784
19506
  routeFileSystemFactory: fsFactory,
@@ -19032,9 +19754,39 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
19032
19754
  registerScheduledTasksRoutes(app, {
19033
19755
  boundWorkspace: primaryBoundWorkspace,
19034
19756
  mutate,
19035
- safeBody
19757
+ safeBody,
19758
+ bridge: deps.manageScheduledTaskSessions ? bridge : void 0
19036
19759
  });
19037
19760
  registerUsageStatsRoutes(app);
19761
+ if (deps.manageScheduledTaskSessions) {
19762
+ const idleTimeoutMs = opts.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
19763
+ const keepalive = startScheduledTaskKeepalive({
19764
+ bridge,
19765
+ boundWorkspace,
19766
+ intervalMs: computeKeepaliveIntervalMs(idleTimeoutMs)
19767
+ });
19768
+ app.locals.stopScheduledTaskKeepalive = keepalive.stop;
19769
+ void rehydrateScheduledTaskSessions({
19770
+ bridge,
19771
+ boundWorkspace,
19772
+ onError: /* @__PURE__ */ __name((sessionId, err) => {
19773
+ process.stderr.write(
19774
+ `qwen serve: failed to rehydrate scheduled-task session ${sessionId}: ${err instanceof Error ? err.message : String(err)}
19775
+ `
19776
+ );
19777
+ }, "onError")
19778
+ // Outer catch is defense-in-depth: rehydrateScheduledTaskSessions already
19779
+ // catches readCronTasks failures and per-session load errors internally
19780
+ // (returning { loaded, failed }), so this only guards an unexpected throw
19781
+ // from the function entry itself. Log rather than swallow it — a silent
19782
+ // failure here leaves every bound task dormant with no diagnostic.
19783
+ }).catch((err) => {
19784
+ process.stderr.write(
19785
+ `qwen serve: unexpected scheduled-task rehydration failure: ${err instanceof Error ? err.message : String(err)}
19786
+ `
19787
+ );
19788
+ });
19789
+ }
19038
19790
  registerPermissionRoutes(app, {
19039
19791
  bridge: primaryBridge,
19040
19792
  mutate,
@@ -19104,6 +19856,7 @@ __name(createServeApp, "createServeApp");
19104
19856
  export {
19105
19857
  InvalidCursorError,
19106
19858
  PromptDeadlineExceededError,
19859
+ computeKeepaliveIntervalMs,
19107
19860
  createDefaultFsAuditEmit,
19108
19861
  createServeApp,
19109
19862
  detectFromLoopback,