@qwen-code/qwen-code 0.18.3 → 0.18.4

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 (508) hide show
  1. package/README.md +64 -492
  2. package/bundled/loop/SKILL.md +53 -26
  3. package/bundled/loop/SKILL.test.ts +67 -0
  4. package/bundled/qc-helper/docs/configuration/settings.md +25 -18
  5. package/bundled/qc-helper/docs/extension/introduction.md +38 -0
  6. package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
  7. package/bundled/qc-helper/docs/features/channels/overview.md +4 -4
  8. package/bundled/qc-helper/docs/features/channels/qqbot.md +179 -0
  9. package/bundled/qc-helper/docs/features/commands.md +49 -0
  10. package/bundled/qc-helper/docs/features/followup-suggestions.md +10 -6
  11. package/bundled/qc-helper/docs/features/hooks.md +6 -3
  12. package/bundled/qc-helper/docs/features/status-line.md +4 -2
  13. package/bundled/qc-helper/docs/qwen-serve.md +9 -4
  14. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +11 -5
  15. package/bundled/qc-helper/docs/support/troubleshooting.md +5 -0
  16. package/chunks/{agent-IBLZKOHM.js → agent-LYTC56HT.js} +24 -23
  17. package/chunks/{agent-headless-U3A2AQWP.js → agent-headless-FPUP5WHP.js} +24 -23
  18. package/chunks/{anthropicContentGenerator-KLBHYGH6.js → anthropicContentGenerator-OLOGBVLP.js} +4 -4
  19. package/chunks/{askUserQuestion-QPZXR3UO.js → askUserQuestion-ANRVSBIJ.js} +2 -2
  20. package/chunks/{ca-RK4QPLIX.js → ca-K6MD665I.js} +42 -2
  21. package/chunks/chunk-2ES3D3TW.js +1026 -0
  22. package/chunks/{chunk-O4PICXES.js → chunk-2MPVVENX.js} +14 -6
  23. package/chunks/{chunk-OY2G3EH4.js → chunk-32SSXBMG.js} +131009 -128408
  24. package/chunks/{chunk-BJ5HQ23U.js → chunk-4HMWGHPP.js} +9 -10
  25. package/chunks/{chunk-SFRV6BGY.js → chunk-4TW2JM5Q.js} +3 -3
  26. package/chunks/{chunk-C63NLV2Y.js → chunk-5RVEAAD2.js} +6 -6
  27. package/chunks/{chunk-K3CCX4PX.js → chunk-6Z2MVJIJ.js} +1046 -293
  28. package/chunks/{chunk-ZOFNJQNJ.js → chunk-7GX7XYZU.js} +3 -3
  29. package/chunks/{chunk-VIEIRAK3.js → chunk-7OCZ77KA.js} +4 -2
  30. package/chunks/{chunk-RTTAC5VW.js → chunk-AQDPHFDZ.js} +1 -1
  31. package/chunks/{chunk-IDYDPBBN.js → chunk-DZCZZPCY.js} +3 -3
  32. package/chunks/{chunk-ZMIBJS45.js → chunk-E5SRTXRG.js} +1 -1
  33. package/chunks/{chunk-FIQECJTQ.js → chunk-F6FP3URI.js} +1 -1
  34. package/chunks/{chunk-IQHSD7K5.js → chunk-FPZF3BNV.js} +1 -1
  35. package/chunks/{chunk-O2HKIE5I.js → chunk-GBTJHKQ6.js} +732 -617
  36. package/chunks/{chunk-NNIYWQIS.js → chunk-HU3RKEK2.js} +2 -1
  37. package/chunks/{chunk-HA2UEYZP.js → chunk-IKOWINH4.js} +7 -4
  38. package/chunks/{chunk-MN5RAXVB.js → chunk-IUEQOXOI.js} +18 -6
  39. package/chunks/{chunk-CPVI5J2L.js → chunk-JIJBNW4A.js} +1 -1
  40. package/chunks/{chunk-ZNUMXPNK.js → chunk-JJHY7NAD.js} +7 -3
  41. package/chunks/{chunk-YJDVHAGL.js → chunk-JN6FVOPP.js} +2 -2
  42. package/chunks/{chunk-VU6A2OBJ.js → chunk-JXQ23SNT.js} +217 -219
  43. package/chunks/{chunk-MSS4XTSL.js → chunk-LXUQBWQA.js} +6 -5
  44. package/chunks/{chunk-WPTCDQN6.js → chunk-M5VYHAHT.js} +2 -2
  45. package/chunks/{chunk-LXYWINWF.js → chunk-N5QHMPZU.js} +1 -1
  46. package/chunks/{chunk-LYSND7KR.js → chunk-PTGKSUUJ.js} +2 -2
  47. package/chunks/{chunk-MRULXYE3.js → chunk-SZWDOOGV.js} +24 -12
  48. package/chunks/{chunk-LYRSMKLS.js → chunk-VWPDSQZY.js} +2 -2
  49. package/chunks/{chunk-B4ZF2KSI.js → chunk-WWU2KUSR.js} +2 -2
  50. package/chunks/{chunk-QP4R5FTG.js → chunk-Z7XXFPGP.js} +4 -3
  51. package/chunks/{chunk-TW522KN6.js → chunk-ZTQ26VBE.js} +13 -6
  52. package/chunks/{computer-use-OEMCNYX5.js → computer-use-P4WQBATW.js} +24 -23
  53. package/chunks/contextCommand-POQ6GYN3.js +54 -0
  54. package/chunks/{cron-create-DQKRQMCP.js → cron-create-OKGQO6GX.js} +6 -6
  55. package/chunks/{cron-delete-DOFPHFTI.js → cron-delete-DTJP7L6O.js} +6 -6
  56. package/chunks/{cron-list-RCVOO3CB.js → cron-list-VKZUASFG.js} +24 -10
  57. package/chunks/{de-FGPM4KW5.js → de-K2F3T3TR.js} +41 -1
  58. package/chunks/{dist-2UCAYOX7.js → dist-BD27IA3L.js} +16 -5
  59. package/chunks/{dist-33LHH26D.js → dist-KIYB7DQW.js} +1 -1
  60. package/chunks/{dist-UH7CYT7F.js → dist-OLC6NBSB.js} +51 -10
  61. package/chunks/dist-QFFZWACU.js +2136 -0
  62. package/chunks/{dist-KF43SZZV.js → dist-QUSDBLAK.js} +1 -1
  63. package/chunks/{edit-HOHKMDP6.js → edit-CS7DSS4Z.js} +26 -27
  64. package/chunks/{en-VP6XPGEC.js → en-KGSAKBJP.js} +232 -0
  65. package/chunks/{enter-worktree-O2DGTKFY.js → enter-worktree-PA4HPHJK.js} +24 -23
  66. package/chunks/{enterPlanMode-FYHJD6AH.js → enterPlanMode-SFE5AFKZ.js} +47 -23
  67. package/chunks/{exit-worktree-TVTAKFIV.js → exit-worktree-FR3AZTC6.js} +191 -41
  68. package/chunks/{exitPlanMode-DL7XTFEC.js → exitPlanMode-AHOUO44D.js} +81 -43
  69. package/chunks/{fr-ATYBVCLT.js → fr-2CAQEOK6.js} +41 -1
  70. package/chunks/{geminiContentGenerator-2LLKQOJZ.js → geminiContentGenerator-AXCVDKGI.js} +4 -4
  71. package/chunks/{glob-DUCIKJZE.js → glob-BQPAW3IW.js} +26 -24
  72. package/chunks/{grep-A7CW7MHE.js → grep-2F7BL5TQ.js} +96 -43
  73. package/chunks/{ja-W2QEA2OI.js → ja-QWL7V6OJ.js} +41 -1
  74. package/chunks/{keychain-token-storage-QSTRHKKL.js → keychain-token-storage-ALKQXYJQ.js} +2 -2
  75. package/chunks/loop-wakeup-RX6YIUSG.js +167 -0
  76. package/chunks/{ls-TRD77UTS.js → ls-6PLNWHMU.js} +3 -3
  77. package/chunks/{lsp-2VFWQPZS.js → lsp-3HFQU4OF.js} +2 -2
  78. package/chunks/{monitor-PPSG4MWE.js → monitor-YTTMDFW2.js} +24 -23
  79. package/chunks/{notebook-edit-OQBMXIAC.js → notebook-edit-7TNZMTBR.js} +25 -26
  80. package/chunks/{openaiContentGenerator-JAHIGA7U.js → openaiContentGenerator-JA6YXXPI.js} +12 -11
  81. package/chunks/{pt-ZKEWJFBW.js → pt-2SPOLMAY.js} +41 -1
  82. package/chunks/{qwenContentGenerator-H357UGVE.js → qwenContentGenerator-NBOVGW7B.js} +26 -25
  83. package/chunks/{qwenOAuth2-KK433U33.js → qwenOAuth2-XWC5SU63.js} +4 -4
  84. package/chunks/{read-file-TQSF7AVG.js → read-file-RUBU3KUA.js} +9 -8
  85. package/chunks/{ripGrep-AI43PPZP.js → ripGrep-TPFC7KZF.js} +24 -23
  86. package/chunks/{ru-VEKTPJ74.js → ru-35IVJTEH.js} +41 -1
  87. package/chunks/{scheduler-R6AQPP7V.js → scheduler-NTVF45LR.js} +24 -23
  88. package/chunks/{send-message-QZOC5GA2.js → send-message-IIT3SHA7.js} +2 -2
  89. package/chunks/{serve-TH2BJ5XR.js → serve-J6VG37OX.js} +1249 -279
  90. package/chunks/{shell-C7AFLMP5.js → shell-EQQEHEFI.js} +24 -23
  91. package/chunks/{skill-RKVBRTPA.js → skill-QWRWJCQJ.js} +11 -10
  92. package/chunks/{src-IW53XETC.js → src-LNADIG5P.js} +137 -59
  93. package/chunks/{syntheticOutput-WJSUK4SZ.js → syntheticOutput-H67FYXU7.js} +3 -3
  94. package/chunks/{task-create-GGSC27HO.js → task-create-OVXHSHAI.js} +7 -7
  95. package/chunks/{task-list-EDHHHSK4.js → task-list-QUUCQJ3U.js} +6 -6
  96. package/chunks/{task-stop-WR5PDVZY.js → task-stop-WA5DMTKK.js} +2 -2
  97. package/chunks/{task-update-UR7NUHBV.js → task-update-PC5427TI.js} +7 -7
  98. package/chunks/{team-create-6F44EH3O.js → team-create-TXWQL777.js} +26 -25
  99. package/chunks/{team-delete-FC33URJK.js → team-delete-ZTEMYRJ3.js} +6 -6
  100. package/chunks/{todoWrite-GO2ME7ZV.js → todoWrite-J6L6ELD6.js} +4 -4
  101. package/chunks/{tool-search-WGNAYT43.js → tool-search-JAVM7ABF.js} +9 -8
  102. package/chunks/{web-fetch-NLLATYIL.js → web-fetch-6XLPPTP7.js} +5 -5
  103. package/chunks/{workflow-L5J5VGY4.js → workflow-7LN3L6KK.js} +242 -39
  104. package/chunks/{write-file-2FKBW3XN.js → write-file-DAKE7YKB.js} +26 -27
  105. package/chunks/{zh-TW-6YFNCKTA.js → zh-TW-BSG6BUWK.js} +232 -2
  106. package/chunks/{zh-OIXDDQHB.js → zh-X4KM6MTW.js} +233 -0
  107. package/cli.js +10735 -5708
  108. package/examples/agent/agents/diary.md +1 -1
  109. package/examples/mcp-server/qwen-extension.json +8 -1
  110. package/examples/starter/agents/diary.md +1 -1
  111. package/locales/ca.js +67 -2
  112. package/locales/de.js +68 -2
  113. package/locales/en.js +304 -0
  114. package/locales/fr.js +69 -2
  115. package/locales/ja.js +65 -2
  116. package/locales/pt.js +67 -2
  117. package/locales/ru.js +68 -2
  118. package/locales/zh-TW.js +288 -2
  119. package/locales/zh.js +288 -0
  120. package/package.json +4 -3
  121. package/web-shell/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  122. package/web-shell/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  123. package/web-shell/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  124. package/web-shell/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  125. package/web-shell/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  126. package/web-shell/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  127. package/web-shell/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  128. package/web-shell/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  129. package/web-shell/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  130. package/web-shell/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  131. package/web-shell/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  132. package/web-shell/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  133. package/web-shell/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  134. package/web-shell/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  135. package/web-shell/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  136. package/web-shell/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  137. package/web-shell/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  138. package/web-shell/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  139. package/web-shell/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  140. package/web-shell/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  141. package/web-shell/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  142. package/web-shell/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  143. package/web-shell/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  144. package/web-shell/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  145. package/web-shell/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  146. package/web-shell/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  147. package/web-shell/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  148. package/web-shell/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  149. package/web-shell/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  150. package/web-shell/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  151. package/web-shell/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  152. package/web-shell/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  153. package/web-shell/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  154. package/web-shell/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  155. package/web-shell/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  156. package/web-shell/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  157. package/web-shell/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  158. package/web-shell/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  159. package/web-shell/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  160. package/web-shell/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  161. package/web-shell/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  162. package/web-shell/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  163. package/web-shell/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  164. package/web-shell/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  165. package/web-shell/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  166. package/web-shell/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  167. package/web-shell/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  168. package/web-shell/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  169. package/web-shell/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  170. package/web-shell/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  171. package/web-shell/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  172. package/web-shell/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  173. package/web-shell/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  174. package/web-shell/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  175. package/web-shell/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  176. package/web-shell/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  177. package/web-shell/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  178. package/web-shell/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  179. package/web-shell/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  180. package/web-shell/assets/abap-DsBKuouk.js +1 -0
  181. package/web-shell/assets/actionscript-3-D_z4Izcz.js +1 -0
  182. package/web-shell/assets/ada-727ZlQH0.js +1 -0
  183. package/web-shell/assets/andromeeda-C3khCPGq.js +1 -0
  184. package/web-shell/assets/angular-html-LfdN0zeE.js +1 -0
  185. package/web-shell/assets/angular-ts-CKsD7JZE.js +1 -0
  186. package/web-shell/assets/apache-Dn00JSTd.js +1 -0
  187. package/web-shell/assets/apex-COJ4H7py.js +1 -0
  188. package/web-shell/assets/apl-BBq3IX1j.js +1 -0
  189. package/web-shell/assets/applescript-Bu5BbsvL.js +1 -0
  190. package/web-shell/assets/ara-7O62HKoU.js +1 -0
  191. package/web-shell/assets/arc-CRFN10gD.js +1 -0
  192. package/web-shell/assets/architectureDiagram-3BPJPVTR-IRlu1CpH.js +36 -0
  193. package/web-shell/assets/asciidoc-BPT9niGB.js +1 -0
  194. package/web-shell/assets/asm-Dhn9LcZ4.js +1 -0
  195. package/web-shell/assets/astro-CqkE3fuf.js +1 -0
  196. package/web-shell/assets/aurora-x-D-2ljcwZ.js +1 -0
  197. package/web-shell/assets/awk-eg146-Ew.js +1 -0
  198. package/web-shell/assets/ayu-dark-Cv9koXgw.js +1 -0
  199. package/web-shell/assets/ballerina-Du268qiB.js +1 -0
  200. package/web-shell/assets/bat-fje9CFhw.js +1 -0
  201. package/web-shell/assets/beancount-BwXTMy5W.js +1 -0
  202. package/web-shell/assets/berry-3xVqZejG.js +1 -0
  203. package/web-shell/assets/bibtex-xW4inM5L.js +1 -0
  204. package/web-shell/assets/bicep-DHo0CJ0O.js +1 -0
  205. package/web-shell/assets/blade-a8OxSdnT.js +1 -0
  206. package/web-shell/assets/blockDiagram-GPEHLZMM-htIZ6iw8.js +132 -0
  207. package/web-shell/assets/bsl-Dgyn0ogV.js +1 -0
  208. package/web-shell/assets/c-C3t2pwGQ.js +1 -0
  209. package/web-shell/assets/c4Diagram-AAUBKEIU-A2GoRq3O.js +10 -0
  210. package/web-shell/assets/cadence-DNquZEk8.js +1 -0
  211. package/web-shell/assets/cairo--RitsXJZ.js +1 -0
  212. package/web-shell/assets/catppuccin-frappe-CD_QflpE.js +1 -0
  213. package/web-shell/assets/catppuccin-latte-DRW-0cLl.js +1 -0
  214. package/web-shell/assets/catppuccin-macchiato-C-_shW-Y.js +1 -0
  215. package/web-shell/assets/catppuccin-mocha-LGGdnPYs.js +1 -0
  216. package/web-shell/assets/channel-WwImfsc7.js +1 -0
  217. package/web-shell/assets/chunk-2J33WTMH-CdP2AC6u.js +1 -0
  218. package/web-shell/assets/chunk-4BX2VUAB-DrA07nW2.js +1 -0
  219. package/web-shell/assets/chunk-55IACEB6-CFGnVU2f.js +1 -0
  220. package/web-shell/assets/chunk-727SXJPM-BTMkq3Tk.js +206 -0
  221. package/web-shell/assets/chunk-AQP2D5EJ-C9sYg04Z.js +231 -0
  222. package/web-shell/assets/chunk-FMBD7UC4-Cag-cj6I.js +15 -0
  223. package/web-shell/assets/chunk-ND2GUHAM-CDSTFoR7.js +1 -0
  224. package/web-shell/assets/chunk-QZHKN3VN-CN9Z6oOs.js +1 -0
  225. package/web-shell/assets/clarity-BHOwM8T6.js +1 -0
  226. package/web-shell/assets/classDiagram-4FO5ZUOK-CJKQYFeJ.js +1 -0
  227. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CJKQYFeJ.js +1 -0
  228. package/web-shell/assets/clojure-DxSadP1t.js +1 -0
  229. package/web-shell/assets/cmake-DbXoA79R.js +1 -0
  230. package/web-shell/assets/cobol-PTqiYgYu.js +1 -0
  231. package/web-shell/assets/codeowners-Bp6g37R7.js +1 -0
  232. package/web-shell/assets/codeql-sacFqUAJ.js +1 -0
  233. package/web-shell/assets/coffee-dyiR41kL.js +1 -0
  234. package/web-shell/assets/common-lisp-C7gG9l05.js +1 -0
  235. package/web-shell/assets/coq-Dsg_Bt_b.js +1 -0
  236. package/web-shell/assets/cose-bilkent-S5V4N54A-DuN9j8Du.js +1 -0
  237. package/web-shell/assets/cpp-BksuvNSY.js +1 -0
  238. package/web-shell/assets/crystal-DtDmRg-F.js +1 -0
  239. package/web-shell/assets/csharp-D9R-vmeu.js +1 -0
  240. package/web-shell/assets/css-BPhBrDlE.js +1 -0
  241. package/web-shell/assets/csv-B0qRVHPH.js +1 -0
  242. package/web-shell/assets/cue-DtFQj3wx.js +1 -0
  243. package/web-shell/assets/cypher-m2LEI-9-.js +1 -0
  244. package/web-shell/assets/cytoscape.esm-CUqq0XTU.js +331 -0
  245. package/web-shell/assets/d-BoXegm-a.js +1 -0
  246. package/web-shell/assets/dagre-BM42HDAG-ByCWe45f.js +4 -0
  247. package/web-shell/assets/dark-plus-C3mMm8J8.js +1 -0
  248. package/web-shell/assets/dart-B9wLZaAG.js +1 -0
  249. package/web-shell/assets/dax-ClGRhx96.js +1 -0
  250. package/web-shell/assets/defaultLocale-DX6XiGOO.js +1 -0
  251. package/web-shell/assets/desktop-DEIpsLCJ.js +1 -0
  252. package/web-shell/assets/diagram-2AECGRRQ-eWyU_pKZ.js +43 -0
  253. package/web-shell/assets/diagram-5GNKFQAL-0Bfu3Fq5.js +10 -0
  254. package/web-shell/assets/diagram-KO2AKTUF-B6KBKkQP.js +3 -0
  255. package/web-shell/assets/diagram-LMA3HP47-TToDmeA_.js +24 -0
  256. package/web-shell/assets/diagram-OG6HWLK6-CQCkC2Yx.js +24 -0
  257. package/web-shell/assets/diff-BgYniUM_.js +1 -0
  258. package/web-shell/assets/docker-COcR7UxN.js +1 -0
  259. package/web-shell/assets/dotenv-BjQB5zDj.js +1 -0
  260. package/web-shell/assets/dracula-BzJJZx-M.js +1 -0
  261. package/web-shell/assets/dracula-soft-BXkSAIEj.js +1 -0
  262. package/web-shell/assets/dream-maker-C-nORZOA.js +1 -0
  263. package/web-shell/assets/edge-D5gP-w-T.js +1 -0
  264. package/web-shell/assets/elixir-CLiX3zqd.js +1 -0
  265. package/web-shell/assets/elm-CmHSxxaM.js +1 -0
  266. package/web-shell/assets/emacs-lisp-BX77sIaO.js +1 -0
  267. package/web-shell/assets/erDiagram-TEJ5UH35-Cm9ls1iB.js +85 -0
  268. package/web-shell/assets/erb-BYTLMnw6.js +1 -0
  269. package/web-shell/assets/erlang-B-DoSBHF.js +1 -0
  270. package/web-shell/assets/everforest-dark-BgDCqdQA.js +1 -0
  271. package/web-shell/assets/everforest-light-C8M2exoo.js +1 -0
  272. package/web-shell/assets/fennel-bCA53EVm.js +1 -0
  273. package/web-shell/assets/fish-w-ucz2PV.js +1 -0
  274. package/web-shell/assets/flowDiagram-I6XJVG4X-Dyoz80Pv.js +162 -0
  275. package/web-shell/assets/fluent-Dayu4EKP.js +1 -0
  276. package/web-shell/assets/fortran-fixed-form-TqA4NnZg.js +1 -0
  277. package/web-shell/assets/fortran-free-form-DKXYxT9g.js +1 -0
  278. package/web-shell/assets/fsharp-XplgxFYe.js +1 -0
  279. package/web-shell/assets/ganttDiagram-6RSMTGT7-Cfut9yaU.js +292 -0
  280. package/web-shell/assets/gdresource-BHYsBjWJ.js +1 -0
  281. package/web-shell/assets/gdscript-DfxzS6Rs.js +1 -0
  282. package/web-shell/assets/gdshader-SKMF96pI.js +1 -0
  283. package/web-shell/assets/genie-ajMbGru0.js +1 -0
  284. package/web-shell/assets/gherkin--30QC5Em.js +1 -0
  285. package/web-shell/assets/git-commit-i4q6IMui.js +1 -0
  286. package/web-shell/assets/git-rebase-B-v9cOL2.js +1 -0
  287. package/web-shell/assets/gitGraphDiagram-PVQCEYII-BCuJdlfD.js +106 -0
  288. package/web-shell/assets/github-dark-DHJKELXO.js +1 -0
  289. package/web-shell/assets/github-dark-default-Cuk6v7N8.js +1 -0
  290. package/web-shell/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  291. package/web-shell/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  292. package/web-shell/assets/github-light-DAi9KRSo.js +1 -0
  293. package/web-shell/assets/github-light-default-D7oLnXFd.js +1 -0
  294. package/web-shell/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  295. package/web-shell/assets/gleam-B430Bg39.js +1 -0
  296. package/web-shell/assets/glimmer-js-D-cwc0-E.js +1 -0
  297. package/web-shell/assets/glimmer-ts-pgjy16dm.js +1 -0
  298. package/web-shell/assets/glsl-DBO2IWDn.js +1 -0
  299. package/web-shell/assets/gnuplot-CM8KxXT1.js +1 -0
  300. package/web-shell/assets/go-B1SYOhNW.js +1 -0
  301. package/web-shell/assets/graph-qsFoMdT2.js +1 -0
  302. package/web-shell/assets/graphql-cDcHW_If.js +1 -0
  303. package/web-shell/assets/groovy-DkBy-JyN.js +1 -0
  304. package/web-shell/assets/hack-D1yCygmZ.js +1 -0
  305. package/web-shell/assets/haml-B2EZWmdv.js +1 -0
  306. package/web-shell/assets/handlebars-BQGss363.js +1 -0
  307. package/web-shell/assets/haskell-BILxekzW.js +1 -0
  308. package/web-shell/assets/haxe-C5wWYbrZ.js +1 -0
  309. package/web-shell/assets/hcl-HzYwdGDm.js +1 -0
  310. package/web-shell/assets/hjson-T-Tgc4AT.js +1 -0
  311. package/web-shell/assets/hlsl-ifBTmRxC.js +1 -0
  312. package/web-shell/assets/houston-DnULxvSX.js +1 -0
  313. package/web-shell/assets/html-C2L_23MC.js +1 -0
  314. package/web-shell/assets/html-derivative-CSfWNPLT.js +1 -0
  315. package/web-shell/assets/http-FRrOvY1W.js +1 -0
  316. package/web-shell/assets/hxml-TIA70rKU.js +1 -0
  317. package/web-shell/assets/hy-BMj5Y0dO.js +1 -0
  318. package/web-shell/assets/imba-bv_oIlVt.js +1 -0
  319. package/web-shell/assets/index-BDZiTAkl.css +1 -0
  320. package/web-shell/assets/index-DaebdpHq.js +516 -0
  321. package/web-shell/assets/infoDiagram-5YYISTIA-CXKxF2VL.js +2 -0
  322. package/web-shell/assets/ini-BjABl1g7.js +1 -0
  323. package/web-shell/assets/init-Gi6I4Gst.js +1 -0
  324. package/web-shell/assets/ishikawaDiagram-YF4QCWOH-DE7HWSU8.js +70 -0
  325. package/web-shell/assets/java-xI-RfyKK.js +1 -0
  326. package/web-shell/assets/javascript-ySlJ1b_l.js +1 -0
  327. package/web-shell/assets/jinja-DGy0s7-h.js +1 -0
  328. package/web-shell/assets/jison-BqZprYcd.js +1 -0
  329. package/web-shell/assets/journeyDiagram-JHISSGLW-D__YUfds.js +139 -0
  330. package/web-shell/assets/json-BQoSv7ci.js +1 -0
  331. package/web-shell/assets/json5-w8dY5SsB.js +1 -0
  332. package/web-shell/assets/jsonc-TU54ms6u.js +1 -0
  333. package/web-shell/assets/jsonl-DREVFZK8.js +1 -0
  334. package/web-shell/assets/jsonnet-BfivnA6A.js +1 -0
  335. package/web-shell/assets/jssm-P4WzXJd0.js +1 -0
  336. package/web-shell/assets/jsx-BAng5TT0.js +1 -0
  337. package/web-shell/assets/julia-BBuGR-5E.js +1 -0
  338. package/web-shell/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  339. package/web-shell/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  340. package/web-shell/assets/kanagawa-wave-DWedfzmr.js +1 -0
  341. package/web-shell/assets/kanban-definition-UN3LZRKU-D82R169M.js +89 -0
  342. package/web-shell/assets/kotlin-B5lbUyaz.js +1 -0
  343. package/web-shell/assets/kusto-mebxcVVE.js +1 -0
  344. package/web-shell/assets/laserwave-DUszq2jm.js +1 -0
  345. package/web-shell/assets/latex-C-cWTeAZ.js +1 -0
  346. package/web-shell/assets/layout-CNYaLpI5.js +1 -0
  347. package/web-shell/assets/lean-XBlWyCtg.js +1 -0
  348. package/web-shell/assets/less-BfCpw3nA.js +1 -0
  349. package/web-shell/assets/light-plus-B7mTdjB0.js +1 -0
  350. package/web-shell/assets/linear-DpyMbKqT.js +1 -0
  351. package/web-shell/assets/liquid-D3W5UaiH.js +1 -0
  352. package/web-shell/assets/log-Cc5clBb7.js +1 -0
  353. package/web-shell/assets/logo-IuBKFhSY.js +1 -0
  354. package/web-shell/assets/lua-CvWAzNxB.js +1 -0
  355. package/web-shell/assets/luau-Du5NY7AG.js +1 -0
  356. package/web-shell/assets/make-Bvotw-X0.js +1 -0
  357. package/web-shell/assets/markdown-UIAJJxZW.js +1 -0
  358. package/web-shell/assets/marko-z0MBrx5-.js +1 -0
  359. package/web-shell/assets/material-theme-D5KoaKCx.js +1 -0
  360. package/web-shell/assets/material-theme-darker-BfHTSMKl.js +1 -0
  361. package/web-shell/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  362. package/web-shell/assets/material-theme-ocean-CyktbL80.js +1 -0
  363. package/web-shell/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  364. package/web-shell/assets/matlab-D9-PGadD.js +1 -0
  365. package/web-shell/assets/mdc-DB_EDNY_.js +1 -0
  366. package/web-shell/assets/mdx-sdHcTMYB.js +1 -0
  367. package/web-shell/assets/mermaid-Ci6OQyBP.js +1 -0
  368. package/web-shell/assets/mermaid.core-D1KEFDhn.js +309 -0
  369. package/web-shell/assets/min-dark-CafNBF8u.js +1 -0
  370. package/web-shell/assets/min-light-CTRr51gU.js +1 -0
  371. package/web-shell/assets/mindmap-definition-RKZ34NQL-BwVUFGFE.js +96 -0
  372. package/web-shell/assets/mipsasm-BC5c_5Pe.js +1 -0
  373. package/web-shell/assets/mojo-Tz6hzZYG.js +1 -0
  374. package/web-shell/assets/monokai-D4h5O-jR.js +1 -0
  375. package/web-shell/assets/move-DB_GagMm.js +1 -0
  376. package/web-shell/assets/narrat-DLbgOhZU.js +1 -0
  377. package/web-shell/assets/nextflow-B0XVJmRM.js +1 -0
  378. package/web-shell/assets/nginx-D_VnBJ67.js +1 -0
  379. package/web-shell/assets/night-owl-C39BiMTA.js +1 -0
  380. package/web-shell/assets/nim-ZlGxZxc3.js +1 -0
  381. package/web-shell/assets/nix-shcSOmrb.js +1 -0
  382. package/web-shell/assets/nord-Ddv68eIx.js +1 -0
  383. package/web-shell/assets/nushell-D4Tzg5kh.js +1 -0
  384. package/web-shell/assets/objective-c-Deuh7S70.js +1 -0
  385. package/web-shell/assets/objective-cpp-BUEGK8hf.js +1 -0
  386. package/web-shell/assets/ocaml-BNioltXt.js +1 -0
  387. package/web-shell/assets/one-dark-pro-GBQ2dnAY.js +1 -0
  388. package/web-shell/assets/one-light-PoHY5YXO.js +1 -0
  389. package/web-shell/assets/ordinal-Cboi1Yqb.js +1 -0
  390. package/web-shell/assets/pascal-JqZropPD.js +1 -0
  391. package/web-shell/assets/perl-CHQXSrWU.js +1 -0
  392. package/web-shell/assets/php-B5ebYQev.js +1 -0
  393. package/web-shell/assets/pieDiagram-4H26LBE5-BO_qoEGx.js +30 -0
  394. package/web-shell/assets/plastic-3e1v2bzS.js +1 -0
  395. package/web-shell/assets/plsql-LKU2TuZ1.js +1 -0
  396. package/web-shell/assets/po-BFLt1xDp.js +1 -0
  397. package/web-shell/assets/poimandres-CS3Unz2-.js +1 -0
  398. package/web-shell/assets/polar-DKykz6zU.js +1 -0
  399. package/web-shell/assets/postcss-B3ZDOciz.js +1 -0
  400. package/web-shell/assets/powerquery-CSHBycmS.js +1 -0
  401. package/web-shell/assets/powershell-BIEUsx6d.js +1 -0
  402. package/web-shell/assets/prisma-B48N-Iqd.js +1 -0
  403. package/web-shell/assets/prolog-BY-TUvya.js +1 -0
  404. package/web-shell/assets/proto-zocC4JxJ.js +1 -0
  405. package/web-shell/assets/pug-CM9l7STV.js +1 -0
  406. package/web-shell/assets/puppet-Cza_XSSt.js +1 -0
  407. package/web-shell/assets/purescript-Bg-kzb6g.js +1 -0
  408. package/web-shell/assets/python-DhUJRlN_.js +1 -0
  409. package/web-shell/assets/qml-D8XfuvdV.js +1 -0
  410. package/web-shell/assets/qmldir-C8lEn-DE.js +1 -0
  411. package/web-shell/assets/qss-DhMKtDLN.js +1 -0
  412. package/web-shell/assets/quadrantDiagram-W4KKPZXB-Cx0ZaWPo.js +7 -0
  413. package/web-shell/assets/r-CwjWoCRV.js +1 -0
  414. package/web-shell/assets/racket-CzouJOBO.js +1 -0
  415. package/web-shell/assets/raku-B1bQXN8T.js +1 -0
  416. package/web-shell/assets/razor-CNLDkMZG.js +1 -0
  417. package/web-shell/assets/red-bN70gL4F.js +1 -0
  418. package/web-shell/assets/reg-5LuOXUq_.js +1 -0
  419. package/web-shell/assets/regexp-DWJ3fJO_.js +1 -0
  420. package/web-shell/assets/rel-DJlmqQ1C.js +1 -0
  421. package/web-shell/assets/requirementDiagram-4Y6WPE33-BJPXejOA.js +84 -0
  422. package/web-shell/assets/riscv-QhoSD0DR.js +1 -0
  423. package/web-shell/assets/rose-pine-CmCqftbK.js +1 -0
  424. package/web-shell/assets/rose-pine-dawn-Ds-gbosJ.js +1 -0
  425. package/web-shell/assets/rose-pine-moon-CjDtw9vr.js +1 -0
  426. package/web-shell/assets/rst-4NLicBqY.js +1 -0
  427. package/web-shell/assets/ruby-DeZ3UC14.js +1 -0
  428. package/web-shell/assets/rust-Be6lgOlo.js +1 -0
  429. package/web-shell/assets/sankeyDiagram-5OEKKPKP-C1xeIL9i.js +40 -0
  430. package/web-shell/assets/sas-BmTFh92c.js +1 -0
  431. package/web-shell/assets/sass-BJ4Li9vH.js +1 -0
  432. package/web-shell/assets/scala-DQVVAn-B.js +1 -0
  433. package/web-shell/assets/scheme-BJGe-b2p.js +1 -0
  434. package/web-shell/assets/scss-C31hgJw-.js +1 -0
  435. package/web-shell/assets/sdbl-BLhTXw86.js +1 -0
  436. package/web-shell/assets/sequenceDiagram-3UESZ5HK-CSYKQUjf.js +162 -0
  437. package/web-shell/assets/shaderlab-B7qAK45m.js +1 -0
  438. package/web-shell/assets/shellscript-atvbtKCR.js +1 -0
  439. package/web-shell/assets/shellsession-C_rIy8kc.js +1 -0
  440. package/web-shell/assets/slack-dark-BthQWCQV.js +1 -0
  441. package/web-shell/assets/slack-ochin-DqwNpetd.js +1 -0
  442. package/web-shell/assets/smalltalk-DkLiglaE.js +1 -0
  443. package/web-shell/assets/snazzy-light-Bw305WKR.js +1 -0
  444. package/web-shell/assets/solarized-dark-DXbdFlpD.js +1 -0
  445. package/web-shell/assets/solarized-light-L9t79GZl.js +1 -0
  446. package/web-shell/assets/solidity-C1w2a3ep.js +1 -0
  447. package/web-shell/assets/soy-C-lX7w71.js +1 -0
  448. package/web-shell/assets/sparql-bYkjHRlG.js +1 -0
  449. package/web-shell/assets/splunk-Cf8iN4DR.js +1 -0
  450. package/web-shell/assets/sql-COK4E0Yg.js +1 -0
  451. package/web-shell/assets/ssh-config-BknIz3MU.js +1 -0
  452. package/web-shell/assets/stata-DorPZHa4.js +1 -0
  453. package/web-shell/assets/stateDiagram-AJRCARHV-d9hiHlAW.js +1 -0
  454. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DgReoybQ.js +1 -0
  455. package/web-shell/assets/stylus-BeQkCIfX.js +1 -0
  456. package/web-shell/assets/svelte-MSaWC3Je.js +1 -0
  457. package/web-shell/assets/swift-BSxZ-RaX.js +1 -0
  458. package/web-shell/assets/synthwave-84-CbfX1IO0.js +1 -0
  459. package/web-shell/assets/system-verilog-C7L56vO4.js +1 -0
  460. package/web-shell/assets/systemd-CUnW07Te.js +1 -0
  461. package/web-shell/assets/talonscript-C1XDQQGZ.js +1 -0
  462. package/web-shell/assets/tasl-CQjiPCtT.js +1 -0
  463. package/web-shell/assets/tcl-DQ1-QYvQ.js +1 -0
  464. package/web-shell/assets/templ-dwX3ZSMB.js +1 -0
  465. package/web-shell/assets/terraform-BbSNqyBO.js +1 -0
  466. package/web-shell/assets/tex-rYs2v40G.js +1 -0
  467. package/web-shell/assets/timeline-definition-PNZ67QCA-BhCBkq8k.js +120 -0
  468. package/web-shell/assets/tokyo-night-DBQeEorK.js +1 -0
  469. package/web-shell/assets/toml-CB2ApiWb.js +1 -0
  470. package/web-shell/assets/ts-tags-CipyTH0X.js +1 -0
  471. package/web-shell/assets/tsv-B_m7g4N7.js +1 -0
  472. package/web-shell/assets/tsx-B6W0miNI.js +1 -0
  473. package/web-shell/assets/turtle-BMR_PYu6.js +1 -0
  474. package/web-shell/assets/twig-NC5TFiHP.js +1 -0
  475. package/web-shell/assets/typescript-Dj6nwHGl.js +1 -0
  476. package/web-shell/assets/typespec-BpWG_bgh.js +1 -0
  477. package/web-shell/assets/typst-BVUVsWT6.js +1 -0
  478. package/web-shell/assets/v-CAQ2eGtk.js +1 -0
  479. package/web-shell/assets/vala-BFOHcciG.js +1 -0
  480. package/web-shell/assets/vb-CdO5JTpU.js +1 -0
  481. package/web-shell/assets/vennDiagram-CIIHVFJN-DPPFWp_y.js +34 -0
  482. package/web-shell/assets/verilog-CJaU5se_.js +1 -0
  483. package/web-shell/assets/vesper-BEBZ7ncR.js +1 -0
  484. package/web-shell/assets/vhdl-DYoNaHQp.js +1 -0
  485. package/web-shell/assets/viml-m4uW47V2.js +1 -0
  486. package/web-shell/assets/vitesse-black-Bkuqu6BP.js +1 -0
  487. package/web-shell/assets/vitesse-dark-D0r3Knsf.js +1 -0
  488. package/web-shell/assets/vitesse-light-CVO1_9PV.js +1 -0
  489. package/web-shell/assets/vue-BuYVFjOK.js +1 -0
  490. package/web-shell/assets/vue-html-xdeiXROB.js +1 -0
  491. package/web-shell/assets/vyper-nyqBNV6O.js +1 -0
  492. package/web-shell/assets/wardley-L42UT6IY-CcOUIgXY.js +173 -0
  493. package/web-shell/assets/wardleyDiagram-YWT4CUSO-p7oR5X7r.js +78 -0
  494. package/web-shell/assets/wasm-C6j12Q_x.js +1 -0
  495. package/web-shell/assets/wasm-CG6Dc4jp.js +1 -0
  496. package/web-shell/assets/wenyan-7A4Fjokl.js +1 -0
  497. package/web-shell/assets/wgsl-CB0Krxn9.js +1 -0
  498. package/web-shell/assets/wikitext-DCE3LsBG.js +1 -0
  499. package/web-shell/assets/wolfram-C3FkfJm5.js +1 -0
  500. package/web-shell/assets/xml-e3z08dGr.js +1 -0
  501. package/web-shell/assets/xsl-Dd0NUgwM.js +1 -0
  502. package/web-shell/assets/xychartDiagram-2RQKCTM6-Dfr7-SEy.js +7 -0
  503. package/web-shell/assets/yaml-CVw76BM1.js +1 -0
  504. package/web-shell/assets/zenscript-HnGAYVZD.js +1 -0
  505. package/web-shell/assets/zig-BVz_zdnA.js +1 -0
  506. package/web-shell/index.html +23 -0
  507. package/chunks/chunk-C64WAJOC.js +0 -117
  508. package/chunks/contextCommand-Y4PRJOJM.js +0 -53
@@ -0,0 +1,1026 @@
1
+ // Force strict mode and setup for ESM
2
+ "use strict";
3
+ import {
4
+ matches,
5
+ nextFireTime,
6
+ parseCron
7
+ } from "./chunk-2MPVVENX.js";
8
+ import {
9
+ humanReadableCron
10
+ } from "./chunk-ZTQ26VBE.js";
11
+ import {
12
+ CRON_TASKS_DISPLAY_PATH,
13
+ addCronTask,
14
+ getCronFilePath,
15
+ readCronTasks,
16
+ removeCronTasks,
17
+ updateCronTasks
18
+ } from "./chunk-4HMWGHPP.js";
19
+ import {
20
+ ToolNames
21
+ } from "./chunk-JJHY7NAD.js";
22
+ import {
23
+ Storage,
24
+ createDebugLogger,
25
+ getProjectHash
26
+ } from "./chunk-IKOWINH4.js";
27
+ import {
28
+ init_esbuild_shims
29
+ } from "./chunk-A4BMJM77.js";
30
+ import {
31
+ __name
32
+ } from "./chunk-J2S4EL5Y.js";
33
+
34
+ // packages/core/src/services/cronScheduler.ts
35
+ init_esbuild_shims();
36
+ import * as fsSync from "node:fs";
37
+ import * as path2 from "node:path";
38
+
39
+ // packages/core/src/services/cronTasksLock.ts
40
+ init_esbuild_shims();
41
+ import * as fs from "node:fs/promises";
42
+ import * as path from "node:path";
43
+ var LOCK_FILENAME = "scheduled_tasks.lock";
44
+ var staleSeq = 0;
45
+ function getLockFilePath(projectRoot) {
46
+ return path.join(
47
+ Storage.getGlobalTempDir(),
48
+ getProjectHash(projectRoot),
49
+ LOCK_FILENAME
50
+ );
51
+ }
52
+ __name(getLockFilePath, "getLockFilePath");
53
+ function isProcessAlive(pid) {
54
+ try {
55
+ process.kill(pid, 0);
56
+ return true;
57
+ } catch (err) {
58
+ return err.code === "EPERM";
59
+ }
60
+ }
61
+ __name(isProcessAlive, "isProcessAlive");
62
+ async function tryAcquireLock(projectRoot, sessionId, lockId) {
63
+ const lockPath = getLockFilePath(projectRoot);
64
+ const content = { pid: process.pid, sessionId, lockId };
65
+ await fs.mkdir(path.dirname(lockPath), { recursive: true });
66
+ for (let attempt = 0; attempt < 2; attempt++) {
67
+ try {
68
+ await fs.writeFile(lockPath, JSON.stringify(content), {
69
+ encoding: "utf-8",
70
+ flag: "wx"
71
+ });
72
+ return true;
73
+ } catch (err) {
74
+ if (err.code !== "EEXIST") throw err;
75
+ }
76
+ let existing = null;
77
+ try {
78
+ existing = JSON.parse(await fs.readFile(lockPath, "utf-8"));
79
+ } catch (err) {
80
+ if (err.code === "ENOENT") {
81
+ continue;
82
+ }
83
+ if (!(err instanceof SyntaxError)) {
84
+ throw err;
85
+ }
86
+ }
87
+ if (existing) {
88
+ if (existing.pid === process.pid && existing.sessionId === sessionId && existing.lockId === lockId) {
89
+ return true;
90
+ }
91
+ if (isProcessAlive(existing.pid)) {
92
+ return false;
93
+ }
94
+ }
95
+ const stalePath = `${lockPath}.stale.${process.pid}.${staleSeq++}`;
96
+ try {
97
+ await fs.rename(lockPath, stalePath);
98
+ } catch (err) {
99
+ if (err.code !== "ENOENT") {
100
+ return false;
101
+ }
102
+ continue;
103
+ }
104
+ let movedIsLive = false;
105
+ try {
106
+ const moved = JSON.parse(
107
+ await fs.readFile(stalePath, "utf-8")
108
+ );
109
+ movedIsLive = isProcessAlive(moved.pid);
110
+ } catch (err) {
111
+ movedIsLive = !(err instanceof SyntaxError);
112
+ }
113
+ if (movedIsLive) {
114
+ await fs.link(stalePath, lockPath).catch(() => {
115
+ });
116
+ await fs.unlink(stalePath).catch(() => {
117
+ });
118
+ return false;
119
+ }
120
+ await fs.unlink(stalePath).catch(() => {
121
+ });
122
+ }
123
+ return false;
124
+ }
125
+ __name(tryAcquireLock, "tryAcquireLock");
126
+ async function releaseLock(projectRoot, sessionId, lockId) {
127
+ const lockPath = getLockFilePath(projectRoot);
128
+ try {
129
+ const raw = await fs.readFile(lockPath, "utf-8");
130
+ const existing = JSON.parse(raw);
131
+ if (existing.pid === process.pid && existing.sessionId === sessionId && existing.lockId === lockId) {
132
+ await fs.unlink(lockPath);
133
+ }
134
+ } catch {
135
+ }
136
+ }
137
+ __name(releaseLock, "releaseLock");
138
+
139
+ // packages/core/src/services/cronScheduler.ts
140
+ var debugLogger = createDebugLogger("CRON_SCHEDULER");
141
+ var MAX_JOBS = 50;
142
+ var RECURRING_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
143
+ var MAX_RECURRING_JITTER_MS = 15 * 60 * 1e3;
144
+ var MAX_ONESHOT_JITTER_MS = 90 * 1e3;
145
+ var LOCK_PROBE_INTERVAL_MS = 5e3;
146
+ var FILE_DEBOUNCE_MS = 300;
147
+ var WAKEUP_MIN_SECONDS = 60;
148
+ var WAKEUP_MAX_SECONDS = 3600;
149
+ var WAKEUP_DEFAULT_SECONDS = 1200;
150
+ var WAKEUP_CHAIN_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
151
+ function hashId(id) {
152
+ let hash = 0;
153
+ for (let i = 0; i < id.length; i++) {
154
+ hash = hash * 31 + id.charCodeAt(i) | 0;
155
+ }
156
+ return Math.abs(hash);
157
+ }
158
+ __name(hashId, "hashId");
159
+ function computeJitter(id, cronExpr, recurring) {
160
+ const hash = hashId(id);
161
+ if (recurring) {
162
+ const now = /* @__PURE__ */ new Date();
163
+ try {
164
+ const first = nextFireTime(cronExpr, now);
165
+ const second = nextFireTime(cronExpr, first);
166
+ const periodMs = second.getTime() - first.getTime();
167
+ const tenPercent = periodMs * 0.1;
168
+ const maxJitter = Math.min(tenPercent, MAX_RECURRING_JITTER_MS);
169
+ return hash % Math.max(1, Math.floor(maxJitter));
170
+ } catch {
171
+ return 0;
172
+ }
173
+ }
174
+ try {
175
+ const next = nextFireTime(cronExpr, /* @__PURE__ */ new Date());
176
+ if (next.getMinutes() % 30 === 0) {
177
+ return -(hash % MAX_ONESHOT_JITTER_MS);
178
+ }
179
+ } catch {
180
+ }
181
+ return 0;
182
+ }
183
+ __name(computeJitter, "computeJitter");
184
+ function generateId() {
185
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
186
+ let id = "";
187
+ for (let i = 0; i < 8; i++) {
188
+ id += chars[Math.floor(Math.random() * chars.length)];
189
+ }
190
+ return id;
191
+ }
192
+ __name(generateId, "generateId");
193
+ function clampWakeupSeconds(delaySeconds) {
194
+ if (!Number.isFinite(delaySeconds)) return WAKEUP_DEFAULT_SECONDS;
195
+ return Math.min(
196
+ WAKEUP_MAX_SECONDS,
197
+ Math.max(WAKEUP_MIN_SECONDS, Math.round(delaySeconds))
198
+ );
199
+ }
200
+ __name(clampWakeupSeconds, "clampWakeupSeconds");
201
+ function wakeupToJob(wakeup) {
202
+ return {
203
+ id: wakeup.id,
204
+ cronExpr: "@wakeup",
205
+ prompt: wakeup.prompt,
206
+ recurring: false,
207
+ createdAt: wakeup.createdAt,
208
+ expiresAt: Infinity,
209
+ fireAtMs: wakeup.fireAtMs,
210
+ jitterMs: 0
211
+ };
212
+ }
213
+ __name(wakeupToJob, "wakeupToJob");
214
+ function truncatePrompt(prompt) {
215
+ return prompt.length > 60 ? prompt.slice(0, 57) + "..." : prompt;
216
+ }
217
+ __name(truncatePrompt, "truncatePrompt");
218
+ var CronScheduler = class {
219
+ /** `projectRoot` anchors durable storage; without it only session-only
220
+ * jobs work. Production constructs via `Config.getCronScheduler()`,
221
+ * which always supplies it. */
222
+ constructor(projectRoot = null) {
223
+ this.projectRoot = projectRoot;
224
+ }
225
+ static {
226
+ __name(this, "CronScheduler");
227
+ }
228
+ // All jobs — session-only and durable — live in this one map.
229
+ jobs = /* @__PURE__ */ new Map();
230
+ // Loop wakeups live separately: second-resolution, never durable, never
231
+ // counted against MAX_JOBS. Delivered through the same onFire as cron.
232
+ wakeups = /* @__PURE__ */ new Map();
233
+ // Start of the self-paced wakeup chain — a session-level 24h budget that
234
+ // spans the whole session. Deliberately NOT reset when a wakeup fires or
235
+ // is cancelled: re-arm leaves at most one pending wakeup, so resetting on
236
+ // an empty map would restart the clock every fire and let a continuous
237
+ // loop escape the cap. Reset only by stop()/destroy() (a new session).
238
+ wakeupChainStartedAt = null;
239
+ // Set once disable() runs (the session's token-limit breaker). Permanent
240
+ // for this scheduler's lifetime — distinct from a stopped-but-restartable
241
+ // timer, so LoopWakeup can reject wakeups that would never fire.
242
+ _disabled = false;
243
+ timer = null;
244
+ onFire = null;
245
+ // --- Durable (file-backed) support ---
246
+ durableEnabled = false;
247
+ // Bumped by stop(). Async durable work captures the value before each
248
+ // await and bails if it changed — a continuation that resumes after
249
+ // stop() must not install state (or keep a lock) that stop() already
250
+ // cleaned up or can no longer see.
251
+ durableGeneration = 0;
252
+ sessionId = null;
253
+ // Distinguishes this scheduler's lock from one written by another
254
+ // scheduler instance with the same pid+sessionId (session reload) —
255
+ // adopting such a lock means owning a file whose unlink is in flight.
256
+ lockId = generateId();
257
+ // Release from a previous stop() that may not have landed yet. A new
258
+ // acquire must wait it out so it can't grab the doomed lock file.
259
+ pendingRelease = null;
260
+ isOwner = false;
261
+ // Durable ids whose on-disk removal hasn't landed yet — a reload that
262
+ // reads the file before the write completes must not resurrect them.
263
+ pendingRemoval = /* @__PURE__ */ new Set();
264
+ // Durable ids whose initial on-disk write hasn't landed yet — a reload
265
+ // that reads the file before the write completes must not reconcile
266
+ // the live job away (or clear its pendingRemoval guard) as if it had
267
+ // been deleted on disk.
268
+ pendingAdd = /* @__PURE__ */ new Set();
269
+ fileWatcher = null;
270
+ lockProbeTimer = null;
271
+ debounceTimer = null;
272
+ // Catch-up work detected before start() installed onFire — flushed
273
+ // through onFire as soon as it exists.
274
+ pendingFires = [];
275
+ // Fire-and-forget writes (tick persists, delivered missed-fire
276
+ // removals), chained so stop() can hold the lock until they land — a
277
+ // successor reading the file pre-write would re-run the same work.
278
+ pendingPersist = Promise.resolve();
279
+ /**
280
+ * Creates a new session-only cron job. Returns the created job.
281
+ * Throws if the max job limit is reached.
282
+ */
283
+ create(cronExpr, prompt, recurring) {
284
+ if (this.jobs.size >= MAX_JOBS) {
285
+ throw new Error(
286
+ `Maximum number of cron jobs (${MAX_JOBS}) reached. Delete some jobs first.`
287
+ );
288
+ }
289
+ const id = generateId();
290
+ const now = Date.now();
291
+ const jitterMs = computeJitter(id, cronExpr, recurring);
292
+ const job = {
293
+ id,
294
+ cronExpr,
295
+ prompt,
296
+ recurring,
297
+ createdAt: now,
298
+ expiresAt: recurring ? now + RECURRING_MAX_AGE_MS : Infinity,
299
+ // Prevent the scheduler from firing during the creation minute
300
+ lastFiredAt: now - now % 6e4,
301
+ jitterMs
302
+ };
303
+ this.jobs.set(id, job);
304
+ return job;
305
+ }
306
+ /**
307
+ * Schedules a second-resolution, session-only one-shot wakeup for
308
+ * self-paced `/loop`. Clamps `delaySeconds` to [60, 3600]; non-finite
309
+ * input falls back to the default heartbeat. The fire time is exact (not
310
+ * minute-rounded) and is not subject to MAX_JOBS. Returns the scheduling
311
+ * outcome for the model (mirrors ScheduleWakeup's output).
312
+ */
313
+ scheduleWakeup(delaySeconds, prompt) {
314
+ if (this._disabled) {
315
+ throw new Error(
316
+ "Cannot schedule a loop wakeup: the scheduler is disabled for this session. Restart the session to re-enable."
317
+ );
318
+ }
319
+ const clampedDelaySeconds = clampWakeupSeconds(delaySeconds);
320
+ const roundedDelaySeconds = Number.isFinite(delaySeconds) ? Math.round(delaySeconds) : delaySeconds;
321
+ const wasClamped = !Number.isFinite(delaySeconds) || roundedDelaySeconds < WAKEUP_MIN_SECONDS || roundedDelaySeconds > WAKEUP_MAX_SECONDS;
322
+ const id = generateId();
323
+ const now = Date.now();
324
+ const fireAtMs = now + clampedDelaySeconds * 1e3;
325
+ const replacedWakeup = this.wakeups.values().next().value ?? null;
326
+ const replacedId = replacedWakeup?.id ?? null;
327
+ if (this.wakeupChainStartedAt === null) {
328
+ this.wakeupChainStartedAt = now;
329
+ }
330
+ this.wakeups.clear();
331
+ if (fireAtMs > this.wakeupChainStartedAt + WAKEUP_CHAIN_MAX_AGE_MS) {
332
+ throw new Error(
333
+ "Loop wakeup chain exceeded the 24h session limit. Omit LoopWakeup to end this loop, or start a new session."
334
+ );
335
+ }
336
+ if (replacedId) {
337
+ debugLogger.debug(`Replacing pending wakeup ${replacedId}`);
338
+ }
339
+ this.wakeups.set(id, { id, fireAtMs, prompt, createdAt: now });
340
+ debugLogger.debug(
341
+ `Wakeup ${id} scheduled for ${new Date(fireAtMs).toISOString()} (delay=${clampedDelaySeconds}s)`
342
+ );
343
+ return {
344
+ id,
345
+ scheduledFor: new Date(fireAtMs).toISOString(),
346
+ clampedDelaySeconds,
347
+ wasClamped,
348
+ replacedId
349
+ };
350
+ }
351
+ /** Cancels a single pending wakeup. Returns true if it existed. */
352
+ cancelWakeup(id) {
353
+ const deleted = this.wakeups.delete(id);
354
+ if (deleted) {
355
+ debugLogger.debug(`Cancelled wakeup ${id}`);
356
+ }
357
+ return deleted;
358
+ }
359
+ /**
360
+ * Cancels every pending wakeup; returns how many were cancelled. The
361
+ * primitive behind a future loop-scoped "cancel all wakeups on abort".
362
+ */
363
+ cancelAllWakeups() {
364
+ const count = this.wakeups.size;
365
+ this.wakeups.clear();
366
+ if (count > 0) debugLogger.debug(`Cancelled ${count} wakeup(s)`);
367
+ return count;
368
+ }
369
+ /**
370
+ * Creates a durable cron job: registered like any other job, and
371
+ * persisted under ~/.qwen (per-project) so it survives restarts.
372
+ * Throws if the job can't be persisted.
373
+ */
374
+ async createDurable(cronExpr, prompt, recurring) {
375
+ if (!this.projectRoot) {
376
+ throw new Error("Durable cron jobs require a project root.");
377
+ }
378
+ const job = this.create(cronExpr, prompt, recurring);
379
+ job.durable = true;
380
+ this.pendingAdd.add(job.id);
381
+ try {
382
+ await addCronTask(this.projectRoot, jobToDurableTask(job));
383
+ } catch (error) {
384
+ this.jobs.delete(job.id);
385
+ throw error;
386
+ } finally {
387
+ this.pendingAdd.delete(job.id);
388
+ }
389
+ return job;
390
+ }
391
+ /**
392
+ * Deletes a job by ID. Durable jobs are also removed from disk, and the
393
+ * removal is awaited — reporting success while the on-disk entry could
394
+ * survive would let the task resurface in another session or after a
395
+ * restart. On write failure the job is restored and the error rethrown.
396
+ * Returns true if the job existed.
397
+ */
398
+ async delete(id) {
399
+ const job = this.jobs.get(id);
400
+ if (!job) return this.cancelWakeup(id);
401
+ this.jobs.delete(id);
402
+ if (job.durable && this.projectRoot) {
403
+ this.pendingRemoval.add(id);
404
+ try {
405
+ await removeCronTasks(this.projectRoot, [id]);
406
+ } catch (error) {
407
+ this.pendingRemoval.delete(id);
408
+ this.jobs.set(id, job);
409
+ throw error;
410
+ }
411
+ }
412
+ return true;
413
+ }
414
+ /**
415
+ * Returns all active jobs.
416
+ */
417
+ list() {
418
+ return [
419
+ ...this.jobs.values(),
420
+ ...[...this.wakeups.values()].map(wakeupToJob)
421
+ ];
422
+ }
423
+ /**
424
+ * Returns the number of active jobs and wakeups.
425
+ */
426
+ get size() {
427
+ return this.jobs.size + this.wakeups.size;
428
+ }
429
+ /**
430
+ * Returns the number of session-only (non-durable) jobs. Headless mode
431
+ * keys its hold-open loop on this: durable jobs outlive the process by
432
+ * design and never fire without lock ownership, so they must not pin it.
433
+ */
434
+ get sessionSize() {
435
+ let count = this.wakeups.size;
436
+ for (const job of this.jobs.values()) {
437
+ if (!job.durable) count++;
438
+ }
439
+ return count;
440
+ }
441
+ /**
442
+ * Enables durable cron support. Loads tasks from disk and watches the
443
+ * tasks file in every session — durable tasks are project-level, so
444
+ * cron_list/cron_delete must see them regardless of which session owns
445
+ * the lock. The lock only gates firing.
446
+ */
447
+ async enableDurable(sessionId) {
448
+ if (this.durableEnabled) return;
449
+ const projectRoot = this.projectRoot;
450
+ if (!projectRoot) return;
451
+ this.durableEnabled = true;
452
+ this.sessionId = sessionId;
453
+ const generation = this.durableGeneration;
454
+ try {
455
+ if (this.pendingRelease) {
456
+ await this.pendingRelease;
457
+ this.pendingRelease = null;
458
+ if (generation !== this.durableGeneration) return;
459
+ }
460
+ const acquired = await tryAcquireLock(
461
+ projectRoot,
462
+ sessionId,
463
+ this.lockId
464
+ );
465
+ if (generation !== this.durableGeneration) {
466
+ this.releaseLateAcquisition(acquired, projectRoot, sessionId);
467
+ return;
468
+ }
469
+ this.isOwner = acquired;
470
+ this.startFileWatcher(projectRoot);
471
+ await this.loadFileTasks(this.isOwner);
472
+ if (generation !== this.durableGeneration) {
473
+ return;
474
+ }
475
+ if (!this.isOwner) {
476
+ this.lockProbeTimer = setInterval(() => {
477
+ void tryAcquireLock(projectRoot, sessionId, this.lockId).then((acquired2) => {
478
+ if (generation !== this.durableGeneration) {
479
+ this.releaseLateAcquisition(acquired2, projectRoot, sessionId);
480
+ return;
481
+ }
482
+ if (acquired2 && !this.isOwner) {
483
+ this.isOwner = true;
484
+ if (this.lockProbeTimer) {
485
+ clearInterval(this.lockProbeTimer);
486
+ this.lockProbeTimer = null;
487
+ }
488
+ void this.loadFileTasks(true).catch((err) => {
489
+ debugLogger.warn(`Cron takeover reload failed: ${err}`);
490
+ });
491
+ }
492
+ }).catch((err) => {
493
+ debugLogger.warn(`Cron lock probe failed: ${err}`);
494
+ });
495
+ }, LOCK_PROBE_INTERVAL_MS);
496
+ this.lockProbeTimer.unref();
497
+ }
498
+ } catch (error) {
499
+ if (generation === this.durableGeneration) {
500
+ if (this.isOwner) {
501
+ this.pendingRelease = releaseLock(
502
+ projectRoot,
503
+ sessionId,
504
+ this.lockId
505
+ );
506
+ this.isOwner = false;
507
+ }
508
+ this.durableEnabled = false;
509
+ this.sessionId = null;
510
+ }
511
+ throw error;
512
+ }
513
+ }
514
+ /**
515
+ * Hands back a lock acquired by an await that resumed after stop() —
516
+ * unless a newer enableDurable() for the same session is already active
517
+ * on this scheduler, in which case the lock is exactly the one it owns
518
+ * (acquisition is idempotent per pid+sessionId+lockId) and releasing
519
+ * would pull it out from under it.
520
+ */
521
+ releaseLateAcquisition(acquired, projectRoot, sessionId) {
522
+ if (!acquired) return;
523
+ if (this.durableEnabled && this.sessionId === sessionId) return;
524
+ this.pendingRelease = releaseLock(projectRoot, sessionId, this.lockId);
525
+ }
526
+ async loadFileTasks(handleMissed) {
527
+ const projectRoot = this.projectRoot;
528
+ if (!projectRoot) return;
529
+ const generation = this.durableGeneration;
530
+ let read;
531
+ try {
532
+ read = await readCronTasks(projectRoot);
533
+ } catch {
534
+ return;
535
+ }
536
+ if (generation !== this.durableGeneration) {
537
+ return;
538
+ }
539
+ const tasks = read.filter(hasParseableCron);
540
+ const now = Date.now();
541
+ const missedOneShots = [];
542
+ const catchUpIds = [];
543
+ const finalTasks = [];
544
+ if (handleMissed) {
545
+ for (const t of tasks) {
546
+ if (this.pendingRemoval.has(t.id)) continue;
547
+ const jitter = computeJitter(t.id, t.cron, t.recurring);
548
+ const anchor = t.recurring ? t.lastFiredAt ?? t.createdAt : t.createdAt;
549
+ const nextFire = computeNextFireMs(t.cron, anchor, jitter);
550
+ if (nextFire === null || nextFire >= now) continue;
551
+ if (!t.recurring) {
552
+ missedOneShots.push(t);
553
+ } else if (now - t.createdAt >= RECURRING_MAX_AGE_MS) {
554
+ finalTasks.push(t);
555
+ } else {
556
+ catchUpIds.push(t.id);
557
+ }
558
+ }
559
+ for (const t of [...missedOneShots, ...finalTasks]) {
560
+ this.pendingRemoval.add(t.id);
561
+ this.jobs.delete(t.id);
562
+ }
563
+ }
564
+ const diskIds = new Set(tasks.map((t) => t.id));
565
+ for (const id of this.pendingAdd) diskIds.add(id);
566
+ for (const job of this.jobs.values()) {
567
+ if (job.durable && !diskIds.has(job.id)) {
568
+ this.jobs.delete(job.id);
569
+ }
570
+ }
571
+ for (const id of this.pendingRemoval) {
572
+ if (!diskIds.has(id)) this.pendingRemoval.delete(id);
573
+ }
574
+ for (const task of tasks) {
575
+ if (this.pendingRemoval.has(task.id)) continue;
576
+ const existing = this.jobs.get(task.id);
577
+ if (!existing && this.jobs.size >= MAX_JOBS) {
578
+ debugLogger.warn(
579
+ `Durable task ${task.id} skipped \u2014 MAX_JOBS (${MAX_JOBS}) reached.`
580
+ );
581
+ continue;
582
+ }
583
+ const job = durableTaskToJob(task, existing);
584
+ if (existing?.lastFiredAt !== void 0) {
585
+ job.lastFiredAt = Math.max(existing.lastFiredAt, job.lastFiredAt ?? 0);
586
+ }
587
+ this.jobs.set(task.id, job);
588
+ }
589
+ if (catchUpIds.length > 0) {
590
+ const nowMinuteMs = now - now % 6e4;
591
+ for (const id of catchUpIds) {
592
+ const job = this.jobs.get(id);
593
+ if (job) job.lastFiredAt = nowMinuteMs;
594
+ }
595
+ }
596
+ if (missedOneShots.length > 0) {
597
+ this.fireOrBuffer({ kind: "missed", tasks: missedOneShots });
598
+ }
599
+ if (catchUpIds.length > 0) {
600
+ this.fireOrBuffer({ kind: "catch-up", ids: catchUpIds });
601
+ }
602
+ if (finalTasks.length > 0) {
603
+ this.fireOrBuffer({
604
+ kind: "final",
605
+ jobs: finalTasks.map((t) => durableTaskToJob(t))
606
+ });
607
+ }
608
+ }
609
+ /**
610
+ * Delivers catch-up work through the normal onFire channel, or holds
611
+ * it until start() installs one. Delivery is what removes a missed or
612
+ * final task from disk (and what persists a catch-up stamp) — a
613
+ * buffered fire leaves disk state untouched, so a stop() that drops
614
+ * the buffer loses nothing.
615
+ */
616
+ fireOrBuffer(pending) {
617
+ if (this.onFire) {
618
+ this.deliverPending(pending, this.onFire);
619
+ } else {
620
+ this.pendingFires.push(pending);
621
+ }
622
+ }
623
+ deliverPending(pending, onFire) {
624
+ switch (pending.kind) {
625
+ case "missed": {
626
+ onFire({
627
+ ...durableTaskToJob(pending.tasks[0]),
628
+ prompt: buildMissedCronNotification(pending.tasks),
629
+ missed: true
630
+ });
631
+ this.removeMissedFromDisk(pending.tasks.map((t) => t.id));
632
+ break;
633
+ }
634
+ case "catch-up": {
635
+ const fired = [];
636
+ for (const id of pending.ids) {
637
+ const job = this.jobs.get(id);
638
+ if (!job) continue;
639
+ onFire(job);
640
+ fired.push(id);
641
+ }
642
+ this.persistCatchUpStamps(fired);
643
+ break;
644
+ }
645
+ case "final": {
646
+ for (const job of pending.jobs) {
647
+ onFire(job);
648
+ }
649
+ this.removeMissedFromDisk(pending.jobs.map((j) => j.id));
650
+ break;
651
+ }
652
+ default: {
653
+ const _exhaustive = pending;
654
+ return _exhaustive;
655
+ }
656
+ }
657
+ }
658
+ /**
659
+ * Persists the in-memory lastFiredAt stamps of just-delivered catch-up
660
+ * fires so a restart doesn't replay them.
661
+ */
662
+ persistCatchUpStamps(ids) {
663
+ if (!this.projectRoot || ids.length === 0) return;
664
+ const stamps = /* @__PURE__ */ new Map();
665
+ for (const id of ids) {
666
+ const fired = this.jobs.get(id)?.lastFiredAt;
667
+ if (fired !== void 0) stamps.set(id, fired);
668
+ }
669
+ if (stamps.size === 0) return;
670
+ this.trackPersist(
671
+ updateCronTasks(this.projectRoot, (tasks) => {
672
+ let changed = false;
673
+ const next = tasks.map((t) => {
674
+ const stamp = stamps.get(t.id);
675
+ if (stamp === void 0 || t.lastFiredAt === stamp) return t;
676
+ changed = true;
677
+ return { ...t, lastFiredAt: stamp };
678
+ });
679
+ return changed ? next : tasks;
680
+ })
681
+ );
682
+ }
683
+ /** Launches the on-disk removal of missed/final tasks just delivered. */
684
+ removeMissedFromDisk(ids) {
685
+ if (!this.projectRoot || ids.length === 0) return;
686
+ this.trackPersist(removeCronTasks(this.projectRoot, ids));
687
+ }
688
+ /**
689
+ * Chains a background write into pendingPersist so stop() releases the
690
+ * lock only after it lands. Failures are logged but not retried — same
691
+ * best-effort contract as a fire-and-forget persist; the fire was
692
+ * already delivered, so a failed stamp degrades to at-least-once.
693
+ */
694
+ trackPersist(write) {
695
+ const settled = write.then(
696
+ () => {
697
+ },
698
+ (err) => {
699
+ debugLogger.warn(
700
+ `Durable cron persist failed \u2014 disk state is stale and the task may fire again in a later session: ${err}`
701
+ );
702
+ }
703
+ );
704
+ this.pendingPersist = this.pendingPersist.then(() => settled);
705
+ }
706
+ startFileWatcher(projectRoot) {
707
+ if (this.fileWatcher) return;
708
+ const filePath = getCronFilePath(projectRoot);
709
+ const dir = path2.dirname(filePath);
710
+ const fileName = path2.basename(filePath);
711
+ try {
712
+ fsSync.mkdirSync(dir, { recursive: true });
713
+ this.fileWatcher = fsSync.watch(
714
+ dir,
715
+ { persistent: false },
716
+ (_event, filename) => {
717
+ if (filename && filename !== fileName) return;
718
+ if (this.debounceTimer) clearTimeout(this.debounceTimer);
719
+ this.debounceTimer = setTimeout(() => {
720
+ void this.loadFileTasks(false);
721
+ }, FILE_DEBOUNCE_MS);
722
+ this.debounceTimer.unref();
723
+ }
724
+ );
725
+ this.fileWatcher.on("error", (err) => {
726
+ debugLogger.warn(
727
+ `Tasks-file watcher error \u2014 durable task changes from other sessions may not be picked up until restart: ${err}`
728
+ );
729
+ });
730
+ } catch {
731
+ }
732
+ }
733
+ /**
734
+ * Starts the scheduler tick. Calls `onFire` when a job is due.
735
+ * Only fires when called — does not auto-fire missed intervals.
736
+ */
737
+ start(onFire) {
738
+ this.onFire = onFire;
739
+ for (const pending of this.pendingFires.splice(0)) {
740
+ this.deliverPending(pending, onFire);
741
+ }
742
+ if (this.timer) return;
743
+ this.timer = setInterval(() => {
744
+ this.tick();
745
+ }, 1e3);
746
+ }
747
+ /**
748
+ * Stops the scheduler and relinquishes durable participation: the lock
749
+ * is released so another session can take over, and a later
750
+ * `enableDurable()` re-acquires from scratch (a re-enable under a new
751
+ * sessionId must not be blocked by this session's own old lock).
752
+ * Does not clear cron jobs — they remain queryable. Pending wakeups are
753
+ * cleared because they are session-scoped and meaningless without a timer.
754
+ */
755
+ stop() {
756
+ if (this.timer) {
757
+ clearInterval(this.timer);
758
+ this.timer = null;
759
+ }
760
+ if (this.lockProbeTimer) {
761
+ clearInterval(this.lockProbeTimer);
762
+ this.lockProbeTimer = null;
763
+ }
764
+ if (this.fileWatcher) {
765
+ this.fileWatcher.close();
766
+ this.fileWatcher = null;
767
+ }
768
+ if (this.debounceTimer) {
769
+ clearTimeout(this.debounceTimer);
770
+ this.debounceTimer = null;
771
+ }
772
+ if (this.wakeups.size > 0) {
773
+ debugLogger.debug(`stop() discarding ${this.wakeups.size} wakeup(s)`);
774
+ this.wakeups.clear();
775
+ }
776
+ this.wakeupChainStartedAt = null;
777
+ this.onFire = null;
778
+ if (this.durableEnabled) {
779
+ this.durableGeneration++;
780
+ if (this.isOwner && this.projectRoot && this.sessionId) {
781
+ const projectRoot = this.projectRoot;
782
+ const sessionId = this.sessionId;
783
+ this.pendingRelease = this.pendingPersist.then(
784
+ () => releaseLock(projectRoot, sessionId, this.lockId)
785
+ );
786
+ }
787
+ this.isOwner = false;
788
+ this.durableEnabled = false;
789
+ for (const pending of this.pendingFires) {
790
+ if (pending.kind === "missed") {
791
+ for (const t of pending.tasks) this.pendingRemoval.delete(t.id);
792
+ } else if (pending.kind === "final") {
793
+ for (const j of pending.jobs) this.pendingRemoval.delete(j.id);
794
+ }
795
+ }
796
+ this.pendingFires.length = 0;
797
+ }
798
+ }
799
+ /**
800
+ * True while durable (file-backed) support is active — this session is
801
+ * either firing durable tasks (owner) or probing to take over.
802
+ */
803
+ get durableActive() {
804
+ return this.durableEnabled;
805
+ }
806
+ /**
807
+ * True when the tick loop has — or may acquire — work: any in-memory
808
+ * job, or durable mode active (the file watcher and lock takeover can
809
+ * install fireable tasks at any time, even while the map is empty).
810
+ */
811
+ get hasPendingWork() {
812
+ return this.jobs.size > 0 || this.wakeups.size > 0 || this.durableEnabled;
813
+ }
814
+ /**
815
+ * Returns true if the scheduler is running.
816
+ */
817
+ get running() {
818
+ return this.timer !== null;
819
+ }
820
+ /**
821
+ * True once disable() has run. Distinct from `!running`: a fresh scheduler
822
+ * is stopped but not disabled, and starts on first pending work. Used by
823
+ * LoopWakeup to reject wakeups that would never fire (vs. ones that will
824
+ * fire once the post-prompt hook starts the tick).
825
+ */
826
+ get disabled() {
827
+ return this._disabled;
828
+ }
829
+ /**
830
+ * Permanently disables the scheduler for this session: stops the tick and
831
+ * marks it disabled so LoopWakeup rejects new wakeups. Only the token-limit
832
+ * breaker calls this; cleared only by a new session (a fresh instance).
833
+ */
834
+ disable() {
835
+ this._disabled = true;
836
+ this.stop();
837
+ }
838
+ /**
839
+ * Manual tick — checks all jobs against the current time and fires those
840
+ * that are due. Exported for testing.
841
+ */
842
+ tick(now) {
843
+ if (this.jobs.size === 0 && this.wakeups.size === 0) return;
844
+ const currentDate = now ?? /* @__PURE__ */ new Date();
845
+ const currentMs = currentDate.getTime();
846
+ const firedAt = /* @__PURE__ */ new Map();
847
+ const removedIds = [];
848
+ for (const job of this.jobs.values()) {
849
+ if (job.durable && !this.isOwner) continue;
850
+ const result = this.processJob(job, currentDate, currentMs);
851
+ if (!job.durable || result === "none") continue;
852
+ if (result === "fired-final" || !job.recurring) {
853
+ removedIds.push(job.id);
854
+ } else {
855
+ firedAt.set(job.id, job.lastFiredAt);
856
+ }
857
+ }
858
+ if (this.projectRoot && (firedAt.size > 0 || removedIds.length > 0)) {
859
+ for (const id of removedIds) this.pendingRemoval.add(id);
860
+ const removed = new Set(removedIds);
861
+ this.trackPersist(
862
+ updateCronTasks(
863
+ this.projectRoot,
864
+ (tasks) => tasks.filter((t) => !removed.has(t.id)).map(
865
+ (t) => firedAt.has(t.id) ? { ...t, lastFiredAt: firedAt.get(t.id) } : t
866
+ )
867
+ )
868
+ );
869
+ }
870
+ for (const wakeup of this.wakeups.values()) {
871
+ if (wakeup.fireAtMs > currentMs) continue;
872
+ this.wakeups.delete(wakeup.id);
873
+ debugLogger.debug(`Firing wakeup ${wakeup.id}`);
874
+ if (this.onFire) this.onFire(wakeupToJob(wakeup));
875
+ }
876
+ }
877
+ /**
878
+ * Processes a single job. Returns 'fired' if the job fired,
879
+ * 'fired-final' if it fired one last time and was removed (aged out),
880
+ * and 'none' otherwise.
881
+ */
882
+ processJob(job, currentDate, currentMs) {
883
+ const absJitter = Math.abs(job.jitterMs);
884
+ const windowMinutes = Math.ceil(absJitter / 6e4);
885
+ const nowMinuteStart = new Date(currentDate);
886
+ nowMinuteStart.setSeconds(0, 0);
887
+ const nowMinuteMs = nowMinuteStart.getTime();
888
+ let matchedMinuteMs = null;
889
+ for (let offset = -windowMinutes; offset <= windowMinutes; offset++) {
890
+ const candidateMs = nowMinuteMs + offset * 6e4;
891
+ const candidateDate = new Date(candidateMs);
892
+ if (!matches(job.cronExpr, candidateDate)) continue;
893
+ const fireTimeMs = candidateMs + job.jitterMs;
894
+ if (currentMs >= fireTimeMs) {
895
+ if (matchedMinuteMs === null || candidateMs > matchedMinuteMs) {
896
+ matchedMinuteMs = candidateMs;
897
+ }
898
+ }
899
+ }
900
+ if (matchedMinuteMs === null) return "none";
901
+ if (job.lastFiredAt !== void 0 && job.lastFiredAt >= matchedMinuteMs) {
902
+ return "none";
903
+ }
904
+ job.lastFiredAt = matchedMinuteMs;
905
+ const expired = job.recurring && currentMs >= job.expiresAt;
906
+ if (!job.recurring || expired) {
907
+ this.jobs.delete(job.id);
908
+ }
909
+ if (this.onFire) {
910
+ this.onFire(job);
911
+ }
912
+ return expired ? "fired-final" : "fired";
913
+ }
914
+ /**
915
+ * Returns a human-readable summary of active session-only jobs for
916
+ * display on session exit. Durable jobs are not included since they
917
+ * persist. Returns null if there are no session-only jobs.
918
+ */
919
+ getExitSummary() {
920
+ const sessionJobs = [...this.jobs.values()].filter((job) => !job.durable);
921
+ const wakeups = [...this.wakeups.values()];
922
+ if (sessionJobs.length === 0 && wakeups.length === 0) return null;
923
+ const count = sessionJobs.length + wakeups.length;
924
+ const lines = [
925
+ `Session ending. ${count} active loop${count === 1 ? "" : "s"} cancelled:`
926
+ ];
927
+ for (const job of sessionJobs) {
928
+ const schedule = humanReadableCron(job.cronExpr);
929
+ lines.push(` - [${job.id}] ${schedule}: ${truncatePrompt(job.prompt)}`);
930
+ }
931
+ for (const wakeup of wakeups) {
932
+ lines.push(
933
+ ` - [${wakeup.id}] wakeup at ${new Date(
934
+ wakeup.fireAtMs
935
+ ).toISOString()}: ${truncatePrompt(wakeup.prompt)}`
936
+ );
937
+ }
938
+ return lines.join("\n");
939
+ }
940
+ /**
941
+ * Clears all jobs and stops the scheduler.
942
+ */
943
+ destroy() {
944
+ this.stop();
945
+ this.jobs.clear();
946
+ this.wakeups.clear();
947
+ this.wakeupChainStartedAt = null;
948
+ this.pendingRemoval.clear();
949
+ this.pendingAdd.clear();
950
+ }
951
+ };
952
+ function buildMissedCronNotification(missed) {
953
+ const plural = missed.length > 1;
954
+ const header = `The following one-shot scheduled task${plural ? "s were" : " was"} missed while Qwen Code was not running. ${plural ? "They have" : "It has"} been removed from ${CRON_TASKS_DISPLAY_PATH} and will not fire again.
955
+
956
+ Do NOT execute ${plural ? "these prompts" : "this prompt"} yet. First ask the user whether to run ${plural ? "each one" : "it"} now (use the ${ToolNames.ASK_USER_QUESTION} tool if available). Only execute if the user confirms.`;
957
+ const blocks = missed.map((task) => {
958
+ const meta = `[${humanReadableCron(task.cron)}, created ${new Date(task.createdAt).toLocaleString()}]`;
959
+ const longestRun = (task.prompt.match(/`+/g) ?? []).reduce(
960
+ (max, run) => Math.max(max, run.length),
961
+ 0
962
+ );
963
+ const fence = "`".repeat(Math.max(3, longestRun + 1));
964
+ return `${meta}
965
+ ${fence}
966
+ ${task.prompt}
967
+ ${fence}`;
968
+ });
969
+ return `${header}
970
+
971
+ ${blocks.join("\n\n")}`;
972
+ }
973
+ __name(buildMissedCronNotification, "buildMissedCronNotification");
974
+ function hasParseableCron(task) {
975
+ try {
976
+ parseCron(task.cron);
977
+ return true;
978
+ } catch {
979
+ return false;
980
+ }
981
+ }
982
+ __name(hasParseableCron, "hasParseableCron");
983
+ function durableTaskToJob(task, existing) {
984
+ const jitterMs = existing && existing.cronExpr === task.cron && existing.recurring === task.recurring ? existing.jitterMs : computeJitter(task.id, task.cron, task.recurring);
985
+ return {
986
+ id: task.id,
987
+ cronExpr: task.cron,
988
+ prompt: task.prompt,
989
+ recurring: task.recurring,
990
+ createdAt: task.createdAt,
991
+ expiresAt: task.recurring ? task.createdAt + RECURRING_MAX_AGE_MS : Infinity,
992
+ lastFiredAt: task.lastFiredAt ?? void 0,
993
+ jitterMs,
994
+ durable: true
995
+ };
996
+ }
997
+ __name(durableTaskToJob, "durableTaskToJob");
998
+ function jobToDurableTask(job) {
999
+ return {
1000
+ id: job.id,
1001
+ cron: job.cronExpr,
1002
+ prompt: job.prompt,
1003
+ recurring: job.recurring,
1004
+ createdAt: job.createdAt,
1005
+ lastFiredAt: job.lastFiredAt ?? null
1006
+ };
1007
+ }
1008
+ __name(jobToDurableTask, "jobToDurableTask");
1009
+ function computeNextFireMs(cronExpr, afterMs, jitterMs) {
1010
+ try {
1011
+ const afterDate = new Date(afterMs);
1012
+ const next = nextFireTime(cronExpr, afterDate);
1013
+ return next.getTime() + jitterMs;
1014
+ } catch {
1015
+ return null;
1016
+ }
1017
+ }
1018
+ __name(computeNextFireMs, "computeNextFireMs");
1019
+
1020
+ export {
1021
+ WAKEUP_MIN_SECONDS,
1022
+ WAKEUP_MAX_SECONDS,
1023
+ clampWakeupSeconds,
1024
+ CronScheduler,
1025
+ buildMissedCronNotification
1026
+ };