@qwen-code/qwen-code 0.19.3 → 0.19.4-nightly.20260702.46814e4f1

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 (308) hide show
  1. package/bundled/loop/SKILL.md +22 -3
  2. package/bundled/loop/SKILL.test.ts +20 -0
  3. package/bundled/loop/autonomous-loop.test.ts +59 -0
  4. package/bundled/loop/autonomous-loop.ts +102 -0
  5. package/bundled/loop/loop-task-file.test.ts +1064 -0
  6. package/bundled/loop/loop-task-file.ts +404 -0
  7. package/bundled/loop/loop-tick-resolver.test.ts +906 -0
  8. package/bundled/loop/loop-tick-resolver.ts +416 -0
  9. package/bundled/qc-helper/SKILL.md +12 -5
  10. package/bundled/qc-helper/docs/configuration/auth.md +1 -1
  11. package/bundled/qc-helper/docs/configuration/settings.md +62 -32
  12. package/bundled/qc-helper/docs/features/approval-mode.md +3 -0
  13. package/bundled/qc-helper/docs/features/auto-mode.md +40 -0
  14. package/bundled/qc-helper/docs/features/channels/overview.md +81 -18
  15. package/bundled/qc-helper/docs/features/channels/plugins.md +1 -1
  16. package/bundled/qc-helper/docs/features/code-review.md +17 -61
  17. package/bundled/qc-helper/docs/features/commands.md +42 -40
  18. package/bundled/qc-helper/docs/features/headless.md +19 -18
  19. package/bundled/qc-helper/docs/features/hooks.md +6 -1
  20. package/bundled/qc-helper/docs/features/mcp.md +3 -1
  21. package/bundled/qc-helper/docs/features/memory.md +1 -1
  22. package/bundled/qc-helper/docs/features/scheduled-tasks.md +10 -0
  23. package/bundled/qc-helper/docs/features/status-line.md +3 -3
  24. package/bundled/qc-helper/docs/ide-integration/ide-integration.md +4 -4
  25. package/bundled/qc-helper/docs/qwen-serve.md +53 -0
  26. package/bundled/qc-helper/docs/support/troubleshooting.md +11 -0
  27. package/bundled/review/DESIGN.md +21 -26
  28. package/bundled/review/SKILL.md +45 -129
  29. package/chunks/MaxSizedBox-GHGRQ2OS.js +69 -0
  30. package/chunks/{StandaloneSessionPicker-Z52JTYST.js → StandaloneSessionPicker-G7YTTM27.js} +49 -42
  31. package/chunks/{acpAgent-7RZUOWOM.js → acpAgent-SDOILBSU.js} +1325 -365
  32. package/chunks/{agent-4FG7WTHJ.js → agent-NTSXGV4L.js} +31 -25
  33. package/chunks/agent-headless-WYURMSAB.js +62 -0
  34. package/chunks/{anthropicContentGenerator-PFITVL7Y.js → anthropicContentGenerator-WL3LJOUB.js} +110 -31
  35. package/chunks/{artifact-tool-D2X7G3C3.js → artifact-tool-W76WC2JX.js} +3 -3
  36. package/chunks/{askUserQuestion-UGETICJQ.js → askUserQuestion-J3P6TH3V.js} +2 -2
  37. package/chunks/bridge-AMOL4W4P.js +73 -0
  38. package/chunks/{ca-IUFWESZL.js → ca-HCMB2I54.js} +10 -9
  39. package/chunks/channel-worker-supervisor-C3IB63V7.js +659 -0
  40. package/chunks/{chunk-STUWFKGD.js → chunk-26JIREA5.js} +466 -543
  41. package/chunks/{chunk-SLNKLLEO.js → chunk-2MRV62AU.js} +37 -8
  42. package/chunks/{chunk-ODLIHNOY.js → chunk-2U4HUMOL.js} +1 -1
  43. package/chunks/{chunk-CKQA6AWF.js → chunk-4D73HUOP.js} +1 -1
  44. package/chunks/{chunk-M2U5NM24.js → chunk-54YZOP7P.js} +309 -72
  45. package/chunks/{chunk-J7FA27RO.js → chunk-5LKL3PAU.js} +3 -3
  46. package/chunks/chunk-5P5XGNYH.js +93 -0
  47. package/chunks/{chunk-UFLGERMB.js → chunk-6JE32BRB.js} +178 -124
  48. package/chunks/{chunk-FKAVULLM.js → chunk-75AVTQJ2.js} +74 -10
  49. package/chunks/{chunk-I2LYBGNI.js → chunk-7IOMIYOE.js} +1 -1
  50. package/chunks/{chunk-4LUZAKMK.js → chunk-7KXAGQJ2.js} +1 -1
  51. package/chunks/{chunk-BXSHL2SF.js → chunk-7LUOQJ3D.js} +1 -1
  52. package/chunks/{chunk-YAINVQ3Q.js → chunk-A5OPLHFM.js} +18693 -17055
  53. package/chunks/chunk-AHNXYU4O.js +24 -0
  54. package/chunks/{chunk-UX4SGCGN.js → chunk-AVQDCKNF.js} +96 -22
  55. package/chunks/{chunk-HYCC3XM3.js → chunk-B236XPGF.js} +1 -1
  56. package/chunks/chunk-B6SZLQAZ.js +3523 -0
  57. package/chunks/{chunk-5DWXLGOM.js → chunk-BJBWRCSK.js} +1 -1
  58. package/chunks/chunk-BPFJQGY7.js +193 -0
  59. package/chunks/{chunk-SKQZZVAV.js → chunk-BZHLWC6T.js} +2 -2
  60. package/chunks/{chunk-U3KSMM7G.js → chunk-D5KISTLW.js} +339 -383
  61. package/chunks/{chunk-GT2FGICD.js → chunk-DE7YXUR7.js} +1 -1
  62. package/chunks/{chunk-BUUQ5HPX.js → chunk-DG573EOO.js} +1 -1
  63. package/chunks/{chunk-VVLOGDB6.js → chunk-DX3TKXNT.js} +2 -2
  64. package/chunks/chunk-E5A7LHNN.js +51 -0
  65. package/chunks/{chunk-3PJXIDKI.js → chunk-E6US47KI.js} +3 -27
  66. package/chunks/{chunk-QBZ22PQX.js → chunk-EWALXUAD.js} +3 -1
  67. package/chunks/{chunk-PDE7CSDS.js → chunk-FXKI7OW6.js} +2 -2
  68. package/chunks/{chunk-F3ZYSEY6.js → chunk-FY4TT4L4.js} +3 -3
  69. package/chunks/{chunk-QLDPRILK.js → chunk-G7OQ3RFJ.js} +3 -3
  70. package/chunks/{chunk-R2BXK7SX.js → chunk-GHOTR7HL.js} +6 -1
  71. package/chunks/{chunk-KMGMKW5Q.js → chunk-GLPV75ES.js} +9 -3
  72. package/chunks/{chunk-LD2XBG6Z.js → chunk-GO6LNQXT.js} +1 -39
  73. package/chunks/{chunk-CNLEDYE3.js → chunk-H6TNLOLM.js} +5 -5
  74. package/chunks/{chunk-JVHEVCAU.js → chunk-HLW4EGKR.js} +31 -6
  75. package/chunks/{chunk-I4H7PRWQ.js → chunk-HTWHAN44.js} +1 -1
  76. package/chunks/{chunk-QE6KJYLT.js → chunk-IPYE5BIS.js} +123 -25
  77. package/chunks/{chunk-EJYJYJZ2.js → chunk-IRJWHZWU.js} +3 -70
  78. package/chunks/{chunk-EDMZZFDU.js → chunk-J3YPTTNL.js} +930 -798
  79. package/chunks/{chunk-GGBIN5K7.js → chunk-JGAJMIJZ.js} +1 -1
  80. package/chunks/{chunk-N4EJFBN5.js → chunk-JVLP5US5.js} +427 -263
  81. package/chunks/{chunk-R5OP2ATH.js → chunk-JZG7VB6C.js} +11 -11
  82. package/chunks/{chunk-QI7GOGJR.js → chunk-KKQWC6WS.js} +1 -1
  83. package/chunks/{chunk-ADCIHOQZ.js → chunk-KX5QZRW2.js} +142 -30
  84. package/chunks/{chunk-SBBN4BWR.js → chunk-L7OJ3ZO3.js} +1 -1
  85. package/chunks/{chunk-NDOC6M5S.js → chunk-L7QPM2YD.js} +2 -2
  86. package/chunks/{chunk-BVSVIN45.js → chunk-LKWAVAB5.js} +3 -3
  87. package/chunks/{chunk-T4T2FNV4.js → chunk-LOW52WYZ.js} +2 -2
  88. package/chunks/{chunk-4QK3O43S.js → chunk-LU7BIVWC.js} +4 -4
  89. package/chunks/{chunk-ZP6UKOPB.js → chunk-LWGLBVWA.js} +1 -1
  90. package/chunks/{chunk-L7OKCI7T.js → chunk-M7BLWURA.js} +15 -1
  91. package/chunks/{chunk-PR32FRT6.js → chunk-MIM62IXS.js} +3 -3
  92. package/chunks/{chunk-RD6YJJJ6.js → chunk-MOUXUCXQ.js} +1 -1
  93. package/chunks/{chunk-VBZ452JT.js → chunk-MSNGFH6L.js} +494 -114
  94. package/chunks/{chunk-BX5YO7UW.js → chunk-MTNTVOJR.js} +542 -370
  95. package/chunks/chunk-MX2YXRER.js +44 -0
  96. package/chunks/chunk-NIOPRZNN.js +27 -0
  97. package/chunks/{chunk-SMYQZVZ3.js → chunk-NOGSPTLJ.js} +1 -1
  98. package/chunks/{chunk-DDMOU62Q.js → chunk-NPQWQYU6.js} +1 -1
  99. package/chunks/{chunk-MNF6S5PR.js → chunk-P5THQV6A.js} +4 -4
  100. package/chunks/{chunk-6V4NZFUS.js → chunk-PCYOT4PK.js} +5 -5
  101. package/chunks/{chunk-CF6BB3LT.js → chunk-PPFWEV7G.js} +10 -1
  102. package/chunks/{chunk-FXKVLFFY.js → chunk-PSFDB5FZ.js} +3 -3
  103. package/chunks/{chunk-XJYUPHRC.js → chunk-QOMAHFYI.js} +3 -3
  104. package/chunks/{chunk-J37FGIOA.js → chunk-QXPI7FEC.js} +38 -4
  105. package/chunks/{chunk-RRFZXMYP.js → chunk-QZDBHNMV.js} +691 -164
  106. package/chunks/{chunk-S7AKE7HL.js → chunk-R6RI2HIC.js} +63 -9
  107. package/chunks/{chunk-HZT4UCFB.js → chunk-RB7S52NJ.js} +4 -4
  108. package/chunks/{chunk-J33ZR6OJ.js → chunk-RK22ACPP.js} +16 -16
  109. package/chunks/chunk-RM3PGSGL.js +66 -0
  110. package/chunks/chunk-RNBYOUGV.js +42 -0
  111. package/chunks/chunk-S6RLAIUR.js +23 -0
  112. package/chunks/{chunk-3TV3HUWZ.js → chunk-SCYK2YLI.js} +81 -30
  113. package/chunks/{chunk-HPZTOP4I.js → chunk-SEKRT4SD.js} +133 -23
  114. package/chunks/chunk-SEZC2725.js +36 -0
  115. package/chunks/chunk-SIUQ3YYX.js +78 -0
  116. package/chunks/{chunk-O2VBQ3Y2.js → chunk-SJBIFVD2.js} +2 -2
  117. package/chunks/chunk-SYCJMSIJ.js +82 -0
  118. package/chunks/{chunk-JE5FVRPC.js → chunk-T22H4V4R.js} +48 -23
  119. package/chunks/{chunk-3227DZO4.js → chunk-T42ACHFI.js} +1 -1
  120. package/chunks/{chunk-UO5GVXQE.js → chunk-TENOUWY2.js} +3 -3
  121. package/chunks/{chunk-JOLIREYR.js → chunk-TOAUDIS7.js} +1 -1
  122. package/chunks/{chunk-QNKBEJO2.js → chunk-UA6XBZT7.js} +2776 -1289
  123. package/chunks/{chunk-O75BHFQW.js → chunk-UQTYK5SS.js} +2 -2
  124. package/chunks/{chunk-Y6YMRS3U.js → chunk-UY2TCIZS.js} +17 -3
  125. package/chunks/{chunk-FNJ7BDPH.js → chunk-UY7ZAYTY.js} +10 -7
  126. package/chunks/{chunk-UYT3MWEB.js → chunk-UYHWM24C.js} +30 -2
  127. package/chunks/{chunk-SMXULRAN.js → chunk-VXGPYF7U.js} +1 -1
  128. package/chunks/{chunk-BTLJ2MF5.js → chunk-W7CG5HPC.js} +3 -3
  129. package/chunks/{chunk-JJXWTVSK.js → chunk-XHZKDN7M.js} +34 -1
  130. package/chunks/{chunk-K5XU6E4T.js → chunk-XKSCTXPK.js} +2 -2
  131. package/chunks/chunk-Y4LITCRB.js +367 -0
  132. package/chunks/chunk-YHTNWGRR.js +239 -0
  133. package/chunks/{chunk-BKXBARJZ.js → chunk-YPCPZSZB.js} +1 -1
  134. package/chunks/{chunk-QWFNTRH4.js → chunk-YSM24SCE.js} +1 -1
  135. package/chunks/chunk-YTFBURQD.js +313 -0
  136. package/chunks/{chunk-NL4C3H6C.js → chunk-YXK4GPYO.js} +1 -1
  137. package/chunks/{chunk-RYLJU2DY.js → chunk-ZN5T4BHI.js} +1 -1
  138. package/chunks/{computer-use-JGB36FDW.js → computer-use-MTSVPLPY.js} +34 -28
  139. package/chunks/contextCommand-VGJ3BPTK.js +67 -0
  140. package/chunks/{cron-create-SKEY55RG.js → cron-create-6YTCOX6P.js} +4 -4
  141. package/chunks/{cron-delete-I3NAT32Z.js → cron-delete-E3NIFSUK.js} +4 -4
  142. package/chunks/{cron-list-6XRRL6TH.js → cron-list-Q64MNQNE.js} +4 -4
  143. package/chunks/daemon-EEB2RYOL.js +8453 -0
  144. package/chunks/daemon-status-provider-H5SNMK42.js +71 -0
  145. package/chunks/{de-EOW5PVHF.js → de-PLLFDERI.js} +10 -9
  146. package/chunks/{dist-NHEYYB2B.js → dist-ADMIQGHI.js} +2 -2
  147. package/chunks/{dist-J37VXPLD.js → dist-BCQ7INM7.js} +40 -15
  148. package/chunks/{dist-663NZ6MI.js → dist-KNZFCY5F.js} +116 -11
  149. package/chunks/{dist-LB6OGPVM.js → dist-LHUWC3K6.js} +26 -5
  150. package/chunks/{dist-PQPZ5Q4N.js → dist-WBBZ76JZ.js} +20 -9
  151. package/chunks/{earlyInputCapture-44RISVVJ.js → earlyInputCapture-U4ZIQSQU.js} +32 -26
  152. package/chunks/{edit-NN6GM5DT.js → edit-SYIQ2KBI.js} +41 -38
  153. package/chunks/{en-HPWEJBTR.js → en-M4EBUBNU.js} +32 -10
  154. package/chunks/{enter-worktree-PB3O2C7D.js → enter-worktree-HPPOO244.js} +31 -25
  155. package/chunks/{enterPlanMode-YQFNNSUA.js → enterPlanMode-56YYO52U.js} +41 -25
  156. package/chunks/{errors-LS7XU5DZ.js → errors-EO4SXCFP.js} +33 -27
  157. package/chunks/{exit-worktree-E2FTNSBK.js → exit-worktree-UDM7E6XH.js} +31 -25
  158. package/chunks/{exitPlanMode-GLYK2BUB.js → exitPlanMode-M6P3AWLJ.js} +149 -33
  159. package/chunks/{fast-path-WQ6M7LI7.js → fast-path-42P4QYWI.js} +33 -14
  160. package/chunks/{fast-path-settings-OAGU3X5H.js → fast-path-settings-UQLRFDQP.js} +2 -2
  161. package/chunks/{fr-BN5NKSAC.js → fr-MBMNQSQ6.js} +10 -9
  162. package/chunks/{gemini-2YFLVA2M.js → gemini-NRLXS5J7.js} +84 -70
  163. package/chunks/{geminiContentGenerator-XV6SV6CD.js → geminiContentGenerator-DLJPYYPA.js} +41 -5
  164. package/chunks/{glob-2H6CDDMK.js → glob-JPY3F74Y.js} +31 -25
  165. package/chunks/{grep-VXIUXM3C.js → grep-HW23YES5.js} +31 -25
  166. package/chunks/initializer-HWOZTC4A.js +67 -0
  167. package/chunks/{ja-7DEUB2TS.js → ja-HFV5QCHR.js} +10 -9
  168. package/chunks/{keychain-token-storage-YLMDLKXT.js → keychain-token-storage-GPAKRDKQ.js} +2 -2
  169. package/chunks/list-OZGAGRDG.js +71 -0
  170. package/chunks/loadedSettingsAdapter-RUTZVVIA.js +66 -0
  171. package/chunks/{loop-wakeup-CITGGQHA.js → loop-wakeup-G2EHBRGR.js} +5 -5
  172. package/chunks/{ls-R5WP4BGZ.js → ls-IDHUVSAG.js} +4 -4
  173. package/chunks/{lsp-GSICJMMW.js → lsp-FSRYXGFT.js} +2 -2
  174. package/chunks/{monitor-HKLRS2HQ.js → monitor-QVWEIXU3.js} +33 -26
  175. package/chunks/nonInteractiveCli-RV2WYPML.js +109 -0
  176. package/chunks/{notebook-edit-Y6SKSGTT.js → notebook-edit-B26W3FFH.js} +37 -34
  177. package/chunks/{openaiContentGenerator-J7G2FYJT.js → openaiContentGenerator-6TH7AZGQ.js} +15 -13
  178. package/chunks/pidfile-KW2QQJZI.js +73 -0
  179. package/chunks/{pt-TNZRNLQB.js → pt-2THT3YHA.js} +10 -9
  180. package/chunks/{qwenContentGenerator-5XIEM5GV.js → qwenContentGenerator-5IQAC7RN.js} +33 -27
  181. package/chunks/{qwenOAuth2-AG3PFFLZ.js → qwenOAuth2-LWLA6MQG.js} +5 -4
  182. package/chunks/{read-file-J7D552ZJ.js → read-file-CWFAHOI2.js} +11 -10
  183. package/chunks/{read-mcp-resource-DQQW7H7T.js → read-mcp-resource-PIJF24RO.js} +2 -2
  184. package/chunks/ripGrep-FTZGDKY4.js +60 -0
  185. package/chunks/{ru-NIAUBKCN.js → ru-Z67YJHBG.js} +10 -9
  186. package/chunks/{run-qwen-serve-SGEEVMXD.js → run-qwen-serve-FN2SW5ZI.js} +545 -97
  187. package/chunks/{scheduler-7CQI3S4Q.js → scheduler-BMS23O3I.js} +31 -25
  188. package/chunks/{send-message-EE4TWKVU.js → send-message-33PYFMCT.js} +20 -4
  189. package/chunks/serve-PXFYKL65.js +71 -0
  190. package/chunks/{server-4QMUWXPW.js → server-BRKALJ4F.js} +4132 -1175
  191. package/chunks/{session-NRO7UFOY.js → session-AQMISBP4.js} +205 -64
  192. package/chunks/{settings-SGWRDQSC.js → settings-JCPVUZMB.js} +35 -29
  193. package/chunks/{shell-62ANGIHL.js → shell-POHCRVN2.js} +31 -25
  194. package/chunks/{skill-VWAQAWW6.js → skill-QPEVHS6H.js} +13 -12
  195. package/chunks/spawnChannel-V3QT62TE.js +69 -0
  196. package/chunks/{src-KUV5J5Q2.js → src-IZSP7L6Y.js} +127 -32
  197. package/chunks/{startInteractiveUI-6EYJN3JV.js → startInteractiveUI-63KATISO.js} +16762 -16075
  198. package/chunks/{syntheticOutput-T5YHQ6S2.js → syntheticOutput-YOSWIHDJ.js} +3 -3
  199. package/chunks/{task-create-BLY7RHXX.js → task-create-NHS2NGB3.js} +9 -7
  200. package/chunks/{task-list-3QUYNVYR.js → task-list-5UIB564R.js} +7 -6
  201. package/chunks/{task-stop-U4RATK2V.js → task-stop-HGXZ2VZ3.js} +2 -2
  202. package/chunks/{task-update-U54O7KJX.js → task-update-IYYWUILG.js} +40 -7
  203. package/chunks/{team-create-LPOGCPM7.js → team-create-E5O2F3CA.js} +31 -25
  204. package/chunks/{team-delete-LKBYPASD.js → team-delete-FEKJCU4P.js} +7 -6
  205. package/chunks/team-plan-approval-2TU4YROB.js +202 -0
  206. package/chunks/theme-manager-37KOGPJL.js +64 -0
  207. package/chunks/{todoWrite-OYXKTVYN.js → todoWrite-TKMVZ2HT.js} +4 -4
  208. package/chunks/{tool-search-YPUFJ3ZQ.js → tool-search-4ZTGNSFI.js} +38 -11
  209. package/chunks/{trustedFolders-5B24TMEA.js → trustedFolders-RJ5WXJ6L.js} +32 -26
  210. package/chunks/{validateNonInterActiveAuth-BTDTYOVT.js → validateNonInterActiveAuth-ZWMHZAOK.js} +66 -55
  211. package/chunks/{web-fetch-EEB5LZYU.js → web-fetch-J4PIW36Q.js} +5 -4
  212. package/chunks/{workflow-LAWIW5LI.js → workflow-6PG2PC5M.js} +68 -39
  213. package/chunks/workspace-providers-status-4QIZN2W4.js +68 -0
  214. package/chunks/workspace-service-CYMCOEIO.js +78 -0
  215. package/chunks/{write-file-PCV226DJ.js → write-file-R354LGQF.js} +41 -40
  216. package/chunks/{zh-5EUYXASN.js → zh-SLZNSSZB.js} +32 -10
  217. package/chunks/{zh-TW-TR3XYGE5.js → zh-TW-P53C2SL5.js} +32 -10
  218. package/cli.js +6 -6
  219. package/locales/ca.js +15 -13
  220. package/locales/de.js +15 -13
  221. package/locales/en.js +52 -15
  222. package/locales/fr.js +15 -14
  223. package/locales/ja.js +15 -14
  224. package/locales/pt.js +15 -13
  225. package/locales/ru.js +15 -13
  226. package/locales/zh-TW.js +50 -14
  227. package/locales/zh.js +50 -14
  228. package/node_modules/@qwen-code/audio-capture/package.json +1 -1
  229. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
  230. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
  231. package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
  232. package/package.json +15 -6
  233. package/patches/chrome-devtools-mcp+1.4.0.patch +31 -0
  234. package/postinstall.js +50 -0
  235. package/web-shell/assets/{arc-DA7r8Ueo.js → arc-Bd3048nX.js} +1 -1
  236. package/web-shell/assets/{architectureDiagram-3BPJPVTR-ZDUxPtZ2.js → architectureDiagram-3BPJPVTR-DyzbzABx.js} +1 -1
  237. package/web-shell/assets/{blockDiagram-GPEHLZMM-vrtOf1kJ.js → blockDiagram-GPEHLZMM-CTjxm9Sy.js} +1 -1
  238. package/web-shell/assets/{c4Diagram-AAUBKEIU-BHFjzIi4.js → c4Diagram-AAUBKEIU-DSOFWNU6.js} +1 -1
  239. package/web-shell/assets/channel-oVoup_Ci.js +1 -0
  240. package/web-shell/assets/{chunk-2J33WTMH-mdeQVz59.js → chunk-2J33WTMH-D_PFdjo2.js} +1 -1
  241. package/web-shell/assets/{chunk-4BX2VUAB-BkKMlwBX.js → chunk-4BX2VUAB-52eG6wOT.js} +1 -1
  242. package/web-shell/assets/{chunk-55IACEB6-B7bnXNfu.js → chunk-55IACEB6-CGTZfKkC.js} +1 -1
  243. package/web-shell/assets/{chunk-727SXJPM-DGz8Mm6i.js → chunk-727SXJPM-CZ-qfRUm.js} +1 -1
  244. package/web-shell/assets/{chunk-AQP2D5EJ-BQAydUNk.js → chunk-AQP2D5EJ-B2dSDcqM.js} +1 -1
  245. package/web-shell/assets/{chunk-FMBD7UC4-GHr2LN_p.js → chunk-FMBD7UC4-Cfy3tyA0.js} +1 -1
  246. package/web-shell/assets/{chunk-ND2GUHAM-7R91lnUx.js → chunk-ND2GUHAM-CApNUpUq.js} +1 -1
  247. package/web-shell/assets/{chunk-QZHKN3VN-aTJD3lSQ.js → chunk-QZHKN3VN-CVBG8kgg.js} +1 -1
  248. package/web-shell/assets/classDiagram-4FO5ZUOK-B8WsaT2G.js +1 -0
  249. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-B8WsaT2G.js +1 -0
  250. package/web-shell/assets/{cose-bilkent-S5V4N54A-BTf8t1RL.js → cose-bilkent-S5V4N54A-URd77-_-.js} +1 -1
  251. package/web-shell/assets/{dagre-BM42HDAG-_sgp3WuA.js → dagre-BM42HDAG-C07H4G9-.js} +1 -1
  252. package/web-shell/assets/{diagram-2AECGRRQ-CROtRy1w.js → diagram-2AECGRRQ-CYbpXrSn.js} +1 -1
  253. package/web-shell/assets/{diagram-5GNKFQAL-BqGRzwSc.js → diagram-5GNKFQAL-SI8s6fjX.js} +1 -1
  254. package/web-shell/assets/{diagram-KO2AKTUF-CMrcEtA7.js → diagram-KO2AKTUF-mBkC4RTW.js} +1 -1
  255. package/web-shell/assets/{diagram-LMA3HP47-BRydGNW5.js → diagram-LMA3HP47-CyBPDzWJ.js} +1 -1
  256. package/web-shell/assets/{diagram-OG6HWLK6-D0ilgNjV.js → diagram-OG6HWLK6-DwK7kBCu.js} +1 -1
  257. package/web-shell/assets/{erDiagram-TEJ5UH35-2lnQeJUM.js → erDiagram-TEJ5UH35-Ds1StEUd.js} +1 -1
  258. package/web-shell/assets/{flowDiagram-I6XJVG4X-C_ZMdQiC.js → flowDiagram-I6XJVG4X-BDC4-jHO.js} +1 -1
  259. package/web-shell/assets/{ganttDiagram-6RSMTGT7-Dw9V_Ny0.js → ganttDiagram-6RSMTGT7-CV2aHQqf.js} +1 -1
  260. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-HDXI-F1B.js → gitGraphDiagram-PVQCEYII-B8RcuV_L.js} +1 -1
  261. package/web-shell/assets/index-B5WZ0qP1.js +717 -0
  262. package/web-shell/assets/index-CYE1IMd1.css +5 -0
  263. package/web-shell/assets/{infoDiagram-5YYISTIA-CuB8Ebua.js → infoDiagram-5YYISTIA-DUPoTf50.js} +1 -1
  264. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-D_tyhVwh.js → ishikawaDiagram-YF4QCWOH-FDYOx9rf.js} +1 -1
  265. package/web-shell/assets/{journeyDiagram-JHISSGLW-CgCwJQNU.js → journeyDiagram-JHISSGLW-C5_ohMRp.js} +1 -1
  266. package/web-shell/assets/{kanban-definition-UN3LZRKU-PZUtcbPx.js → kanban-definition-UN3LZRKU-Bn4UnOMG.js} +1 -1
  267. package/web-shell/assets/{linear-CZqRdJIU.js → linear-Bl0pKQtY.js} +1 -1
  268. package/web-shell/assets/{mermaid.core-CPW_4UEF.js → mermaid.core-sevQFoji.js} +72 -72
  269. package/web-shell/assets/{mindmap-definition-RKZ34NQL-D_Y75ID7.js → mindmap-definition-RKZ34NQL-DSH4JZF9.js} +1 -1
  270. package/web-shell/assets/{pieDiagram-4H26LBE5-Q4dTyLeF.js → pieDiagram-4H26LBE5-acWvdQTD.js} +1 -1
  271. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-ckw329Ft.js → quadrantDiagram-W4KKPZXB-DlggX4Sm.js} +1 -1
  272. package/web-shell/assets/{requirementDiagram-4Y6WPE33-DbVDm4It.js → requirementDiagram-4Y6WPE33--mMqwmV8.js} +1 -1
  273. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-CHuZ_ecH.js → sankeyDiagram-5OEKKPKP-BtV9tZ77.js} +1 -1
  274. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DU2YSpq-.js → sequenceDiagram-3UESZ5HK-iDQzPFlj.js} +1 -1
  275. package/web-shell/assets/{stateDiagram-AJRCARHV-CA9PEBUo.js → stateDiagram-AJRCARHV-CsCyQLZ3.js} +1 -1
  276. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CPapECG9.js +1 -0
  277. package/web-shell/assets/{timeline-definition-PNZ67QCA-Bhlo4WVc.js → timeline-definition-PNZ67QCA-Dl0rnKvr.js} +1 -1
  278. package/web-shell/assets/{vennDiagram-CIIHVFJN-6xtPLsyl.js → vennDiagram-CIIHVFJN-qF7nTZzA.js} +1 -1
  279. package/web-shell/assets/{wardley-L42UT6IY-3eozmXPf.js → wardley-L42UT6IY-fWoK9i7F.js} +1 -1
  280. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-BOn6hKss.js → wardleyDiagram-YWT4CUSO-pHGfkMnc.js} +1 -1
  281. package/web-shell/assets/{xychartDiagram-2RQKCTM6-BsP4-I_y.js → xychartDiagram-2RQKCTM6-3Doc4Trz.js} +1 -1
  282. package/web-shell/index.html +18 -2
  283. package/chunks/MaxSizedBox-QNF3EIGU.js +0 -63
  284. package/chunks/agent-headless-RQ5BTX3G.js +0 -56
  285. package/chunks/bridge-JL2PMCIW.js +0 -66
  286. package/chunks/chunk-5GOVVXEV.js +0 -73
  287. package/chunks/chunk-BC3C4F3Q.js +0 -40
  288. package/chunks/chunk-BW4KCQFD.js +0 -1103
  289. package/chunks/chunk-RKIZXJMB.js +0 -13
  290. package/chunks/contextCommand-WYU6OQ2F.js +0 -61
  291. package/chunks/daemon-status-provider-HH2EC5FI.js +0 -65
  292. package/chunks/headlessSafetyWarnings-TBE35GJ4.js +0 -55
  293. package/chunks/initializer-2Y7SLOKV.js +0 -61
  294. package/chunks/list-ZAFHZ7OS.js +0 -65
  295. package/chunks/loadedSettingsAdapter-6KJXD6M3.js +0 -60
  296. package/chunks/nonInteractiveCli-5W4GIZQM.js +0 -96
  297. package/chunks/ripGrep-IEIFIWP4.js +0 -54
  298. package/chunks/serve-V6GVZR6U.js +0 -65
  299. package/chunks/spawnChannel-3VHW5EPY.js +0 -63
  300. package/chunks/theme-manager-LYLGAERF.js +0 -58
  301. package/chunks/workspace-providers-status-PIAFVYHA.js +0 -62
  302. package/chunks/workspace-service-YAIOD4HG.js +0 -71
  303. package/web-shell/assets/channel-iRo68q4Q.js +0 -1
  304. package/web-shell/assets/classDiagram-4FO5ZUOK-iHF24a8X.js +0 -1
  305. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-iHF24a8X.js +0 -1
  306. package/web-shell/assets/index-CHmzAWys.css +0 -5
  307. package/web-shell/assets/index-w6GTOHh1.js +0 -713
  308. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-t1LRI0oY.js +0 -1
@@ -0,0 +1,416 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Qwen
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import * as path from 'node:path';
8
+ import { tildeifyPath } from '../../../utils/paths.js';
9
+ import {
10
+ LOOP_TASK_FILE_MAX_BYTES,
11
+ readLoopTaskFile,
12
+ type LoopTaskFileSource,
13
+ } from './loop-task-file.js';
14
+ import {
15
+ AUTONOMOUS_PREAMBLE,
16
+ AUTONOMOUS_PREAMBLE_MARKER,
17
+ CRON_REARM,
18
+ autonomousTickText,
19
+ keepAliveRearm,
20
+ type LoopMode,
21
+ } from './autonomous-loop.js';
22
+
23
+ export {
24
+ AUTONOMOUS_SENTINEL_CRON,
25
+ AUTONOMOUS_SENTINEL_DYNAMIC,
26
+ AutonomousLoopTickResolver,
27
+ detectAutonomousSentinel,
28
+ } from './autonomous-loop.js';
29
+ export type { LoopMode } from './autonomous-loop.js';
30
+
31
+ /**
32
+ * Fire-time resolver for `.qwen/loop.md`-driven loops.
33
+ *
34
+ * A `/loop` whose scheduled prompt is one of these sentinels re-reads loop.md
35
+ * on every fire and gets either the FULL task block (first delivery, or whenever
36
+ * the file changed) or a one-line SHORT reminder (unchanged) — so the task list
37
+ * is paid for once into the cached message-prefix and later ticks stay cheap.
38
+ *
39
+ * Divergence from the upstream design this mirrors: the `lastContent` cache is
40
+ * held per Session instance (not a module singleton) so it scopes to one
41
+ * conversation and resets cleanly with that conversation's context (compaction).
42
+ * Change-detection is full content equality, not mtime/hash, so edit and
43
+ * delete→recreate both re-expand for free.
44
+ */
45
+
46
+ export const LOOP_SENTINEL_CRON = '<<loop.md>>';
47
+ export const LOOP_SENTINEL_DYNAMIC = '<<loop.md-dynamic>>';
48
+
49
+ export interface LoopTickResolverDeps {
50
+ /** Pass `config.getWorkingDir()` — loop.md is resolved against the cwd. */
51
+ projectRoot: string;
52
+ /** Home-candidate confinement root: `$QWEN_HOME` when set, else `$HOME`. */
53
+ homeDir: string;
54
+ /**
55
+ * QWEN_HOME-aware global dir holding the home `loop.md` (`Storage.getGlobalQwenDir()`).
56
+ * Omitted → defaults to `<homeDir>/.qwen` inside readLoopTaskFile.
57
+ */
58
+ homeQwenDir?: string;
59
+ /**
60
+ * Pass `() => config.isTrustedFolder()`. Re-evaluated on every `resolve()`,
61
+ * never captured once: `isTrustedFolder()` is not process-stable in IDE
62
+ * sessions (a workspace-trust update can flip it), and a trusted→untrusted
63
+ * flip must immediately stop reading the repo-controlled project
64
+ * `.qwen/loop.md` (the user-owned `~/.qwen/loop.md` still is read).
65
+ */
66
+ allowProjectFile: () => boolean;
67
+ }
68
+
69
+ export interface LoopTickResult {
70
+ /** Text to deliver to the model in place of the sentinel prompt. */
71
+ modelText: string;
72
+ /** True when the full task block was delivered (vs a short reminder). */
73
+ full: boolean;
74
+ /** Non-absolute label for the matched candidate (e.g. "project loop.md"),
75
+ * when present — safe for logs/UI that must not leak the absolute path, and
76
+ * doubles as the "a loop.md was found" flag for callers. */
77
+ sourceLabel?: string;
78
+ /** True ONLY for buildTransientErrorTick: a loop.md exists but could not be
79
+ * read THIS tick (a transient EACCES/EIO or editor/AV lock), as distinct from
80
+ * the genuinely-absent no-op (where this stays false). Lets the caller's echo
81
+ * say "temporarily unavailable" instead of "not present". Carries no errno or
82
+ * path — those stay in the modelText note and LOCAL debug logs only. */
83
+ transientError?: boolean;
84
+ /** True when this tick is an autonomous-mode tick (a `<<autonomous-loop*>>`
85
+ * fire, or a loop.md sentinel whose file is gone and has converged on the
86
+ * autonomous preamble). Lets the caller's echo label it distinctly. */
87
+ autonomous?: boolean;
88
+ }
89
+
90
+ const TRUNCATION_WARNING = `> WARNING: loop.md was truncated to ${LOOP_TASK_FILE_MAX_BYTES} bytes. Keep the task list concise.`;
91
+
92
+ const INTRO =
93
+ 'The user configured a loop-tasks file. Work through the tasks defined below; these are the instructions for this tick and every subsequent tick (the reminder on later fires refers back to this message).';
94
+
95
+ // Mode-specific pacing guidance. Appended to BOTH the full block and the short
96
+ // reminder — the no-op/re-arm instruction applies on every tick.
97
+ const PACING_SUFFIX: Record<LoopMode, string> = {
98
+ cron: CRON_REARM,
99
+ dynamic: `You scheduled this tick via LoopWakeup (not a recurring cron). To keep the loop alive, call LoopWakeup again at the end of this turn with prompt set to the literal sentinel \`${LOOP_SENTINEL_DYNAMIC}\` — otherwise the loop ends after this tick.`,
100
+ };
101
+
102
+ // Preamble for the UNCHANGED-tick reminder, which points back to the full block
103
+ // delivered on an earlier fire. NOT used on the first/changed full delivery,
104
+ // where the block is present in THIS message — there is no "earlier" to refer
105
+ // back to, so claiming the contents were established earlier would contradict
106
+ // the INTRO that sits right above them.
107
+ const SHORT_REMINDER_PREAMBLE =
108
+ 'Work the tasks from the loop.md contents established earlier in this conversation. If you cannot find them, treat this as a no-op tick.';
109
+
110
+ /**
111
+ * The single H1 for every tick variant (full block, short reminder, absent), so
112
+ * they share one heading style and the dynamic-pacing suffix lives in one place.
113
+ * `sourceLabel` (set only on a full-block delivery) is a relative label like
114
+ * "project loop.md", never the absolute path — so the resolved file location
115
+ * isn't leaked to the model/API provider.
116
+ */
117
+ function tickHeading(
118
+ mode: LoopMode,
119
+ opts: { sourceLabel?: string; absent?: boolean; unavailable?: boolean } = {},
120
+ ): string {
121
+ // `unavailable` (transient read failure) is distinct from `absent`: the file
122
+ // exists but couldn't be read THIS tick, so the heading must not claim it's gone.
123
+ const subject = opts.unavailable
124
+ ? 'loop.md unavailable'
125
+ : opts.absent
126
+ ? 'loop.md absent'
127
+ : opts.sourceLabel
128
+ ? `loop.md tasks from ${opts.sourceLabel}`
129
+ : 'loop.md tasks';
130
+ const base = `# /loop tick — ${subject}`;
131
+ return mode === 'dynamic' ? `${base} (dynamic pacing)` : base;
132
+ }
133
+
134
+ /** Model-safe relative label per source — exhaustive, so a new loop.md
135
+ * candidate added to readLoopTaskFile won't compile until it gets a label
136
+ * (rather than silently mislabelling it). */
137
+ const SOURCE_LABELS: Record<LoopTaskFileSource, string> = {
138
+ project: 'project loop.md',
139
+ home: 'home loop.md',
140
+ };
141
+
142
+ // Per-mode tail for a TRANSIENT-failure no-op tick (buildTransientErrorTick):
143
+ // "treat this as a no-op" + the mode's re-arm. A genuinely-absent loop.md does
144
+ // NOT use this — it converges on absentAutonomousTickText (run the autonomous
145
+ // check, not a no-op).
146
+ const ABSENT_TAIL: Record<LoopMode, string> = {
147
+ cron: 'Treat this as a no-op tick; the recurring cron fires the next tick automatically.',
148
+ dynamic: `Treat this as a no-op tick. To pick it up if it is recreated, call LoopWakeup again with prompt set to the literal sentinel \`${LOOP_SENTINEL_DYNAMIC}\` — otherwise the loop ends after this tick.`,
149
+ };
150
+
151
+ /** Detect whether a scheduled prompt is a loop.md sentinel, and which mode. */
152
+ export function detectLoopSentinel(prompt: string): LoopMode | null {
153
+ const trimmed = prompt.trim();
154
+ if (trimmed === LOOP_SENTINEL_DYNAMIC) {
155
+ return 'dynamic';
156
+ }
157
+ if (trimmed === LOOP_SENTINEL_CRON) {
158
+ return 'cron';
159
+ }
160
+ return null;
161
+ }
162
+
163
+ // Shared self-paced re-arm instruction; the loop.md and autonomous dynamic ticks
164
+ // differ only in the sentinel the model re-arms with, so build both from one
165
+ // template to keep them in lockstep.
166
+ // `keepAliveRearm` itself lives in autonomous-loop.ts so the interactive TUI
167
+ // path can expand autonomous sentinels without importing loop.md file readers.
168
+
169
+ // Re-arm guidance for an absent-loop.md tick that has converged on autonomous
170
+ // mode: re-arm the LOOP.MD sentinel (not the autonomous one) so a recreated file
171
+ // is picked up on the next fire.
172
+ const ABSENT_AUTONOMOUS_REARM: Record<LoopMode, string> = {
173
+ cron: PACING_SUFFIX.cron,
174
+ dynamic: keepAliveRearm(
175
+ LOOP_SENTINEL_DYNAMIC,
176
+ 'To pick up loop.md if it is recreated',
177
+ ),
178
+ };
179
+
180
+ /** The tick text for an absent loop.md that converges on autonomous mode — like
181
+ * a pure autonomous tick but headed "loop.md absent" and re-arming the loop.md
182
+ * sentinel so a recreated file is picked up. It says "run the autonomous check",
183
+ * NOT an unconditional no-op: the no-op wording would contradict the preamble
184
+ * prepended on the first fire (and the dedup tick that follows it). */
185
+ function absentAutonomousTickText(mode: LoopMode, locations: string): string {
186
+ return `${tickHeading(mode, { absent: true })}\nloop.md is not currently present at ${locations}. Run the autonomous check using the loop instructions established earlier in this conversation. If you cannot find them, treat this as a no-op tick and stop immediately. ${ABSENT_AUTONOMOUS_REARM[mode]}`;
187
+ }
188
+
189
+ /** Trim a truncated body back to its last full line before the warning tail. */
190
+ function cutToLastNewline(content: string): string {
191
+ const cut = content.lastIndexOf('\n');
192
+ // `> 0`, not `>= 0`: when the only newline is at index 0 (or there is none),
193
+ // there is no complete line to keep, so cutting would empty the body and leave
194
+ // the INTRO promising tasks that aren't there. Keep the (truncated) content
195
+ // instead — only a genuine trailing partial line (newline at index > 0) is
196
+ // dropped so the warning never glues onto a half-line.
197
+ return cut > 0 ? content.slice(0, cut) : content;
198
+ }
199
+
200
+ export class LoopTickResolver {
201
+ // What the model has actually received. Drives full-vs-reminder detection.
202
+ #lastContent: string | typeof AUTONOMOUS_PREAMBLE_MARKER | null = null;
203
+ // The most recent resolve()'s content, committed to #lastContent only once
204
+ // the caller confirms it reached the model (markDelivered) — so a tick that
205
+ // is aborted between resolve() and delivery can't poison the cache into
206
+ // sending a dangling short reminder next time.
207
+ #pendingContent: string | typeof AUTONOMOUS_PREAMBLE_MARKER | null = null;
208
+ // Instance-scoped fs.realpath cache for the confinement boundaries, handed to
209
+ // readLoopTaskFile. Tying it to the resolver (a fresh Map per /cd rebuild,
210
+ // cleared by resetCache) keeps the per-tick perf win while staying
211
+ // invalidatable — a module-global cache would pin a stale boundary in a
212
+ // long-lived process after a /cd or symlink re-point.
213
+ readonly #realDirCache = new Map<string, Promise<string>>();
214
+
215
+ constructor(private readonly deps: LoopTickResolverDeps) {}
216
+
217
+ /** Forget the delivered content so the next fire re-delivers the full block
218
+ * — called when the conversation is compacted (fresh context). */
219
+ resetCache(): void {
220
+ this.#lastContent = null;
221
+ this.#pendingContent = null;
222
+ // A reset may follow a /cd or symlink change, so drop the cached boundary
223
+ // realpaths too and re-resolve them on the next tick.
224
+ this.#realDirCache.clear();
225
+ }
226
+
227
+ /** Commit the last resolve()'s content once it has reached the model. */
228
+ markDelivered(): void {
229
+ if (this.#pendingContent !== null) {
230
+ this.#lastContent = this.#pendingContent;
231
+ }
232
+ }
233
+
234
+ /** Expand an autonomous tick: the full preamble + tick text on the first
235
+ * delivery, then only the short tick text once the preamble was committed
236
+ * (markDelivered sets #lastContent to the shared marker). Shared by a pure
237
+ * autonomous fire and the absent-loop.md convergence in resolve(), so the
238
+ * preamble is delivered once across both. */
239
+ #autonomousTick(tickText: string): LoopTickResult {
240
+ // Set the marker in BOTH branches (like resolve() sets #pendingContent above
241
+ // its short/full split): the short branch must also refresh it, or a stale
242
+ // value left by a previously-aborted full tick would be committed by the next
243
+ // markDelivered() and poison a later fire into a dangling short reminder.
244
+ this.#pendingContent = AUTONOMOUS_PREAMBLE_MARKER;
245
+ if (this.#lastContent === AUTONOMOUS_PREAMBLE_MARKER) {
246
+ return { modelText: tickText, full: false, autonomous: true };
247
+ }
248
+ return {
249
+ modelText: `${AUTONOMOUS_PREAMBLE}\n${tickText}`,
250
+ full: true,
251
+ autonomous: true,
252
+ };
253
+ }
254
+
255
+ /** Resolve an autonomous-loop sentinel fire (a bare `/loop`, no loop.md).
256
+ * Synchronous — the preamble is static; only the dedup state is consulted. */
257
+ resolveAutonomous(mode: LoopMode): LoopTickResult {
258
+ return this.#autonomousTick(autonomousTickText(mode));
259
+ }
260
+
261
+ /** MODEL-FACING label for the home loop.md location. Mirrors
262
+ * readLoopTaskFile's home candidate (`<homeQwenDir>/loop.md`) so the absent
263
+ * reminder — and the caller's sanitized resolve-error — names the location
264
+ * actually checked (QWEN_HOME-aware), but must NEVER surface a raw absolute
265
+ * path: it flows into model/API text, leaking the host's filesystem layout.
266
+ * - under $HOME → tilde-abbreviated `~/.qwen/loop.md`;
267
+ * - relocated via $QWEN_HOME → the literal `$QWEN_HOME/loop.md`, not the
268
+ * resolved dir (`tildeifyPath` only abbreviates $HOME, so it's a no-op for
269
+ * a $QWEN_HOME outside $HOME and would otherwise pass the path through);
270
+ * - any other out-of-$HOME dir → a generic placeholder, never the path.
271
+ * The real absolute path stays in LOCAL debug logs only. */
272
+ homeLoopLabel(): string {
273
+ const homeQwenDir =
274
+ this.deps.homeQwenDir ?? path.join(this.deps.homeDir, '.qwen');
275
+ const homeLoopPath = path.join(homeQwenDir, 'loop.md');
276
+
277
+ const tildeified = tildeifyPath(homeLoopPath);
278
+ if (tildeified !== homeLoopPath) {
279
+ return tildeified.replace(/\\/g, '/');
280
+ }
281
+ // Outside $HOME: tildeifyPath was a no-op. When $QWEN_HOME relocated the
282
+ // global dir (homeQwenDir is its resolved value), report the literal env-var
283
+ // name — never the absolute path. The home candidate is always
284
+ // `<homeQwenDir>/loop.md`, so swap the whole resolved dir for `$QWEN_HOME` and
285
+ // re-attach the user-facing POSIX slash + basename directly. Deriving the tail from the
286
+ // resolved path's length instead mishandles edge dirs: a trailing slash
287
+ // (`$QWEN_HOME=/x/.qwen/`) over-counts the separator, and a filesystem-root
288
+ // homeQwenDir (`$QWEN_HOME=/` → homeLoopPath `/loop.md`, dirname `/`) drops the
289
+ // leading separator — both garbling the tail into `$QWEN_HOMEloop.md`.
290
+ if (process.env['QWEN_HOME']) {
291
+ return '$QWEN_HOME/loop.md';
292
+ }
293
+ return 'the configured global loop.md';
294
+ }
295
+
296
+ /** The checked-candidate "where" string shared by the absent reminder and the
297
+ * caller's sanitized resolve-error. Names the project candidate ONLY when it
298
+ * was actually read (`projectChecked` — a trusted folder), so neither path can
299
+ * claim `.qwen/loop.md (project)` for an untrusted folder where the project
300
+ * file is skipped. The home label is the QWEN_HOME-aware, never-absolute
301
+ * homeLoopLabel(). Single source of truth so the two messages can't drift. */
302
+ absentLocations(projectChecked: boolean): string {
303
+ const homeLabel = this.homeLoopLabel();
304
+ return projectChecked
305
+ ? `.qwen/loop.md (project) or ${homeLabel} (home)`
306
+ : `${homeLabel} (home)`;
307
+ }
308
+
309
+ /** A model-facing no-op tick for a loop.md that is unreadable THIS tick (a
310
+ * transient read failure — see buildTransientErrorTick). Clears the
311
+ * change-detection caches so a later successful tick re-delivers the FULL block
312
+ * instead of a dangling short reminder. A genuinely-absent loop.md no longer
313
+ * routes here — it converges on the autonomous preamble in resolve(). */
314
+ #noOpTick(modelText: string, transientError = false): LoopTickResult {
315
+ this.#pendingContent = null;
316
+ if (this.#lastContent !== AUTONOMOUS_PREAMBLE_MARKER) {
317
+ this.#lastContent = null;
318
+ }
319
+ return { modelText, full: false, transientError };
320
+ }
321
+
322
+ /**
323
+ * No-op tick for a transient, non-whitelisted read error (EACCES/EIO, or a
324
+ * Windows editor/AV briefly locking loop.md). Mirrors the absent tick — same
325
+ * heading + the mode's re-arm tail (ABSENT_TAIL) — so a `dynamic` loop still
326
+ * re-arms LoopWakeup and survives the hiccup instead of dying silently: its
327
+ * firing wakeup was already consumed by the scheduler, and only the
328
+ * end-of-turn re-arm keeps it alive, so a thrown turn ends the loop forever.
329
+ * `cron` callers don't use this (they re-fire on their own next interval).
330
+ * `projectChecked` is the trust captured for THIS tick (so the named candidate
331
+ * set matches what was probed); `code` is the errno only — never an absolute
332
+ * path — for a brief model-facing note.
333
+ */
334
+ buildTransientErrorTick(
335
+ mode: LoopMode,
336
+ projectChecked: boolean,
337
+ code: string,
338
+ ): LoopTickResult {
339
+ return this.#noOpTick(
340
+ // `unavailable`, not `absent`: the file exists but was unreadable this tick,
341
+ // so the heading mirrors the body instead of contradicting it.
342
+ `${tickHeading(mode, { unavailable: true })}\nloop.md at ${this.absentLocations(
343
+ projectChecked,
344
+ )} could not be read this tick (${code}). ${ABSENT_TAIL[mode]}`,
345
+ // Flag the tick as a transient read failure (file exists, unreadable this
346
+ // tick) so the caller's echo distinguishes it from a genuinely-absent file.
347
+ true,
348
+ );
349
+ }
350
+
351
+ /**
352
+ * @param allowProjectFileOverride Trust captured once by the caller for this
353
+ * tick (see LoopTickResolverDeps.allowProjectFile). Threaded in — rather than
354
+ * re-reading the getter here — so the caller's error path can name the SAME
355
+ * candidate set that was probed even if `isTrustedFolder()` flips mid-tick.
356
+ * Omitted by direct callers, who fall back to the per-tick getter.
357
+ */
358
+ async resolve(
359
+ mode: LoopMode,
360
+ allowProjectFileOverride?: boolean,
361
+ ): Promise<LoopTickResult> {
362
+ // Re-read trust per tick (see LoopTickResolverDeps.allowProjectFile): a
363
+ // resolver built while trusted must skip the project file once trust flips.
364
+ // Captured so the absent reminder reflects what was ACTUALLY checked.
365
+ const allowProjectFile =
366
+ allowProjectFileOverride ?? this.deps.allowProjectFile();
367
+ const result = await readLoopTaskFile({
368
+ projectRoot: this.deps.projectRoot,
369
+ homeDir: this.deps.homeDir,
370
+ homeQwenDir: this.deps.homeQwenDir,
371
+ allowProjectFile,
372
+ realDirCache: this.#realDirCache,
373
+ });
374
+
375
+ if (result.status === 'missing') {
376
+ // Absent loop.md converges on autonomous mode: prepend the autonomous
377
+ // preamble (once, deduped via the shared marker) so a file-less loop keeps
378
+ // working autonomously instead of no-op'ing forever. The tick text says
379
+ // "run the autonomous check" (NOT an unconditional no-op, which would
380
+ // contradict the prepended preamble) and keeps the loop.md-absent heading +
381
+ // a loop.md-sentinel re-arm so a recreated file is still picked up (its
382
+ // content can never equal the marker, so it re-delivers full).
383
+ return this.#autonomousTick(
384
+ absentAutonomousTickText(mode, this.absentLocations(allowProjectFile)),
385
+ );
386
+ }
387
+
388
+ const content = result.truncated
389
+ ? `${cutToLastNewline(result.content)}\n${TRUNCATION_WARNING}`
390
+ : result.content;
391
+ this.#pendingContent = content;
392
+
393
+ // Label by which candidate matched, never result.path (the absolute path),
394
+ // which would leak the OS username / dir layout to the API provider and to
395
+ // debug logs. The label alone is enough for the caller's UI and presence
396
+ // check, so the absolute path is not surfaced on the result at all.
397
+ const sourceLabel = SOURCE_LABELS[result.source];
398
+
399
+ if (this.#lastContent === content) {
400
+ return {
401
+ modelText: `${tickHeading(mode)}\n${SHORT_REMINDER_PREAMBLE} ${PACING_SUFFIX[mode]}`,
402
+ full: false,
403
+ sourceLabel,
404
+ };
405
+ }
406
+
407
+ // First/changed full delivery: INTRO + the block itself, then only the
408
+ // pacing suffix — no "established earlier" preamble, which would contradict
409
+ // the block sitting right here in this same message.
410
+ return {
411
+ modelText: `${tickHeading(mode, { sourceLabel })}\n${INTRO}\n${content}\n${PACING_SUFFIX[mode]}`,
412
+ full: true,
413
+ sourceLabel,
414
+ };
415
+ }
416
+ }
@@ -75,6 +75,13 @@ Use this index to locate the right document for the user's question. Load only t
75
75
  | Contextual tips | `docs/features/tips.md` |
76
76
  | Channels (Telegram/WeChat/DingTalk/etc.) | `docs/features/channels/overview.md` |
77
77
 
78
+ ### Daemon Mode
79
+
80
+ | Topic | Doc Path |
81
+ | --------------------------------- | --------------------------------- |
82
+ | qwen serve (daemon mode overview) | `docs/qwen-serve.md` |
83
+ | Local launch templates | `docs/qwen-serve-deploy-local.md` |
84
+
78
85
  ### IDE Integration
79
86
 
80
87
  | Topic | Doc Path |
@@ -111,11 +118,11 @@ When the user asks about configuration, the primary reference is `docs/configura
111
118
 
112
119
  ### Config File Locations & Priority
113
120
 
114
- | Level | Path | Description |
115
- | ------- | ------------------------------------------------------------ | -------------------------------------- |
116
- | User | `~/.qwen/settings.json` | Personal global config |
117
- | Project | `<project>/.qwen/settings.json` | Project-specific, overrides user level |
118
- | System | macOS: `/Library/Application Support/QwenCode/settings.json` | Admin-level config |
121
+ | Level | Path | Description |
122
+ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
123
+ | User | `~/.qwen/settings.json` | Personal global config |
124
+ | Project | `<project>/.qwen/settings.json` | Project-specific, overrides user level |
125
+ | System | Linux: `/etc/qwen-code/settings.json`<br>Windows: `C:\ProgramData\qwen-code\settings.json`<br>macOS: `/Library/Application Support/QwenCode/settings.json` | Admin-level config |
119
126
 
120
127
  **Priority** (highest to lowest): CLI args > env vars > system settings > project settings > user settings > defaults
121
128
 
@@ -165,7 +165,7 @@ The key concept is **Model Providers** (`modelProviders`): Qwen Code supports mu
165
165
 
166
166
  | Protocol | `modelProviders` key | Environment variables | Providers |
167
167
  | ----------------- | -------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
168
- | OpenAI-compatible | `openai` | `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_MODEL` | OpenAI, Azure OpenAI, OpenRouter, Requesty, ModelScope, Alibaba Cloud, any OpenAI-compatible endpoint |
168
+ | OpenAI-compatible | `openai` | `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_MODEL` (alias: `QWEN_MODEL`) | OpenAI, Azure OpenAI, OpenRouter, Requesty, ModelScope, Alibaba Cloud, any OpenAI-compatible endpoint |
169
169
  | Anthropic | `anthropic` | `ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL`, `ANTHROPIC_MODEL` | Anthropic Claude |
170
170
  | Google GenAI | `gemini` | `GEMINI_API_KEY`, `GEMINI_MODEL` | Google Gemini |
171
171
  | Vertex AI | `vertex-ai` | `GOOGLE_API_KEY`, `GOOGLE_MODEL` (sets `GOOGLE_GENAI_USE_VERTEXAI=true`; uses the `gemini` protocol) | Google Vertex AI |