@qwen-code/qwen-code 0.18.5-nightly.20260622.6bc3f853e → 0.18.5-preview.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/bundled/qc-helper/SKILL.md +13 -5
  2. package/bundled/qc-helper/docs/configuration/_meta.ts +1 -0
  3. package/bundled/qc-helper/docs/configuration/auth.md +68 -48
  4. package/bundled/qc-helper/docs/configuration/model-providers.md +217 -195
  5. package/bundled/qc-helper/docs/configuration/qwen-ignore.md +31 -15
  6. package/bundled/qc-helper/docs/configuration/settings.md +44 -27
  7. package/bundled/qc-helper/docs/configuration/themes.md +7 -4
  8. package/bundled/qc-helper/docs/extension/extension-releasing.md +1 -1
  9. package/bundled/qc-helper/docs/extension/introduction.md +27 -21
  10. package/bundled/qc-helper/docs/features/arena.md +3 -3
  11. package/bundled/qc-helper/docs/features/channels/overview.md +1 -1
  12. package/bundled/qc-helper/docs/features/channels/plugins.md +1 -1
  13. package/bundled/qc-helper/docs/features/commands.md +6 -1
  14. package/bundled/qc-helper/docs/features/headless.md +1 -1
  15. package/bundled/qc-helper/docs/features/mcp.md +33 -14
  16. package/bundled/qc-helper/docs/features/sandbox.md +2 -2
  17. package/bundled/qc-helper/docs/features/tool-use-summaries.md +1 -1
  18. package/bundled/qc-helper/docs/integration-github-action.md +2 -2
  19. package/bundled/qc-helper/docs/overview.md +1 -1
  20. package/bundled/qc-helper/docs/quickstart.md +9 -5
  21. package/bundled/qc-helper/docs/qwen-serve.md +14 -2
  22. package/bundled/qc-helper/docs/support/tos-privacy.md +1 -1
  23. package/chunks/{agent-WFLPE5MW.js → agent-P4KSTVXX.js} +24 -22
  24. package/chunks/{agent-headless-Q27MG73I.js → agent-headless-QUAPWF55.js} +24 -22
  25. package/chunks/{anthropicContentGenerator-5S4OMMNL.js → anthropicContentGenerator-7352A7I5.js} +12 -11
  26. package/chunks/artifact-tool-5J4HUZAV.js +675 -0
  27. package/chunks/{askUserQuestion-WHVYL2S2.js → askUserQuestion-HF7HCWDD.js} +20 -7
  28. package/chunks/chunk-22IFUCVR.js +291 -0
  29. package/chunks/{chunk-26ZYKTYZ.js → chunk-2BIF2NVV.js} +2 -2
  30. package/chunks/{chunk-VKILGMZQ.js → chunk-2QDQTWCI.js} +1 -1
  31. package/chunks/{chunk-XGU3ETVO.js → chunk-3BR4OIOE.js} +3 -3
  32. package/chunks/{chunk-LTN3VYMZ.js → chunk-3UALQ56H.js} +1 -1
  33. package/chunks/{chunk-QBUR6J4B.js → chunk-BC5POO46.js} +8 -7
  34. package/chunks/{chunk-MSJ2MXJ6.js → chunk-BGUDAULQ.js} +11 -290
  35. package/chunks/{chunk-FH4P6RQA.js → chunk-BNXANYLH.js} +1 -1
  36. package/chunks/{chunk-WE6TNQJU.js → chunk-C4K3FEQ2.js} +36 -0
  37. package/chunks/{chunk-G4BUMVEY.js → chunk-CGEGHF2C.js} +2 -217
  38. package/chunks/chunk-EEEZIVFJ.js +908 -0
  39. package/chunks/{chunk-7Z2O7IBO.js → chunk-EIJYMXXX.js} +619 -135
  40. package/chunks/chunk-EJYJYJZ2.js +3703 -0
  41. package/chunks/{chunk-ATLUHLZE.js → chunk-EW6C27XX.js} +1 -1
  42. package/chunks/{chunk-42HGOMED.js → chunk-F6XNTYNE.js} +216 -1
  43. package/chunks/{chunk-C6MI2ASN.js → chunk-GZCJS5WH.js} +2 -2
  44. package/chunks/{chunk-KGV3F6UF.js → chunk-HGNSRCRB.js} +1 -1
  45. package/chunks/{chunk-CX3SGIPK.js → chunk-KBXLIVWQ.js} +2 -2
  46. package/chunks/{chunk-GOMVJKBL.js → chunk-L7U2RI5O.js} +59 -57
  47. package/chunks/{chunk-GBN55AWZ.js → chunk-NKJ6LRCR.js} +2 -2
  48. package/chunks/{chunk-2O3NAOJG.js → chunk-NWLUISRA.js} +1 -1
  49. package/chunks/{chunk-ID533GA3.js → chunk-OTBK43JR.js} +1 -1
  50. package/chunks/{chunk-AE6RQU6F.js → chunk-PRYMDRBV.js} +1 -1
  51. package/chunks/{chunk-KQIKOTQJ.js → chunk-RYLJU2DY.js} +60 -5
  52. package/chunks/{chunk-CTHZVIMD.js → chunk-T2VDEFUU.js} +2 -2
  53. package/chunks/{chunk-SWGPABMH.js → chunk-T336V435.js} +80 -83
  54. package/chunks/{chunk-LF6BKGZT.js → chunk-TXVGVZYR.js} +3 -3
  55. package/chunks/{chunk-GM3LTU6K.js → chunk-UMRZ7XCR.js} +170 -5015
  56. package/chunks/{chunk-XU7BKR3B.js → chunk-XU5P23GN.js} +3 -3
  57. package/chunks/{chunk-EJ6NFQ2L.js → chunk-ZC675NGC.js} +5 -5
  58. package/chunks/{chunk-CXZV4Q4J.js → chunk-ZXNEOCW2.js} +7118 -5113
  59. package/chunks/{computer-use-F5O56FVW.js → computer-use-4TLHI3UR.js} +24 -22
  60. package/chunks/contextCommand-HFEITKSR.js +56 -0
  61. package/chunks/{cron-create-THNDTYXU.js → cron-create-A5637KCI.js} +12 -9
  62. package/chunks/{cron-delete-BS5H6TFJ.js → cron-delete-AADOSEOZ.js} +4 -4
  63. package/chunks/{cron-list-7OBVHT7K.js → cron-list-OFCPTT2Y.js} +4 -4
  64. package/chunks/{dist-GKRNVFBH.js → dist-ZBX7LPJZ.js} +2 -1
  65. package/chunks/{edit-UV7MBOJU.js → edit-B7H73V6O.js} +24 -22
  66. package/chunks/{en-S3OQBISC.js → en-7OGNWWME.js} +48 -0
  67. package/chunks/{enter-worktree-TSCHZMJ3.js → enter-worktree-GG7ZHYPS.js} +24 -22
  68. package/chunks/{enterPlanMode-LKS7VIUG.js → enterPlanMode-RHTAKG52.js} +27 -23
  69. package/chunks/{exit-worktree-Q6EWFLZU.js → exit-worktree-U7VQZRMG.js} +24 -22
  70. package/chunks/{exitPlanMode-HS6I4D2O.js → exitPlanMode-S35A36II.js} +36 -28
  71. package/chunks/{geminiContentGenerator-GEZ63VSW.js → geminiContentGenerator-W7KVATBA.js} +4 -4
  72. package/chunks/{glob-ZN5LKB7E.js → glob-WOFF7ECI.js} +26 -23
  73. package/chunks/{grep-NIKBBYBU.js → grep-MWNYWYWQ.js} +24 -22
  74. package/chunks/{keychain-token-storage-YHXIWXIB.js → keychain-token-storage-CSYMNRPP.js} +2 -2
  75. package/chunks/{loop-wakeup-SSBWZ64K.js → loop-wakeup-DGSMT4N6.js} +5 -5
  76. package/chunks/{ls-YPFUHZRQ.js → ls-UGRZ4ZOM.js} +6 -6
  77. package/chunks/{lsp-FD6DNVAF.js → lsp-72IJURW3.js} +2 -2
  78. package/chunks/{monitor-A25XKPU5.js → monitor-AYUINLYN.js} +24 -22
  79. package/chunks/{notebook-edit-E72AIOUS.js → notebook-edit-EP4D4WFD.js} +25 -23
  80. package/chunks/{openaiContentGenerator-ZDLZDXLU.js → openaiContentGenerator-SLYYF7AM.js} +12 -15
  81. package/chunks/{qwenContentGenerator-HVJPPMTT.js → qwenContentGenerator-VZ7JYU4A.js} +26 -24
  82. package/chunks/{qwenOAuth2-WZ54YZ4J.js → qwenOAuth2-K4AASPCV.js} +5 -4
  83. package/chunks/{read-file-L6FM3KUX.js → read-file-65EQ53KS.js} +9 -8
  84. package/chunks/{ripGrep-YRJCUISE.js → ripGrep-5XLHJDDM.js} +24 -22
  85. package/chunks/{scheduler-M3742P2I.js → scheduler-5GLJSA2H.js} +73 -27
  86. package/chunks/{send-message-FWFTX62Q.js → send-message-URUZ7PLA.js} +24 -4
  87. package/chunks/{serve-ZIP2GDFY.js → serve-MUROZGCG.js} +618 -92
  88. package/chunks/{shell-T5VSPJLU.js → shell-ET3BQWKB.js} +24 -22
  89. package/chunks/{skill-ETTFYDOV.js → skill-YEYABCAF.js} +11 -10
  90. package/chunks/{src-UKOPSYDK.js → src-POVOI65Y.js} +140 -67
  91. package/chunks/{syntheticOutput-JY5NEDTV.js → syntheticOutput-65FRJGWM.js} +3 -3
  92. package/chunks/{task-create-IGILDV25.js → task-create-IH45HOFT.js} +6 -6
  93. package/chunks/{task-list-KBEJVAAG.js → task-list-FUB6JWSX.js} +5 -5
  94. package/chunks/{task-stop-WFTMQ6AC.js → task-stop-P6IOHQM3.js} +2 -2
  95. package/chunks/{task-update-UIVX7ZEV.js → task-update-RTUT7LJV.js} +6 -6
  96. package/chunks/{team-create-DRKUVGBN.js → team-create-EFZFKQFP.js} +28 -26
  97. package/chunks/{team-delete-LPOXDPVB.js → team-delete-RXGYRMHC.js} +5 -5
  98. package/chunks/{todoWrite-R4RIJKOD.js → todoWrite-O6JK24G6.js} +4 -4
  99. package/chunks/{tool-search-EIIK27ON.js → tool-search-BRJC42TE.js} +9 -8
  100. package/chunks/{web-fetch-JU7SS6KE.js → web-fetch-KUMBROUI.js} +4 -4
  101. package/chunks/{workflow-4RGAYFSJ.js → workflow-UDRBNFTT.js} +557 -97
  102. package/chunks/{write-file-GLQYJFEZ.js → write-file-F7TAHAHF.js} +24 -22
  103. package/chunks/{zh-QXLZV2PX.js → zh-3RMSEO5M.js} +48 -0
  104. package/chunks/{zh-TW-3OKU7LDA.js → zh-TW-R7WRLTJS.js} +48 -0
  105. package/cli.js +8473 -5091
  106. package/locales/en.js +69 -0
  107. package/locales/zh-TW.js +66 -0
  108. package/locales/zh.js +66 -0
  109. package/package.json +3 -2
  110. package/web-shell/assets/{arc-CRFN10gD.js → arc-DHUeMnnj.js} +1 -1
  111. package/web-shell/assets/{architectureDiagram-3BPJPVTR-IRlu1CpH.js → architectureDiagram-3BPJPVTR-DlX12yyj.js} +1 -1
  112. package/web-shell/assets/{blockDiagram-GPEHLZMM-htIZ6iw8.js → blockDiagram-GPEHLZMM-DTFUXMUT.js} +1 -1
  113. package/web-shell/assets/{c4Diagram-AAUBKEIU-A2GoRq3O.js → c4Diagram-AAUBKEIU-CWdB54fk.js} +1 -1
  114. package/web-shell/assets/channel-C3WhMjjP.js +1 -0
  115. package/web-shell/assets/{chunk-2J33WTMH-CdP2AC6u.js → chunk-2J33WTMH-CF5C5jNR.js} +1 -1
  116. package/web-shell/assets/{chunk-4BX2VUAB-DrA07nW2.js → chunk-4BX2VUAB-Cw7Ydfji.js} +1 -1
  117. package/web-shell/assets/{chunk-55IACEB6-CFGnVU2f.js → chunk-55IACEB6-CnbI1ZCw.js} +1 -1
  118. package/web-shell/assets/{chunk-727SXJPM-BTMkq3Tk.js → chunk-727SXJPM-DmSy00Pe.js} +1 -1
  119. package/web-shell/assets/{chunk-AQP2D5EJ-C9sYg04Z.js → chunk-AQP2D5EJ-DgNgXqBu.js} +1 -1
  120. package/web-shell/assets/{chunk-FMBD7UC4-Cag-cj6I.js → chunk-FMBD7UC4-tz2IvOXv.js} +1 -1
  121. package/web-shell/assets/{chunk-ND2GUHAM-CDSTFoR7.js → chunk-ND2GUHAM-DaBLEBPa.js} +1 -1
  122. package/web-shell/assets/{chunk-QZHKN3VN-CN9Z6oOs.js → chunk-QZHKN3VN-DVCQST3O.js} +1 -1
  123. package/web-shell/assets/classDiagram-4FO5ZUOK-CQ6TXPif.js +1 -0
  124. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CQ6TXPif.js +1 -0
  125. package/web-shell/assets/{cose-bilkent-S5V4N54A-DuN9j8Du.js → cose-bilkent-S5V4N54A-CAKTcdCQ.js} +1 -1
  126. package/web-shell/assets/{dagre-BM42HDAG-ByCWe45f.js → dagre-BM42HDAG-BdkBwlKg.js} +1 -1
  127. package/web-shell/assets/{diagram-2AECGRRQ-eWyU_pKZ.js → diagram-2AECGRRQ-DYt3G65F.js} +1 -1
  128. package/web-shell/assets/{diagram-5GNKFQAL-0Bfu3Fq5.js → diagram-5GNKFQAL-BWvROWjY.js} +1 -1
  129. package/web-shell/assets/{diagram-KO2AKTUF-B6KBKkQP.js → diagram-KO2AKTUF-BvvgwIaQ.js} +1 -1
  130. package/web-shell/assets/{diagram-LMA3HP47-TToDmeA_.js → diagram-LMA3HP47-E7NLSNKg.js} +1 -1
  131. package/web-shell/assets/{diagram-OG6HWLK6-CQCkC2Yx.js → diagram-OG6HWLK6-CYmUBgpE.js} +1 -1
  132. package/web-shell/assets/{erDiagram-TEJ5UH35-Cm9ls1iB.js → erDiagram-TEJ5UH35-BU5gY30h.js} +1 -1
  133. package/web-shell/assets/{flowDiagram-I6XJVG4X-Dyoz80Pv.js → flowDiagram-I6XJVG4X-V_ZssSZ9.js} +1 -1
  134. package/web-shell/assets/{ganttDiagram-6RSMTGT7-Cfut9yaU.js → ganttDiagram-6RSMTGT7-QIShlsdI.js} +1 -1
  135. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BCuJdlfD.js → gitGraphDiagram-PVQCEYII-DJxdu2YS.js} +1 -1
  136. package/web-shell/assets/index-BPnhI7gl.css +1 -0
  137. package/web-shell/assets/index-De4rqTsW.js +706 -0
  138. package/web-shell/assets/{infoDiagram-5YYISTIA-CXKxF2VL.js → infoDiagram-5YYISTIA-BqjdrFeO.js} +1 -1
  139. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-DE7HWSU8.js → ishikawaDiagram-YF4QCWOH-BP_a2YZ2.js} +1 -1
  140. package/web-shell/assets/{journeyDiagram-JHISSGLW-D__YUfds.js → journeyDiagram-JHISSGLW-BXg-S3Lk.js} +1 -1
  141. package/web-shell/assets/{kanban-definition-UN3LZRKU-D82R169M.js → kanban-definition-UN3LZRKU-BksAkdEJ.js} +1 -1
  142. package/web-shell/assets/{linear-DpyMbKqT.js → linear-D2m9-ODE.js} +1 -1
  143. package/web-shell/assets/{mermaid.core-D1KEFDhn.js → mermaid.core-dTtkZp2F.js} +5 -5
  144. package/web-shell/assets/{mindmap-definition-RKZ34NQL-BwVUFGFE.js → mindmap-definition-RKZ34NQL-Bft9my8O.js} +1 -1
  145. package/web-shell/assets/{pieDiagram-4H26LBE5-BO_qoEGx.js → pieDiagram-4H26LBE5-Cw8S-alZ.js} +1 -1
  146. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-Cx0ZaWPo.js → quadrantDiagram-W4KKPZXB-DaDoTMts.js} +1 -1
  147. package/web-shell/assets/{requirementDiagram-4Y6WPE33-BJPXejOA.js → requirementDiagram-4Y6WPE33-Cp5kSpwj.js} +1 -1
  148. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-C1xeIL9i.js → sankeyDiagram-5OEKKPKP-CW8RsJJZ.js} +1 -1
  149. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-CSYKQUjf.js → sequenceDiagram-3UESZ5HK-DTfpIiJK.js} +1 -1
  150. package/web-shell/assets/{stateDiagram-AJRCARHV-d9hiHlAW.js → stateDiagram-AJRCARHV-DixFVzEs.js} +1 -1
  151. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DZgE04s3.js +1 -0
  152. package/web-shell/assets/{timeline-definition-PNZ67QCA-BhCBkq8k.js → timeline-definition-PNZ67QCA-DYsbXn5l.js} +1 -1
  153. package/web-shell/assets/{vennDiagram-CIIHVFJN-DPPFWp_y.js → vennDiagram-CIIHVFJN-HUpRpuUp.js} +1 -1
  154. package/web-shell/assets/{wardley-L42UT6IY-CcOUIgXY.js → wardley-L42UT6IY-cT3nQH_T.js} +1 -1
  155. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-p7oR5X7r.js → wardleyDiagram-YWT4CUSO-Dmm7J6Qc.js} +1 -1
  156. package/web-shell/assets/{xychartDiagram-2RQKCTM6-Dfr7-SEy.js → xychartDiagram-2RQKCTM6-CX0L5p9C.js} +1 -1
  157. package/web-shell/index.html +3 -3
  158. package/chunks/chunk-77WXWU44.js +0 -26
  159. package/chunks/contextCommand-WBVNKL2C.js +0 -54
  160. package/web-shell/assets/channel-WwImfsc7.js +0 -1
  161. package/web-shell/assets/classDiagram-4FO5ZUOK-CJKQYFeJ.js +0 -1
  162. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CJKQYFeJ.js +0 -1
  163. package/web-shell/assets/index-BDZiTAkl.css +0 -1
  164. package/web-shell/assets/index-DaebdpHq.js +0 -516
  165. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DgReoybQ.js +0 -1
@@ -4,57 +4,68 @@ import {
4
4
  AgentEventEmitter,
5
5
  FileDiscoveryService,
6
6
  GitWorktreeService,
7
- WorkspaceContext,
8
7
  generateAgentWorktreeSlug,
8
+ parsePositiveIntegerEnv,
9
9
  rebuildToolRegistryOnOverride,
10
+ resolveSavedWorkflowScript,
10
11
  stripAnsiAndControl,
12
+ writeWorkflowSnapshot,
11
13
  writeWorktreeSessionMarker
12
- } from "./chunk-CXZV4Q4J.js";
14
+ } from "./chunk-ZXNEOCW2.js";
13
15
  import "./chunk-K5PGHDBN.js";
14
- import "./chunk-XU7BKR3B.js";
15
- import "./chunk-2O3NAOJG.js";
16
- import "./chunk-XGU3ETVO.js";
16
+ import "./chunk-TXVGVZYR.js";
17
+ import "./chunk-XU5P23GN.js";
18
+ import "./chunk-2BIF2NVV.js";
19
+ import "./chunk-NWLUISRA.js";
20
+ import "./chunk-3BR4OIOE.js";
17
21
  import "./chunk-2MPVVENX.js";
18
22
  import "./chunk-ZTQ26VBE.js";
19
- import "./chunk-C6MI2ASN.js";
20
- import "./chunk-LF6BKGZT.js";
21
- import "./chunk-26ZYKTYZ.js";
23
+ import "./chunk-GZCJS5WH.js";
22
24
  import "./chunk-MLZQVCF3.js";
23
25
  import "./chunk-LD2XBG6Z.js";
24
- import "./chunk-ID533GA3.js";
25
- import "./chunk-KGV3F6UF.js";
26
- import "./chunk-77WXWU44.js";
27
- import "./chunk-AE6RQU6F.js";
28
- import "./chunk-GM3LTU6K.js";
26
+ import "./chunk-OTBK43JR.js";
27
+ import "./chunk-HGNSRCRB.js";
28
+ import {
29
+ WorkspaceContext
30
+ } from "./chunk-EEEZIVFJ.js";
31
+ import "./chunk-PRYMDRBV.js";
32
+ import {
33
+ WorkflowRunEvent,
34
+ logWorkflowRun,
35
+ read,
36
+ writeLine
37
+ } from "./chunk-UMRZ7XCR.js";
29
38
  import "./chunk-3PJXIDKI.js";
30
39
  import "./chunk-UWCTAVOD.js";
31
40
  import "./chunk-OFEVLU4C.js";
32
41
  import "./chunk-OMX7CUOE.js";
33
- import "./chunk-FH4P6RQA.js";
34
- import "./chunk-CTHZVIMD.js";
42
+ import "./chunk-BNXANYLH.js";
43
+ import "./chunk-T2VDEFUU.js";
35
44
  import {
36
45
  SyntheticOutputTool
37
- } from "./chunk-VKILGMZQ.js";
46
+ } from "./chunk-2QDQTWCI.js";
38
47
  import {
39
48
  BaseDeclarativeTool,
40
49
  BaseToolInvocation,
41
50
  ToolDisplayNames,
42
51
  ToolNames
43
- } from "./chunk-GOMVJKBL.js";
44
- import "./chunk-MSJ2MXJ6.js";
45
- import "./chunk-ATLUHLZE.js";
52
+ } from "./chunk-L7U2RI5O.js";
53
+ import "./chunk-BGUDAULQ.js";
54
+ import "./chunk-EW6C27XX.js";
55
+ import "./chunk-22IFUCVR.js";
46
56
  import {
47
57
  createChildAbortController
48
58
  } from "./chunk-64WXLC72.js";
49
- import "./chunk-LTN3VYMZ.js";
50
- import "./chunk-42HGOMED.js";
51
- import "./chunk-G4BUMVEY.js";
59
+ import "./chunk-3UALQ56H.js";
60
+ import "./chunk-F6XNTYNE.js";
61
+ import "./chunk-CGEGHF2C.js";
62
+ import "./chunk-EJYJYJZ2.js";
52
63
  import "./chunk-55ZMG67I.js";
53
64
  import "./chunk-H6BD2ELD.js";
54
65
  import "./chunk-5IFG2VC4.js";
55
66
  import {
56
67
  createDebugLogger
57
- } from "./chunk-WE6TNQJU.js";
68
+ } from "./chunk-C4K3FEQ2.js";
58
69
  import "./chunk-ZERZSAZL.js";
59
70
  import "./chunk-QN5NZ3UQ.js";
60
71
  import "./chunk-BR4QREVK.js";
@@ -358,9 +369,11 @@ function createWorkflowSandbox(opts) {
358
369
  // init script without leaking the host function itself when not used.
359
370
  hasParallel: !!opts.parallel,
360
371
  hasPipeline: !!opts.pipeline,
372
+ hasWorkflow: !!opts.workflow,
361
373
  hasBudget: !!opts.budget,
362
374
  hostParallel: opts.parallel,
363
375
  hostPipeline: opts.pipeline,
376
+ hostWorkflow: opts.workflow,
364
377
  budgetTotal: opts.budget ? opts.budget.total : null,
365
378
  hostBudgetSpent: opts.budget ? opts.budget.spent.bind(opts.budget) : null,
366
379
  hostBudgetRemaining: opts.budget ? opts.budget.remaining.bind(opts.budget) : null
@@ -466,7 +479,7 @@ function createWorkflowSandbox(opts) {
466
479
  // FIX-Round1-T13: throw on any opts key not in the allowlist \u2014 catches
467
480
  // typos like { scema: ... } that previously slipped through the
468
481
  // [key:string]: unknown index signature.
469
- const KNOWN_AGENT_OPTS = ['label', 'phase', 'schema', 'model', 'isolation', 'agentType'];
482
+ const KNOWN_AGENT_OPTS = ['label', 'phase', 'schema', 'model', 'isolation', 'agentType', 'stallMs'];
470
483
  globalThis.agent = vmAsync(function (prompt, agentOpts) {
471
484
  agentOpts = agentOpts || {};
472
485
  const keys = Object.keys(agentOpts);
@@ -639,15 +652,64 @@ function createWorkflowSandbox(opts) {
639
652
  });
640
653
  };
641
654
  }
642
- // workflow() always throws in P1.
643
- globalThis.workflow = function workflow() {
644
- return new Promise(function (_, reject) {
645
- reject(new Error(
646
- 'workflow() (nested workflow invocation) is not supported in P1. ' +
647
- 'Scheduled for a later phase.'
648
- ));
655
+ // --- workflow (nested, single-level) ---
656
+ // Mirrors agent(): args cross vm\u2192host verbatim (safe direction), the
657
+ // single result is revived back into the vm realm via JSON round-trip
658
+ // (same T1/T8/T14 escape defense as agent / parallel / pipeline). The
659
+ // host impl resolves a saved workflow and runs it sharing this run's
660
+ // agent-count cap + token budget. When __b.hasWorkflow is false, the
661
+ // sandbox is either bare (no resolver wired) OR is itself a nested
662
+ // workflow \u2014 in both cases workflow() must throw, which is how the
663
+ // single-level nesting limit is enforced (a nested sandbox is created
664
+ // without a workflow impl, so its workflow() lands in the else branch).
665
+ if (__b.hasWorkflow) {
666
+ const callWorkflow = vmAsync(function (nameOrRef, wfArgs) {
667
+ // Sanitize args through a JSON round-trip BEFORE crossing so the
668
+ // host only ever sees vm-realm plain objects (same defense as
669
+ // agent()'s safeOpts). nameOrRef may be a string or {scriptPath}.
670
+ var safeRef;
671
+ var safeArgs;
672
+ try {
673
+ safeRef = nameOrRef === undefined
674
+ ? undefined
675
+ : JSON.parse(JSON.stringify(nameOrRef));
676
+ safeArgs = wfArgs === undefined
677
+ ? undefined
678
+ : JSON.parse(JSON.stringify(wfArgs));
679
+ } catch (e) {
680
+ throw new Error(
681
+ 'workflow() received a non-JSON-serializable argument: ' +
682
+ String(e && e.message != null ? e.message : e)
683
+ );
684
+ }
685
+ return __b.hostWorkflow(safeRef, safeArgs).then(function (value) {
686
+ if (value === null || typeof value !== 'object') {
687
+ return value;
688
+ }
689
+ try {
690
+ return JSON.parse(JSON.stringify(value));
691
+ } catch (e) {
692
+ __b.logRevivalFailure(0, String(e && e.message != null ? e.message : e));
693
+ return null;
694
+ }
695
+ });
649
696
  });
650
- };
697
+ globalThis.workflow = function workflow(nameOrRef, wfArgs) {
698
+ return callWorkflow(nameOrRef, wfArgs);
699
+ };
700
+ } else {
701
+ globalThis.workflow = function workflow() {
702
+ return new Promise(function (_, reject) {
703
+ reject(new Error(
704
+ "workflow() is unavailable here. Either this sandbox was created " +
705
+ "without a saved-workflow resolver, or this script is already " +
706
+ "running as a nested workflow \u2014 workflow() nesting is limited to " +
707
+ "a single level (a workflow cannot call another workflow that " +
708
+ "itself calls workflow())."
709
+ ));
710
+ });
711
+ };
712
+ }
651
713
 
652
714
  // --- budget ---
653
715
  const safeBudget = Object.create(null);
@@ -738,8 +800,8 @@ function resolveMaxTokensPerWorkflow(env = process.env) {
738
800
  if (raw === void 0 || raw.trim() === "") {
739
801
  return null;
740
802
  }
741
- const parsed = Number(raw);
742
- if (!Number.isInteger(parsed) || parsed < 1) {
803
+ const parsed = parsePositiveIntegerEnv(raw, 0);
804
+ if (parsed < 1) {
743
805
  debugLogger2.warn(
744
806
  `Invalid ${MAX_TOKENS_PER_WORKFLOW_ENV}=${JSON.stringify(raw)}, treating as unset (no cap)`
745
807
  );
@@ -813,6 +875,231 @@ var WorkflowBudgetExceededError = class extends Error {
813
875
  }
814
876
  };
815
877
 
878
+ // packages/core/src/agents/runtime/workflow-stall.ts
879
+ init_esbuild_shims();
880
+ var DEFAULT_STALL_MS = 6e4;
881
+ var MAX_STALL_ATTEMPTS = 3;
882
+ var MAX_WORKFLOW_STALL_MS_ENV = "QWEN_CODE_WORKFLOW_STALL_SECONDS";
883
+ function resolveStallMs(perCall, env = process.env) {
884
+ if (typeof perCall === "number" && Number.isFinite(perCall)) {
885
+ if (perCall === 0) return 0;
886
+ if (perCall > 0) return perCall;
887
+ }
888
+ const raw = env[MAX_WORKFLOW_STALL_MS_ENV];
889
+ if (raw !== void 0 && raw.trim() !== "") {
890
+ const sec = Number(raw);
891
+ if (Number.isFinite(sec) && sec > 0) return sec * 1e3;
892
+ if (sec === 0) return 0;
893
+ }
894
+ return DEFAULT_STALL_MS;
895
+ }
896
+ __name(resolveStallMs, "resolveStallMs");
897
+ var debugLogger3 = createDebugLogger("WORKFLOW_STALL");
898
+ function attachStallWatchdog(emitter, controller, stallMs) {
899
+ if (stallMs <= 0) {
900
+ return { stalled: /* @__PURE__ */ __name(() => false, "stalled"), dispose: /* @__PURE__ */ __name(() => {
901
+ }, "dispose") };
902
+ }
903
+ let inFlightTools = 0;
904
+ let fired = false;
905
+ let timer;
906
+ let disposed = false;
907
+ const clear = /* @__PURE__ */ __name(() => {
908
+ if (timer) {
909
+ clearTimeout(timer);
910
+ timer = void 0;
911
+ }
912
+ }, "clear");
913
+ const arm = /* @__PURE__ */ __name(() => {
914
+ clear();
915
+ if (disposed || fired) return;
916
+ if (inFlightTools > 0) return;
917
+ timer = setTimeout(() => {
918
+ if (disposed || fired) return;
919
+ fired = true;
920
+ debugLogger3.warn(
921
+ `[Workflow] agent dispatch stalled \u2014 no progress for ${stallMs}ms; aborting.`
922
+ );
923
+ try {
924
+ controller.abort("stalled");
925
+ } catch (e) {
926
+ debugLogger3.warn("stall watchdog abort threw:", e);
927
+ }
928
+ }, stallMs);
929
+ if (typeof timer.unref === "function") {
930
+ timer.unref();
931
+ }
932
+ }, "arm");
933
+ const onActivity = /* @__PURE__ */ __name(() => arm(), "onActivity");
934
+ const onToolCall = /* @__PURE__ */ __name(() => {
935
+ inFlightTools += 1;
936
+ clear();
937
+ }, "onToolCall");
938
+ const onToolResult = /* @__PURE__ */ __name(() => {
939
+ inFlightTools = Math.max(0, inFlightTools - 1);
940
+ arm();
941
+ }, "onToolResult");
942
+ emitter.on("round_start" /* ROUND_START */, onActivity);
943
+ emitter.on("round_end" /* ROUND_END */, onActivity);
944
+ emitter.on("stream_text" /* STREAM_TEXT */, onActivity);
945
+ emitter.on("usage_metadata" /* USAGE_METADATA */, onActivity);
946
+ emitter.on("tool_call" /* TOOL_CALL */, onToolCall);
947
+ emitter.on("tool_result" /* TOOL_RESULT */, onToolResult);
948
+ return {
949
+ stalled: /* @__PURE__ */ __name(() => fired, "stalled"),
950
+ dispose: /* @__PURE__ */ __name(() => {
951
+ if (disposed) return;
952
+ disposed = true;
953
+ clear();
954
+ emitter.off("round_start" /* ROUND_START */, onActivity);
955
+ emitter.off("round_end" /* ROUND_END */, onActivity);
956
+ emitter.off("stream_text" /* STREAM_TEXT */, onActivity);
957
+ emitter.off("usage_metadata" /* USAGE_METADATA */, onActivity);
958
+ emitter.off("tool_call" /* TOOL_CALL */, onToolCall);
959
+ emitter.off("tool_result" /* TOOL_RESULT */, onToolResult);
960
+ }, "dispose")
961
+ };
962
+ }
963
+ __name(attachStallWatchdog, "attachStallWatchdog");
964
+ async function runStallResilient(attemptFn, opts) {
965
+ const { stallMs, signal, label } = opts;
966
+ if (stallMs <= 0) {
967
+ const emitter = new AgentEventEmitter();
968
+ return attemptFn(signal ?? new AbortController().signal, emitter);
969
+ }
970
+ let attempt = 0;
971
+ for (; ; ) {
972
+ attempt += 1;
973
+ const controller = new AbortController();
974
+ let onParentAbort;
975
+ if (signal) {
976
+ if (signal.aborted) {
977
+ controller.abort(signal.reason);
978
+ } else {
979
+ onParentAbort = /* @__PURE__ */ __name(() => controller.abort(signal.reason), "onParentAbort");
980
+ signal.addEventListener("abort", onParentAbort);
981
+ }
982
+ }
983
+ const emitter = new AgentEventEmitter();
984
+ const watchdog = attachStallWatchdog(emitter, controller, stallMs);
985
+ try {
986
+ return await attemptFn(controller.signal, emitter);
987
+ } catch (err) {
988
+ if (signal?.aborted) throw err;
989
+ if (watchdog.stalled() && attempt < MAX_STALL_ATTEMPTS) {
990
+ debugLogger3.warn(
991
+ `[Workflow] agent "${label ?? "workflow-agent"}" stalled (attempt ${attempt}/${MAX_STALL_ATTEMPTS}) \u2014 retrying.`
992
+ );
993
+ continue;
994
+ }
995
+ if (watchdog.stalled()) {
996
+ throw new Error(
997
+ `agent "${label ?? "workflow-agent"}" stalled on all ${MAX_STALL_ATTEMPTS} attempts (no progress for ${stallMs}ms each).`
998
+ );
999
+ }
1000
+ throw err;
1001
+ } finally {
1002
+ watchdog.dispose();
1003
+ if (onParentAbort && signal) {
1004
+ signal.removeEventListener("abort", onParentAbort);
1005
+ }
1006
+ }
1007
+ }
1008
+ }
1009
+ __name(runStallResilient, "runStallResilient");
1010
+
1011
+ // packages/core/src/agents/runtime/workflow-journal.ts
1012
+ init_esbuild_shims();
1013
+ import { createHash } from "node:crypto";
1014
+ var debugLogger4 = createDebugLogger("WORKFLOW_JOURNAL");
1015
+ var JOURNAL_KEY_VERSION = "v2";
1016
+ function canonicalizeAgentOpts(opts) {
1017
+ const projected = {};
1018
+ for (const k of ["schema", "model", "isolation", "agentType"]) {
1019
+ const v = opts[k];
1020
+ if (v === void 0 || typeof v === "function") continue;
1021
+ projected[k] = v;
1022
+ }
1023
+ const sortDeep = /* @__PURE__ */ __name((val) => {
1024
+ if (typeof val === "function") return void 0;
1025
+ if (Array.isArray(val)) return val.map(sortDeep);
1026
+ if (val && typeof val === "object") {
1027
+ const out = {};
1028
+ for (const key of Object.keys(val).sort()) {
1029
+ if (key === "__proto__") continue;
1030
+ out[key] = sortDeep(val[key]);
1031
+ }
1032
+ return out;
1033
+ }
1034
+ return val;
1035
+ }, "sortDeep");
1036
+ try {
1037
+ return JSON.stringify(sortDeep(projected));
1038
+ } catch {
1039
+ return "{}";
1040
+ }
1041
+ }
1042
+ __name(canonicalizeAgentOpts, "canonicalizeAgentOpts");
1043
+ function deriveAgentKey(prefixHash, prompt, opts) {
1044
+ const hash = createHash("sha256");
1045
+ hash.update(prefixHash);
1046
+ hash.update("\0");
1047
+ hash.update(prompt);
1048
+ hash.update("\0");
1049
+ hash.update(canonicalizeAgentOpts(opts));
1050
+ return `${JOURNAL_KEY_VERSION}:${hash.digest("hex")}`;
1051
+ }
1052
+ __name(deriveAgentKey, "deriveAgentKey");
1053
+ function deriveArgsSeed(args) {
1054
+ const hash = createHash("sha256");
1055
+ let serialized;
1056
+ try {
1057
+ serialized = JSON.stringify(args ?? null) ?? "null";
1058
+ } catch {
1059
+ serialized = "non-serializable-args";
1060
+ }
1061
+ hash.update(serialized);
1062
+ return `${JOURNAL_KEY_VERSION}:${hash.digest("hex")}`;
1063
+ }
1064
+ __name(deriveArgsSeed, "deriveArgsSeed");
1065
+ function buildReplay(entries) {
1066
+ const results = /* @__PURE__ */ new Map();
1067
+ const started = /* @__PURE__ */ new Map();
1068
+ for (const e of entries) {
1069
+ if (e.type === "result") {
1070
+ results.set(e.key, e);
1071
+ } else if (e.type === "started") {
1072
+ const list = started.get(e.key);
1073
+ if (list) list.push(e);
1074
+ else started.set(e.key, [e]);
1075
+ }
1076
+ }
1077
+ return { results, started };
1078
+ }
1079
+ __name(buildReplay, "buildReplay");
1080
+ var WorkflowJournal = class {
1081
+ constructor(path2) {
1082
+ this.path = path2;
1083
+ }
1084
+ static {
1085
+ __name(this, "WorkflowJournal");
1086
+ }
1087
+ /** Load + parse all entries into replay maps. Empty maps if no file. */
1088
+ async load() {
1089
+ try {
1090
+ const entries = await read(this.path);
1091
+ return buildReplay(entries);
1092
+ } catch (e) {
1093
+ debugLogger4.warn(`WorkflowJournal.load failed for ${this.path}: ${e}`);
1094
+ return { results: /* @__PURE__ */ new Map(), started: /* @__PURE__ */ new Map() };
1095
+ }
1096
+ }
1097
+ /** Append one entry. Rejects only on I/O error (callers `.catch`). */
1098
+ append(entry) {
1099
+ return writeLine(this.path, entry);
1100
+ }
1101
+ };
1102
+
816
1103
  // packages/core/src/agents/runtime/workflow-prompts.ts
817
1104
  init_esbuild_shims();
818
1105
  var WORKFLOW_SUBAGENT_SYSTEM_PROMPT = 'You are a subagent spawned by a workflow orchestration script. Use the tools available to complete the task.\nCRITICAL: Your final text response is returned **verbatim** as a string to the calling script \u2014 it is your return value, not a message to a human.\n- Output the literal result (data, JSON, text). Do NOT output confirmations like "Done." or "Sent."\n- If asked for JSON, return ONLY the raw JSON \u2014 no code fences, no prose, no markdown.\n- Do NOT use SendUserMessage to deliver your answer. Put your answer in your final text response.\n- Be concise. The script will parse your output.';
@@ -880,8 +1167,8 @@ function resolveMaxAgentsPerRun(env = process.env) {
880
1167
  if (raw === void 0 || raw.trim() === "") {
881
1168
  return DEFAULT_MAX_AGENTS_PER_RUN;
882
1169
  }
883
- const parsed = Number(raw);
884
- if (!Number.isInteger(parsed) || parsed < 1) {
1170
+ const parsed = parsePositiveIntegerEnv(raw, 0);
1171
+ if (parsed < 1) {
885
1172
  debugLogger.warn(
886
1173
  `Invalid ${MAX_WORKFLOW_AGENTS_ENV}=${JSON.stringify(raw)}, using default (${DEFAULT_MAX_AGENTS_PER_RUN})`
887
1174
  );
@@ -901,8 +1188,8 @@ var HARD_MAX_CONCURRENCY_CEILING = 64;
901
1188
  function resolveConcurrencyLimit(env = process.env) {
902
1189
  const raw = env[MAX_WORKFLOW_CONCURRENCY_ENV];
903
1190
  if (raw !== void 0 && raw.trim() !== "") {
904
- const parsed = Number(raw);
905
- if (Number.isInteger(parsed) && parsed >= 1) {
1191
+ const parsed = parsePositiveIntegerEnv(raw, 0);
1192
+ if (parsed >= 1) {
906
1193
  if (parsed > HARD_MAX_CONCURRENCY_CEILING) {
907
1194
  debugLogger.warn(
908
1195
  `${MAX_WORKFLOW_CONCURRENCY_ENV}=${parsed} exceeds hard ceiling (${HARD_MAX_CONCURRENCY_CEILING}); clamping.`
@@ -946,48 +1233,72 @@ function sanitizeForErrorMessage(value) {
946
1233
  __name(sanitizeForErrorMessage, "sanitizeForErrorMessage");
947
1234
  function createProductionDispatch(config, signal, onTokens) {
948
1235
  return async (prompt, opts) => {
949
- const { AgentHeadless, ContextState } = await import("./agent-headless-Q27MG73I.js");
950
- const ctx = new ContextState();
951
- ctx.set("task_prompt", prompt);
952
- if (opts.agentType === void 0 && opts.model === void 0 && opts.isolation === void 0 && opts.schema === void 0) {
953
- const subagent = await AgentHeadless.create(
954
- opts.label ?? "workflow-agent",
1236
+ const stallMs = resolveStallMs(
1237
+ typeof opts.stallMs === "number" ? opts.stallMs : void 0
1238
+ );
1239
+ return runStallResilient(
1240
+ (attemptSignal, emitter) => runSingleDispatch(
955
1241
  config,
956
- {
957
- systemPrompt: WORKFLOW_SUBAGENT_SYSTEM_PROMPT,
958
- initialMessages: []
959
- },
960
- {},
961
- // T11 (PR #4732 R1): bound resource ceiling so a single agent() call
962
- // cannot loop the model indefinitely. Without this, runConfig was {}
963
- // and the loop guards never tripped — combined with the cancellation
964
- // bug below, workflows were effectively unkillable.
965
- {
966
- max_turns: WORKFLOW_SUBAGENT_MAX_TURNS,
967
- max_time_minutes: WORKFLOW_SUBAGENT_MAX_TIME_MINUTES
968
- },
969
- // T11 (PR #4732 R1): disallow SendMessage / ExitPlanMode to align with
970
- // upstream Tg8 — closes the back-channel that would let a subagent
971
- // deliver its answer via user message instead of the script's read.
972
- { tools: ["*"], disallowedTools: WORKFLOW_SUBAGENT_DISALLOWED_TOOLS }
973
- );
974
- try {
975
- await subagent.execute(ctx, signal);
976
- } finally {
977
- reportTokens(subagent, opts, onTokens);
978
- }
979
- const mode = subagent.getTerminateMode();
980
- if (mode !== "GOAL" /* GOAL */) {
981
- throw new Error(
982
- `Workflow subagent did not complete (terminate mode: ${mode}).`
983
- );
1242
+ prompt,
1243
+ opts,
1244
+ attemptSignal,
1245
+ emitter,
1246
+ onTokens
1247
+ ),
1248
+ {
1249
+ stallMs,
1250
+ signal,
1251
+ label: typeof opts.label === "string" ? opts.label : void 0
984
1252
  }
985
- return subagent.getFinalText();
986
- }
987
- return runOverridePath(config, ctx, opts, signal, onTokens);
1253
+ );
988
1254
  };
989
1255
  }
990
1256
  __name(createProductionDispatch, "createProductionDispatch");
1257
+ async function runSingleDispatch(config, prompt, opts, attemptSignal, emitter, onTokens) {
1258
+ const { AgentHeadless, ContextState } = await import("./agent-headless-QUAPWF55.js");
1259
+ const ctx = new ContextState();
1260
+ ctx.set("task_prompt", prompt);
1261
+ if (opts.agentType === void 0 && opts.model === void 0 && opts.isolation === void 0 && opts.schema === void 0) {
1262
+ const subagent = await AgentHeadless.create(
1263
+ opts.label ?? "workflow-agent",
1264
+ config,
1265
+ {
1266
+ systemPrompt: WORKFLOW_SUBAGENT_SYSTEM_PROMPT,
1267
+ initialMessages: []
1268
+ },
1269
+ {},
1270
+ // T11 (PR #4732 R1): bound resource ceiling so a single agent() call
1271
+ // cannot loop the model indefinitely. Without this, runConfig was {}
1272
+ // and the loop guards never tripped — combined with the cancellation
1273
+ // bug below, workflows were effectively unkillable.
1274
+ {
1275
+ max_turns: WORKFLOW_SUBAGENT_MAX_TURNS,
1276
+ max_time_minutes: WORKFLOW_SUBAGENT_MAX_TIME_MINUTES
1277
+ },
1278
+ // T11 (PR #4732 R1): disallow SendMessage / ExitPlanMode to align with
1279
+ // upstream Tg8 — closes the back-channel that would let a subagent
1280
+ // deliver its answer via user message instead of the script's read.
1281
+ { tools: ["*"], disallowedTools: WORKFLOW_SUBAGENT_DISALLOWED_TOOLS },
1282
+ // P-stall: the stall-watchdog emitter observes reasoning-loop events
1283
+ // (round/tool/usage) to detect a hang and abort `attemptSignal`.
1284
+ emitter
1285
+ );
1286
+ try {
1287
+ await subagent.execute(ctx, attemptSignal);
1288
+ } finally {
1289
+ reportTokens(subagent, opts, onTokens);
1290
+ }
1291
+ const mode = subagent.getTerminateMode();
1292
+ if (mode !== "GOAL" /* GOAL */) {
1293
+ throw new Error(
1294
+ `Workflow subagent did not complete (terminate mode: ${mode}).`
1295
+ );
1296
+ }
1297
+ return subagent.getFinalText();
1298
+ }
1299
+ return runOverridePath(config, ctx, opts, attemptSignal, onTokens, emitter);
1300
+ }
1301
+ __name(runSingleDispatch, "runSingleDispatch");
991
1302
  function reportTokens(subagent, opts, onTokens) {
992
1303
  if (!onTokens) return;
993
1304
  try {
@@ -998,7 +1309,7 @@ function reportTokens(subagent, opts, onTokens) {
998
1309
  }
999
1310
  }
1000
1311
  __name(reportTokens, "reportTokens");
1001
- async function runOverridePath(config, ctx, opts, signal, onTokens) {
1312
+ async function runOverridePath(config, ctx, opts, signal, onTokens, emitter) {
1002
1313
  if (opts.isolation === "remote") {
1003
1314
  throw new Error(
1004
1315
  "agent({isolation:'remote'}) is not available in this build."
@@ -1079,7 +1390,10 @@ ${WORKFLOW_SUBAGENT_SYSTEM_PROMPT_WITH_SCHEMA}` : WORKFLOW_SUBAGENT_SYSTEM_PROMP
1079
1390
  schemaState.abortController = child;
1080
1391
  dispatchSignal = child.signal;
1081
1392
  }
1082
- const eventEmitter = schemaState ? createSchemaEventEmitter(schemaState) : void 0;
1393
+ const eventEmitter = emitter ?? (schemaState ? new AgentEventEmitter() : void 0);
1394
+ if (schemaState && eventEmitter) {
1395
+ attachSchemaListeners(eventEmitter, schemaState);
1396
+ }
1083
1397
  const { subagent, dispose } = await subagentMgr.createAgentHeadless(
1084
1398
  augmented,
1085
1399
  effectiveContext,
@@ -1318,8 +1632,7 @@ function createSchemaModeState() {
1318
1632
  };
1319
1633
  }
1320
1634
  __name(createSchemaModeState, "createSchemaModeState");
1321
- function createSchemaEventEmitter(state) {
1322
- const emitter = new AgentEventEmitter();
1635
+ function attachSchemaListeners(emitter, state) {
1323
1636
  const targetTool = ToolNames.STRUCTURED_OUTPUT;
1324
1637
  emitter.on("tool_call" /* TOOL_CALL */, (evt) => {
1325
1638
  if (evt.name !== targetTool) return;
@@ -1341,9 +1654,8 @@ function createSchemaEventEmitter(state) {
1341
1654
  state.abortController.abort();
1342
1655
  }
1343
1656
  });
1344
- return emitter;
1345
1657
  }
1346
- __name(createSchemaEventEmitter, "createSchemaEventEmitter");
1658
+ __name(attachSchemaListeners, "attachSchemaListeners");
1347
1659
  async function createSchemaConfigOverride(base, schema) {
1348
1660
  const override = Object.create(base);
1349
1661
  await rebuildToolRegistryOnOverride(override, base);
@@ -1367,7 +1679,46 @@ var WorkflowOrchestrator = class {
1367
1679
  let agentCount = 0;
1368
1680
  const emitter = req.emitter;
1369
1681
  const budget = req.budget;
1682
+ const journal = req.journal;
1683
+ const replay = req.resumeReplay;
1684
+ let prefixHash = deriveArgsSeed(req.args);
1685
+ let hadMiss = false;
1686
+ let journalAgentId = 0;
1370
1687
  const countedDispatch = /* @__PURE__ */ __name((prompt, opts) => {
1688
+ let journalKey;
1689
+ let journalEntryId;
1690
+ if (journal) {
1691
+ journalKey = deriveAgentKey(prefixHash, prompt, opts);
1692
+ prefixHash = journalKey;
1693
+ if (!hadMiss && replay) {
1694
+ const cached = replay.results.get(journalKey);
1695
+ if (cached !== void 0) {
1696
+ const respawns = replay.started.get(journalKey);
1697
+ if (respawns && respawns.length > 0) {
1698
+ debugLogger.info(
1699
+ `[Workflow] resume cache hit after ${respawns.length} prior respawn(s) for runId=${runId}.`
1700
+ );
1701
+ }
1702
+ const label2 = typeof opts.label === "string" ? opts.label : void 0;
1703
+ try {
1704
+ emitter?.agentDispatched?.(label2);
1705
+ } catch (e) {
1706
+ debugLogger.warn("emitter.agentDispatched threw:", e);
1707
+ }
1708
+ try {
1709
+ emitter?.agentCompleted?.(label2);
1710
+ } catch (e) {
1711
+ debugLogger.warn("emitter.agentCompleted threw:", e);
1712
+ }
1713
+ return Promise.resolve(cached.result);
1714
+ }
1715
+ }
1716
+ hadMiss = true;
1717
+ journalEntryId = String(journalAgentId += 1);
1718
+ journal.append({ type: "started", key: journalKey, agentId: journalEntryId }).catch(
1719
+ (e) => debugLogger.warn(`journal started-append failed: ${e}`)
1720
+ );
1721
+ }
1371
1722
  if (budget && budget.total !== null && budget.remaining() <= 0) {
1372
1723
  debugLogger.warn(
1373
1724
  `[Workflow] budget gate refused dispatch at entry: runId=${runId} spent=${budget.spent()} total=${budget.total}`
@@ -1409,6 +1760,16 @@ var WorkflowOrchestrator = class {
1409
1760
  } catch (e) {
1410
1761
  debugLogger.warn("emitter.agentCompleted threw:", e);
1411
1762
  }
1763
+ if (journal && journalKey !== void 0) {
1764
+ journal.append({
1765
+ type: "result",
1766
+ key: journalKey,
1767
+ agentId: journalEntryId ?? "",
1768
+ result
1769
+ }).catch(
1770
+ (e) => debugLogger.warn(`journal result-append failed: ${e}`)
1771
+ );
1772
+ }
1412
1773
  if (budget) {
1413
1774
  try {
1414
1775
  emitter?.budgetUpdated?.(budget.spent(), budget.total);
@@ -1438,11 +1799,27 @@ var WorkflowOrchestrator = class {
1438
1799
  }, "countedDispatch");
1439
1800
  const parallelImpl = makeParallelImpl(signal);
1440
1801
  const pipelineImpl = makePipelineImpl(signal);
1802
+ const resolveSavedWorkflow = req.resolveSavedWorkflow;
1803
+ const workflowImpl = resolveSavedWorkflow ? async (nameOrRef, nestedArgs) => {
1804
+ const resolved = await resolveSavedWorkflow(nameOrRef);
1805
+ const nestedSandbox = createWorkflowSandbox({
1806
+ args: nestedArgs,
1807
+ dispatch: countedDispatch,
1808
+ parallel: parallelImpl,
1809
+ pipeline: pipelineImpl,
1810
+ abortOnTimeout: req.abortOnTimeout,
1811
+ emitter,
1812
+ budget
1813
+ // No `workflow` — single-level nesting limit.
1814
+ });
1815
+ return nestedSandbox.run(resolved.script);
1816
+ } : void 0;
1441
1817
  const sandbox = createWorkflowSandbox({
1442
1818
  args: req.args,
1443
1819
  dispatch: countedDispatch,
1444
1820
  parallel: parallelImpl,
1445
1821
  pipeline: pipelineImpl,
1822
+ workflow: workflowImpl,
1446
1823
  abortOnTimeout: req.abortOnTimeout,
1447
1824
  emitter,
1448
1825
  budget
@@ -1466,19 +1843,31 @@ var WorkflowOrchestrator = class {
1466
1843
  }
1467
1844
  }
1468
1845
  };
1469
- async function settleToNullArray(thunks, signal) {
1846
+ async function settleToNullArray(thunks, signal, kind = "parallel") {
1470
1847
  const settled = await Promise.allSettled(
1471
1848
  thunks.map((t) => Promise.resolve().then(t))
1472
1849
  );
1473
1850
  if (signal?.aborted)
1474
1851
  throw new DOMException("Workflow run aborted.", "AbortError");
1475
- return settled.map((r, i) => {
1852
+ let budgetDropped = 0;
1853
+ const result = settled.map((r, i) => {
1476
1854
  if (r.status === "fulfilled") return r.value;
1477
- debugLogger.warn(
1478
- `Workflow thunk at index ${i} rejected: ${String(r.reason?.message ?? r.reason)}`
1479
- );
1855
+ const reason = r.reason;
1856
+ if (reason?.name === "WorkflowBudgetExceededError") {
1857
+ budgetDropped += 1;
1858
+ } else {
1859
+ debugLogger.warn(
1860
+ `Workflow thunk at index ${i} rejected: ${String(reason?.message ?? r.reason)}`
1861
+ );
1862
+ }
1480
1863
  return null;
1481
1864
  });
1865
+ if (budgetDropped > 0) {
1866
+ debugLogger.warn(
1867
+ `${kind}: ${budgetDropped} slot${budgetDropped === 1 ? "" : "s"} dropped \u2014 token budget exceeded.`
1868
+ );
1869
+ }
1870
+ return result;
1482
1871
  }
1483
1872
  __name(settleToNullArray, "settleToNullArray");
1484
1873
  function makeParallelImpl(signal) {
@@ -1524,7 +1913,7 @@ function makePipelineImpl(signal) {
1524
1913
  const chains = items.map(
1525
1914
  (item, idx) => () => runPipelineChain(item, idx, stages)
1526
1915
  );
1527
- return settleToNullArray(chains, signal);
1916
+ return settleToNullArray(chains, signal, "pipeline");
1528
1917
  };
1529
1918
  }
1530
1919
  __name(makePipelineImpl, "makePipelineImpl");
@@ -1549,6 +1938,7 @@ __name(extractErrorMessage, "extractErrorMessage");
1549
1938
 
1550
1939
  // packages/core/src/tools/workflow/workflow.ts
1551
1940
  import { randomBytes as randomBytes2 } from "node:crypto";
1941
+ import * as path from "node:path";
1552
1942
  var WORKFLOW_PARAM_SCHEMA = {
1553
1943
  type: "object",
1554
1944
  properties: {
@@ -1556,11 +1946,22 @@ var WORKFLOW_PARAM_SCHEMA = {
1556
1946
  type: "string",
1557
1947
  description: "JavaScript source of the workflow. Wrapped as an async IIFE. May call the injected globals `phase(title)`, `log(msg)`, `agent(prompt, opts?)`, and read `args`. agent() opts: `{ label?, phase?, schema?, model?, agentType?, isolation? }`. `schema` (JSON Schema object): the subagent must deliver its result by calling `structured_output` with arguments matching the schema; agent() resolves to the validated object. Two failed attempts produce a terminal error \"subagent completed without calling StructuredOutput (after 2 in-conversation nudges)\". `agentType` (string): resolves against the declarative-agents registry (`.qwen/agents/<name>.md`, project then user then built-in). Unresolved names throw \"agent({agentType}): agent type 'X' not found\". `model` (string): per-call model override; routes provider correctly via the subagent runtime view. `isolation`: `'worktree'` provisions a fresh git worktree under `<projectRoot>/.qwen/worktrees/agent-<7hex>`; the worktree is auto-removed if no changes, otherwise the path and branch are returned alongside the result. `'remote'` throws \"agent({isolation:'remote'}) is not available in this build\" (parity with upstream). isolation=worktree refuses to run when the parent working tree has uncommitted changes (the subagent would see a stale HEAD). Workflow subagents always have SendMessage / ExitPlanMode in their disallowed-tool floor regardless of agentType. Concurrency: `parallel([() => agent(...), ...])` runs thunks through a shared per-run window (default `max(1, min(16, cpus-2))` agents in flight; override via `QWEN_CODE_MAX_WORKFLOW_CONCURRENCY`) and resolves to a position-aligned array \u2014 a thunk that throws, or resolves to a non-JSON-serializable value, becomes `null` at its index (errors-as-data); parallel() itself rejects only on invalid arguments or abort. `pipeline(items, ...stages)` runs each item through the stages (staggered, no inter-stage barrier); a stage that throws, returns `null`, or returns a non-JSON-serializable value drops that item to `null`. Pass THUNKS to parallel, not eager calls: `parallel([() => agent(...)])`, not `parallel([agent(...)])`. At most 1000 agent() calls per run (override via `QWEN_CODE_MAX_WORKFLOW_AGENTS`). `Date.now()` and `Math.random()` both throw \u2014 workflow scripts must be deterministic for resume. `export const meta = {...}` declarations are stripped before execution."
1558
1948
  },
1949
+ scriptPath: {
1950
+ type: "string",
1951
+ description: "Optional. Absolute path to a saved workflow `.js` file to load and run instead of inline `script`. Primarily set by the `/<name>` saved-workflow slash command. Provide exactly ONE of `script` or `scriptPath`. The file is read at execution time, so edits to a saved workflow take effect on the next run."
1952
+ },
1559
1953
  args: {
1560
1954
  description: "Optional structured value bound to the `args` global. Pass actual JSON, not a stringified value."
1955
+ },
1956
+ resumeFromRunId: {
1957
+ type: "string",
1958
+ description: "Optional. Resume a prior workflow run by id (e.g. wf_abc123\u2026). Re-runs the SAME script; agent() calls whose rolling prefix-hash (prompt + opts, chained in call order) matches a journaled result are served from cache for the longest unchanged prefix, and the first changed/missing call onward runs live. Pass the same script and args as the original run for the cache to apply."
1561
1959
  }
1562
- },
1563
- required: ["script"]
1960
+ }
1961
+ // `script` is required UNLESS `scriptPath` is supplied; this XOR can't be
1962
+ // expressed as a plain `required` list, so it's enforced in
1963
+ // `validateToolParamValues`. Inline authoring (the LLM path) should always
1964
+ // pass `script`; the `scriptPath` property description states the XOR.
1564
1965
  };
1565
1966
  var WorkflowToolInvocation = class extends BaseToolInvocation {
1566
1967
  constructor(config, toolOptions, params) {
@@ -1572,7 +1973,10 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
1572
1973
  __name(this, "WorkflowToolInvocation");
1573
1974
  }
1574
1975
  getDescription() {
1575
- return `Run a workflow script (${this.params.script.length} chars)`;
1976
+ if (this.params.scriptPath && this.params.script === void 0) {
1977
+ return `Run saved workflow (${path.basename(this.params.scriptPath)})`;
1978
+ }
1979
+ return `Run a workflow script (${this.params.script?.length ?? 0} chars)`;
1576
1980
  }
1577
1981
  toolLocations() {
1578
1982
  return [];
@@ -1592,7 +1996,26 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
1592
1996
  (outputTokens) => budget.recordSpent(outputTokens)
1593
1997
  );
1594
1998
  const orchestrator = new WorkflowOrchestrator(dispatch);
1595
- const runId = `wf_${randomBytes2(8).toString("hex")}`;
1999
+ let resolvedScript = this.params.script ?? "";
2000
+ let resolvedScriptPath = this.params.scriptPath;
2001
+ if (this.params.scriptPath && this.params.script === void 0) {
2002
+ const loaded = await resolveSavedWorkflowScript(
2003
+ { scriptPath: this.params.scriptPath },
2004
+ this.config
2005
+ );
2006
+ resolvedScript = loaded.script;
2007
+ resolvedScriptPath = loaded.scriptPath;
2008
+ }
2009
+ const runId = this.params.resumeFromRunId ?? `wf_${randomBytes2(8).toString("hex")}`;
2010
+ let journal;
2011
+ let resumeReplay;
2012
+ const storage = this.config.storage;
2013
+ if (storage) {
2014
+ journal = new WorkflowJournal(storage.getWorkflowRunJournalPath(runId));
2015
+ if (this.params.resumeFromRunId) {
2016
+ resumeReplay = await journal.load();
2017
+ }
2018
+ }
1596
2019
  const registry = this.config.getWorkflowRunRegistry?.();
1597
2020
  const registryEntry = registry?.register({
1598
2021
  runId,
@@ -1606,7 +2029,13 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
1606
2029
  // P5: seed the cap so the dialog can render the `M / N` form
1607
2030
  // immediately, before the first `budgetUpdated` fires. Stays
1608
2031
  // `null` when no env override.
1609
- tokenBudgetTotal: budget.total
2032
+ tokenBudgetTotal: budget.total,
2033
+ // P7b: carry the script source so a completed run can be snapshotted
2034
+ // to disk and saved to `.qwen/workflows/<name>.js` from the dialog.
2035
+ // `scriptPath` is set when the run was launched from a saved file (run
2036
+ // provenance for the snapshot).
2037
+ script: resolvedScript,
2038
+ scriptPath: resolvedScriptPath
1610
2039
  });
1611
2040
  const emitter = {
1612
2041
  phaseStarted: /* @__PURE__ */ __name((title) => {
@@ -1629,12 +2058,18 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
1629
2058
  };
1630
2059
  try {
1631
2060
  const outcome = await orchestrator.run({
1632
- script: this.params.script,
2061
+ script: resolvedScript,
1633
2062
  args: this.params.args,
1634
2063
  abortOnTimeout: dispatchController,
1635
2064
  runId,
1636
2065
  emitter,
1637
- budget
2066
+ budget,
2067
+ // P-nested: resolve `workflow('<name>')` / `workflow({scriptPath})`
2068
+ // against the saved-workflow scripts in `.qwen/workflows/`.
2069
+ resolveSavedWorkflow: /* @__PURE__ */ __name((ref) => resolveSavedWorkflowScript(ref, this.config), "resolveSavedWorkflow"),
2070
+ // P6: resume journal (always wired) + replay maps (resume only).
2071
+ journal,
2072
+ resumeReplay
1638
2073
  });
1639
2074
  if (registryEntry) {
1640
2075
  registryEntry.meta = outcome.meta;
@@ -1704,6 +2139,23 @@ ${safeStringifyDisplayPayload({
1704
2139
  };
1705
2140
  } finally {
1706
2141
  dispatchController.abort();
2142
+ if (registryEntry && registryEntry.status !== "running") {
2143
+ await writeWorkflowSnapshot(this.config, registryEntry);
2144
+ try {
2145
+ logWorkflowRun(
2146
+ this.config,
2147
+ new WorkflowRunEvent({
2148
+ status: registryEntry.status,
2149
+ agents_dispatched: registryEntry.agentsDispatched,
2150
+ agents_completed: registryEntry.agentsCompleted,
2151
+ phase_count: registryEntry.phases.length,
2152
+ tokens_spent: registryEntry.tokensSpent,
2153
+ duration_ms: (registryEntry.endTime ?? registryEntry.startTime) - registryEntry.startTime
2154
+ })
2155
+ );
2156
+ } catch {
2157
+ }
2158
+ }
1707
2159
  }
1708
2160
  }
1709
2161
  };
@@ -1803,7 +2255,7 @@ var WorkflowTool = class extends BaseDeclarativeTool {
1803
2255
  super(
1804
2256
  ToolNames.WORKFLOW,
1805
2257
  ToolDisplayNames.WORKFLOW,
1806
- "Execute a workflow script that orchestrates subagents. Supports `phase`, `log`, sequential `agent`, concurrent fan-out via `parallel(thunks)` / `pipeline(items, ...stages)` (default `max(1, min(16, cpus-2))` agents in flight per run, up to 1000 agents total; both env-overridable), per-call `agent({ schema, agentType, model, isolation: 'worktree' })` for structured-output contracts, declarative-agent selection, model override, and git-worktree-isolated subagents. No resume and no background execution yet (scheduled for later phases). Scripts run in a node:vm sandbox without access to the filesystem or shell; all I/O happens through the spawned agents.",
2258
+ "Execute a workflow script that orchestrates subagents. Supports `phase`, `log`, sequential `agent`, concurrent fan-out via `parallel(thunks)` / `pipeline(items, ...stages)` (default `max(1, min(16, cpus-2))` agents in flight per run, up to 1000 agents total; both env-overridable), per-call `agent({ schema, agentType, model, isolation: 'worktree' })` for structured-output contracts, declarative-agent selection, model override, and git-worktree-isolated subagents. Pass `resumeFromRunId` to resume a prior run \u2014 agent() calls whose rolling prefix-hash matches the journal are served from cache for the longest unchanged prefix. Runs are tracked in the background-tasks view and the `/workflows` dialog (live phase tree, token usage, cancel). Scripts run in a node:vm sandbox without access to the filesystem or shell; all I/O happens through the spawned agents.",
1807
2259
  "other" /* Other */,
1808
2260
  WORKFLOW_PARAM_SCHEMA,
1809
2261
  /* isOutputMarkdown */
@@ -1818,8 +2270,16 @@ var WorkflowTool = class extends BaseDeclarativeTool {
1818
2270
  __name(this, "WorkflowTool");
1819
2271
  }
1820
2272
  validateToolParamValues(params) {
1821
- if (typeof params.script !== "string" || params.script.length === 0) {
1822
- return "WorkflowTool: `script` parameter is required and must be a non-empty string.";
2273
+ const hasScript = typeof params.script === "string" && params.script.length > 0;
2274
+ const hasPath = typeof params.scriptPath === "string" && params.scriptPath.length > 0;
2275
+ if (!hasScript && !hasPath) {
2276
+ return "WorkflowTool: provide `script` (inline source) or `scriptPath` (a saved workflow file).";
2277
+ }
2278
+ if (hasScript && hasPath) {
2279
+ return "WorkflowTool: provide exactly one of `script` or `scriptPath`, not both.";
2280
+ }
2281
+ if (params.resumeFromRunId !== void 0 && !/^wf_[0-9a-f]+$/.test(params.resumeFromRunId)) {
2282
+ return "WorkflowTool: `resumeFromRunId` must match the generated id format `wf_<hex>`.";
1823
2283
  }
1824
2284
  return null;
1825
2285
  }