@qwen-code/qwen-code 0.18.5-nightly.20260622.6bc3f853e → 0.19.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 (146) hide show
  1. package/bundled/qc-helper/docs/configuration/qwen-ignore.md +31 -15
  2. package/bundled/qc-helper/docs/configuration/settings.md +15 -14
  3. package/bundled/qc-helper/docs/extension/introduction.md +24 -6
  4. package/bundled/qc-helper/docs/features/mcp.md +9 -6
  5. package/bundled/qc-helper/docs/qwen-serve.md +1 -1
  6. package/chunks/{agent-WFLPE5MW.js → agent-IPSDEZNB.js} +24 -22
  7. package/chunks/{agent-headless-Q27MG73I.js → agent-headless-ZMTUWMZJ.js} +24 -22
  8. package/chunks/{anthropicContentGenerator-5S4OMMNL.js → anthropicContentGenerator-6MCH4X6S.js} +12 -11
  9. package/chunks/artifact-tool-PBX64YTT.js +675 -0
  10. package/chunks/{askUserQuestion-WHVYL2S2.js → askUserQuestion-5ZQOWSRT.js} +20 -7
  11. package/chunks/chunk-22IFUCVR.js +291 -0
  12. package/chunks/{chunk-XGU3ETVO.js → chunk-255L5QYW.js} +3 -3
  13. package/chunks/{chunk-26ZYKTYZ.js → chunk-2BIF2NVV.js} +2 -2
  14. package/chunks/{chunk-LTN3VYMZ.js → chunk-3UALQ56H.js} +1 -1
  15. package/chunks/{chunk-2O3NAOJG.js → chunk-57XRIZVC.js} +1 -1
  16. package/chunks/{chunk-MSJ2MXJ6.js → chunk-BGUDAULQ.js} +11 -290
  17. package/chunks/{chunk-FH4P6RQA.js → chunk-BNXANYLH.js} +1 -1
  18. package/chunks/{chunk-WE6TNQJU.js → chunk-C4K3FEQ2.js} +36 -0
  19. package/chunks/{chunk-G4BUMVEY.js → chunk-CGEGHF2C.js} +2 -217
  20. package/chunks/{chunk-GM3LTU6K.js → chunk-CICUTYTF.js} +173 -5025
  21. package/chunks/chunk-EEEZIVFJ.js +908 -0
  22. package/chunks/chunk-EJYJYJZ2.js +3703 -0
  23. package/chunks/{chunk-ATLUHLZE.js → chunk-EW6C27XX.js} +1 -1
  24. package/chunks/{chunk-QBUR6J4B.js → chunk-GAAALA2X.js} +6 -6
  25. package/chunks/{chunk-C6MI2ASN.js → chunk-GZCJS5WH.js} +2 -2
  26. package/chunks/{chunk-KGV3F6UF.js → chunk-HGNSRCRB.js} +1 -1
  27. package/chunks/{chunk-42HGOMED.js → chunk-JDV3VBPY.js} +216 -1
  28. package/chunks/{chunk-CX3SGIPK.js → chunk-JRVB4QUY.js} +2 -2
  29. package/chunks/{chunk-7Z2O7IBO.js → chunk-KFR4QTV3.js} +557 -22
  30. package/chunks/{chunk-ID533GA3.js → chunk-OTBK43JR.js} +1 -1
  31. package/chunks/{chunk-GOMVJKBL.js → chunk-PLY4F7QW.js} +5 -3
  32. package/chunks/{chunk-VKILGMZQ.js → chunk-PO5LVPK3.js} +1 -1
  33. package/chunks/{chunk-AE6RQU6F.js → chunk-PRYMDRBV.js} +1 -1
  34. package/chunks/{chunk-GBN55AWZ.js → chunk-QKUAGMGE.js} +2 -2
  35. package/chunks/{chunk-KQIKOTQJ.js → chunk-RYLJU2DY.js} +60 -5
  36. package/chunks/{chunk-SWGPABMH.js → chunk-S7ILEIB4.js} +82 -84
  37. package/chunks/{chunk-CTHZVIMD.js → chunk-T2VDEFUU.js} +2 -2
  38. package/chunks/{chunk-LF6BKGZT.js → chunk-TXVGVZYR.js} +3 -3
  39. package/chunks/{chunk-EJ6NFQ2L.js → chunk-VRIVIYRL.js} +5 -5
  40. package/chunks/{chunk-XU7BKR3B.js → chunk-XU5P23GN.js} +3 -3
  41. package/chunks/{chunk-CXZV4Q4J.js → chunk-YF3ORUIU.js} +6362 -4888
  42. package/chunks/{computer-use-F5O56FVW.js → computer-use-YYK42DD5.js} +24 -22
  43. package/chunks/contextCommand-BO45MUAA.js +56 -0
  44. package/chunks/{cron-create-THNDTYXU.js → cron-create-DXKAP5KN.js} +4 -4
  45. package/chunks/{cron-delete-BS5H6TFJ.js → cron-delete-WGO4PZTF.js} +4 -4
  46. package/chunks/{cron-list-7OBVHT7K.js → cron-list-EY7D3ZUC.js} +4 -4
  47. package/chunks/{dist-GKRNVFBH.js → dist-ZBX7LPJZ.js} +2 -1
  48. package/chunks/{edit-UV7MBOJU.js → edit-QERNJN7K.js} +24 -22
  49. package/chunks/{en-S3OQBISC.js → en-UTXMGXIR.js} +47 -0
  50. package/chunks/{enter-worktree-TSCHZMJ3.js → enter-worktree-6ZKH5IL3.js} +24 -22
  51. package/chunks/{enterPlanMode-LKS7VIUG.js → enterPlanMode-B2PBF4MA.js} +27 -23
  52. package/chunks/{exit-worktree-Q6EWFLZU.js → exit-worktree-EOCMQO4I.js} +24 -22
  53. package/chunks/{exitPlanMode-HS6I4D2O.js → exitPlanMode-WSRXCBRZ.js} +36 -28
  54. package/chunks/{geminiContentGenerator-GEZ63VSW.js → geminiContentGenerator-NTR4LTKS.js} +4 -4
  55. package/chunks/{glob-ZN5LKB7E.js → glob-IWDJQI2V.js} +26 -23
  56. package/chunks/{grep-NIKBBYBU.js → grep-2DV5BXMH.js} +24 -22
  57. package/chunks/{keychain-token-storage-YHXIWXIB.js → keychain-token-storage-CSYMNRPP.js} +2 -2
  58. package/chunks/{loop-wakeup-SSBWZ64K.js → loop-wakeup-XVSDE7QR.js} +5 -5
  59. package/chunks/{ls-YPFUHZRQ.js → ls-LPY3ATQQ.js} +6 -6
  60. package/chunks/{lsp-FD6DNVAF.js → lsp-ZT3AAXIF.js} +2 -2
  61. package/chunks/{monitor-A25XKPU5.js → monitor-6HBDS2RS.js} +24 -22
  62. package/chunks/{notebook-edit-E72AIOUS.js → notebook-edit-J5AY5BRY.js} +25 -23
  63. package/chunks/{openaiContentGenerator-ZDLZDXLU.js → openaiContentGenerator-ENABCJDM.js} +12 -15
  64. package/chunks/{qwenContentGenerator-HVJPPMTT.js → qwenContentGenerator-ISW42U7C.js} +26 -24
  65. package/chunks/{qwenOAuth2-WZ54YZ4J.js → qwenOAuth2-K4AASPCV.js} +5 -4
  66. package/chunks/{read-file-L6FM3KUX.js → read-file-NRX2FSSQ.js} +9 -8
  67. package/chunks/{ripGrep-YRJCUISE.js → ripGrep-WF5CKHR5.js} +24 -22
  68. package/chunks/{scheduler-M3742P2I.js → scheduler-PNPG5WJ3.js} +73 -27
  69. package/chunks/{send-message-FWFTX62Q.js → send-message-447W6NH6.js} +24 -4
  70. package/chunks/{serve-ZIP2GDFY.js → serve-ZBRCIIHW.js} +430 -70
  71. package/chunks/{shell-T5VSPJLU.js → shell-DLIL6MLU.js} +24 -22
  72. package/chunks/{skill-ETTFYDOV.js → skill-32TXHY4A.js} +11 -10
  73. package/chunks/{src-UKOPSYDK.js → src-PDDLF5BB.js} +114 -67
  74. package/chunks/{syntheticOutput-JY5NEDTV.js → syntheticOutput-GQRDRLGR.js} +3 -3
  75. package/chunks/{task-create-IGILDV25.js → task-create-66DDSTVI.js} +6 -6
  76. package/chunks/{task-list-KBEJVAAG.js → task-list-GOPXRSHG.js} +5 -5
  77. package/chunks/{task-stop-WFTMQ6AC.js → task-stop-M7NKGFX2.js} +2 -2
  78. package/chunks/{task-update-UIVX7ZEV.js → task-update-M5TBHLZV.js} +6 -6
  79. package/chunks/{team-create-DRKUVGBN.js → team-create-EHLDSJGI.js} +28 -26
  80. package/chunks/{team-delete-LPOXDPVB.js → team-delete-DKKDS65W.js} +5 -5
  81. package/chunks/{todoWrite-R4RIJKOD.js → todoWrite-4VX7X44D.js} +4 -4
  82. package/chunks/{tool-search-EIIK27ON.js → tool-search-FU7IZAOO.js} +9 -8
  83. package/chunks/{web-fetch-JU7SS6KE.js → web-fetch-YPP3V4FJ.js} +4 -4
  84. package/chunks/{workflow-4RGAYFSJ.js → workflow-WUDNBCGX.js} +544 -92
  85. package/chunks/{write-file-GLQYJFEZ.js → write-file-NVFPX6CH.js} +24 -22
  86. package/chunks/{zh-TW-3OKU7LDA.js → zh-TW-J2TTW67R.js} +47 -0
  87. package/chunks/{zh-QXLZV2PX.js → zh-YOXVTJU5.js} +47 -0
  88. package/cli.js +7932 -4946
  89. package/locales/en.js +68 -0
  90. package/locales/zh-TW.js +65 -0
  91. package/locales/zh.js +65 -0
  92. package/package.json +3 -2
  93. package/web-shell/assets/{arc-CRFN10gD.js → arc-pxOt9B72.js} +1 -1
  94. package/web-shell/assets/{architectureDiagram-3BPJPVTR-IRlu1CpH.js → architectureDiagram-3BPJPVTR-B9XuYYOT.js} +1 -1
  95. package/web-shell/assets/{blockDiagram-GPEHLZMM-htIZ6iw8.js → blockDiagram-GPEHLZMM-5yK68iu4.js} +1 -1
  96. package/web-shell/assets/{c4Diagram-AAUBKEIU-A2GoRq3O.js → c4Diagram-AAUBKEIU-B1LY-qNI.js} +1 -1
  97. package/web-shell/assets/channel-Cx7egbSX.js +1 -0
  98. package/web-shell/assets/{chunk-2J33WTMH-CdP2AC6u.js → chunk-2J33WTMH-DkgXg7cM.js} +1 -1
  99. package/web-shell/assets/{chunk-4BX2VUAB-DrA07nW2.js → chunk-4BX2VUAB-DdM45KFM.js} +1 -1
  100. package/web-shell/assets/{chunk-55IACEB6-CFGnVU2f.js → chunk-55IACEB6-CmdsDjD4.js} +1 -1
  101. package/web-shell/assets/{chunk-727SXJPM-BTMkq3Tk.js → chunk-727SXJPM-CQ4pJ5GH.js} +1 -1
  102. package/web-shell/assets/{chunk-AQP2D5EJ-C9sYg04Z.js → chunk-AQP2D5EJ-Dy6UWz37.js} +1 -1
  103. package/web-shell/assets/{chunk-FMBD7UC4-Cag-cj6I.js → chunk-FMBD7UC4-CC8nFqap.js} +1 -1
  104. package/web-shell/assets/{chunk-ND2GUHAM-CDSTFoR7.js → chunk-ND2GUHAM-CkmS7lx7.js} +1 -1
  105. package/web-shell/assets/{chunk-QZHKN3VN-CN9Z6oOs.js → chunk-QZHKN3VN-DynyqleZ.js} +1 -1
  106. package/web-shell/assets/classDiagram-4FO5ZUOK-CwH_F8cH.js +1 -0
  107. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CwH_F8cH.js +1 -0
  108. package/web-shell/assets/{cose-bilkent-S5V4N54A-DuN9j8Du.js → cose-bilkent-S5V4N54A-DA0fzCsY.js} +1 -1
  109. package/web-shell/assets/{dagre-BM42HDAG-ByCWe45f.js → dagre-BM42HDAG-DHYXRqCo.js} +1 -1
  110. package/web-shell/assets/{diagram-2AECGRRQ-eWyU_pKZ.js → diagram-2AECGRRQ-DWD6BcPs.js} +1 -1
  111. package/web-shell/assets/{diagram-5GNKFQAL-0Bfu3Fq5.js → diagram-5GNKFQAL-CX9wnqVc.js} +1 -1
  112. package/web-shell/assets/{diagram-KO2AKTUF-B6KBKkQP.js → diagram-KO2AKTUF-BpE8Kbt8.js} +1 -1
  113. package/web-shell/assets/{diagram-LMA3HP47-TToDmeA_.js → diagram-LMA3HP47-DLPcrP0C.js} +1 -1
  114. package/web-shell/assets/{diagram-OG6HWLK6-CQCkC2Yx.js → diagram-OG6HWLK6-CSUCBsCe.js} +1 -1
  115. package/web-shell/assets/{erDiagram-TEJ5UH35-Cm9ls1iB.js → erDiagram-TEJ5UH35-d3Z0uMXS.js} +1 -1
  116. package/web-shell/assets/{flowDiagram-I6XJVG4X-Dyoz80Pv.js → flowDiagram-I6XJVG4X-C7vj5FX3.js} +1 -1
  117. package/web-shell/assets/{ganttDiagram-6RSMTGT7-Cfut9yaU.js → ganttDiagram-6RSMTGT7-BV9UvDV_.js} +1 -1
  118. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BCuJdlfD.js → gitGraphDiagram-PVQCEYII-CoWp0mW4.js} +1 -1
  119. package/web-shell/assets/index-CjTH6cLP.js +516 -0
  120. package/web-shell/assets/{infoDiagram-5YYISTIA-CXKxF2VL.js → infoDiagram-5YYISTIA-DUswfJHA.js} +1 -1
  121. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-DE7HWSU8.js → ishikawaDiagram-YF4QCWOH-WidEKukx.js} +1 -1
  122. package/web-shell/assets/{journeyDiagram-JHISSGLW-D__YUfds.js → journeyDiagram-JHISSGLW-D7IRK3VN.js} +1 -1
  123. package/web-shell/assets/{kanban-definition-UN3LZRKU-D82R169M.js → kanban-definition-UN3LZRKU-CwFJ6Cja.js} +1 -1
  124. package/web-shell/assets/{linear-DpyMbKqT.js → linear-BQ8GvDRY.js} +1 -1
  125. package/web-shell/assets/{mermaid.core-D1KEFDhn.js → mermaid.core-CwF8A_xO.js} +5 -5
  126. package/web-shell/assets/{mindmap-definition-RKZ34NQL-BwVUFGFE.js → mindmap-definition-RKZ34NQL-TR1s0iZi.js} +1 -1
  127. package/web-shell/assets/{pieDiagram-4H26LBE5-BO_qoEGx.js → pieDiagram-4H26LBE5-Cd91pMl9.js} +1 -1
  128. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-Cx0ZaWPo.js → quadrantDiagram-W4KKPZXB-BGxGDNMl.js} +1 -1
  129. package/web-shell/assets/{requirementDiagram-4Y6WPE33-BJPXejOA.js → requirementDiagram-4Y6WPE33-Cq3fWmYz.js} +1 -1
  130. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-C1xeIL9i.js → sankeyDiagram-5OEKKPKP-ChLyGdq0.js} +1 -1
  131. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-CSYKQUjf.js → sequenceDiagram-3UESZ5HK-tazy79aB.js} +1 -1
  132. package/web-shell/assets/{stateDiagram-AJRCARHV-d9hiHlAW.js → stateDiagram-AJRCARHV-dIYLUNSf.js} +1 -1
  133. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-luL7KTiX.js +1 -0
  134. package/web-shell/assets/{timeline-definition-PNZ67QCA-BhCBkq8k.js → timeline-definition-PNZ67QCA-BuENhrC2.js} +1 -1
  135. package/web-shell/assets/{vennDiagram-CIIHVFJN-DPPFWp_y.js → vennDiagram-CIIHVFJN-DLtum9dF.js} +1 -1
  136. package/web-shell/assets/{wardley-L42UT6IY-CcOUIgXY.js → wardley-L42UT6IY-Bf7OSF3y.js} +1 -1
  137. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-p7oR5X7r.js → wardleyDiagram-YWT4CUSO-slMw3OB3.js} +1 -1
  138. package/web-shell/assets/{xychartDiagram-2RQKCTM6-Dfr7-SEy.js → xychartDiagram-2RQKCTM6-CdxOm8oC.js} +1 -1
  139. package/web-shell/index.html +1 -1
  140. package/chunks/chunk-77WXWU44.js +0 -26
  141. package/chunks/contextCommand-WBVNKL2C.js +0 -54
  142. package/web-shell/assets/channel-WwImfsc7.js +0 -1
  143. package/web-shell/assets/classDiagram-4FO5ZUOK-CJKQYFeJ.js +0 -1
  144. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CJKQYFeJ.js +0 -1
  145. package/web-shell/assets/index-DaebdpHq.js +0 -516
  146. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DgReoybQ.js +0 -1
@@ -4,57 +4,67 @@ import {
4
4
  AgentEventEmitter,
5
5
  FileDiscoveryService,
6
6
  GitWorktreeService,
7
- WorkspaceContext,
8
7
  generateAgentWorktreeSlug,
9
8
  rebuildToolRegistryOnOverride,
9
+ resolveSavedWorkflowScript,
10
10
  stripAnsiAndControl,
11
+ writeWorkflowSnapshot,
11
12
  writeWorktreeSessionMarker
12
- } from "./chunk-CXZV4Q4J.js";
13
+ } from "./chunk-YF3ORUIU.js";
13
14
  import "./chunk-K5PGHDBN.js";
14
- import "./chunk-XU7BKR3B.js";
15
- import "./chunk-2O3NAOJG.js";
16
- import "./chunk-XGU3ETVO.js";
15
+ import "./chunk-TXVGVZYR.js";
16
+ import "./chunk-XU5P23GN.js";
17
+ import "./chunk-2BIF2NVV.js";
18
+ import "./chunk-57XRIZVC.js";
19
+ import "./chunk-255L5QYW.js";
17
20
  import "./chunk-2MPVVENX.js";
18
21
  import "./chunk-ZTQ26VBE.js";
19
- import "./chunk-C6MI2ASN.js";
20
- import "./chunk-LF6BKGZT.js";
21
- import "./chunk-26ZYKTYZ.js";
22
+ import "./chunk-GZCJS5WH.js";
22
23
  import "./chunk-MLZQVCF3.js";
23
24
  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";
25
+ import "./chunk-OTBK43JR.js";
26
+ import "./chunk-HGNSRCRB.js";
27
+ import {
28
+ WorkspaceContext
29
+ } from "./chunk-EEEZIVFJ.js";
30
+ import "./chunk-PRYMDRBV.js";
31
+ import {
32
+ WorkflowRunEvent,
33
+ logWorkflowRun,
34
+ read,
35
+ writeLine
36
+ } from "./chunk-CICUTYTF.js";
29
37
  import "./chunk-3PJXIDKI.js";
30
38
  import "./chunk-UWCTAVOD.js";
31
39
  import "./chunk-OFEVLU4C.js";
32
40
  import "./chunk-OMX7CUOE.js";
33
- import "./chunk-FH4P6RQA.js";
34
- import "./chunk-CTHZVIMD.js";
41
+ import "./chunk-BNXANYLH.js";
42
+ import "./chunk-T2VDEFUU.js";
35
43
  import {
36
44
  SyntheticOutputTool
37
- } from "./chunk-VKILGMZQ.js";
45
+ } from "./chunk-PO5LVPK3.js";
38
46
  import {
39
47
  BaseDeclarativeTool,
40
48
  BaseToolInvocation,
41
49
  ToolDisplayNames,
42
50
  ToolNames
43
- } from "./chunk-GOMVJKBL.js";
44
- import "./chunk-MSJ2MXJ6.js";
45
- import "./chunk-ATLUHLZE.js";
51
+ } from "./chunk-PLY4F7QW.js";
52
+ import "./chunk-BGUDAULQ.js";
53
+ import "./chunk-EW6C27XX.js";
54
+ import "./chunk-22IFUCVR.js";
46
55
  import {
47
56
  createChildAbortController
48
57
  } from "./chunk-64WXLC72.js";
49
- import "./chunk-LTN3VYMZ.js";
50
- import "./chunk-42HGOMED.js";
51
- import "./chunk-G4BUMVEY.js";
58
+ import "./chunk-3UALQ56H.js";
59
+ import "./chunk-JDV3VBPY.js";
60
+ import "./chunk-CGEGHF2C.js";
61
+ import "./chunk-EJYJYJZ2.js";
52
62
  import "./chunk-55ZMG67I.js";
53
63
  import "./chunk-H6BD2ELD.js";
54
64
  import "./chunk-5IFG2VC4.js";
55
65
  import {
56
66
  createDebugLogger
57
- } from "./chunk-WE6TNQJU.js";
67
+ } from "./chunk-C4K3FEQ2.js";
58
68
  import "./chunk-ZERZSAZL.js";
59
69
  import "./chunk-QN5NZ3UQ.js";
60
70
  import "./chunk-BR4QREVK.js";
@@ -358,9 +368,11 @@ function createWorkflowSandbox(opts) {
358
368
  // init script without leaking the host function itself when not used.
359
369
  hasParallel: !!opts.parallel,
360
370
  hasPipeline: !!opts.pipeline,
371
+ hasWorkflow: !!opts.workflow,
361
372
  hasBudget: !!opts.budget,
362
373
  hostParallel: opts.parallel,
363
374
  hostPipeline: opts.pipeline,
375
+ hostWorkflow: opts.workflow,
364
376
  budgetTotal: opts.budget ? opts.budget.total : null,
365
377
  hostBudgetSpent: opts.budget ? opts.budget.spent.bind(opts.budget) : null,
366
378
  hostBudgetRemaining: opts.budget ? opts.budget.remaining.bind(opts.budget) : null
@@ -466,7 +478,7 @@ function createWorkflowSandbox(opts) {
466
478
  // FIX-Round1-T13: throw on any opts key not in the allowlist \u2014 catches
467
479
  // typos like { scema: ... } that previously slipped through the
468
480
  // [key:string]: unknown index signature.
469
- const KNOWN_AGENT_OPTS = ['label', 'phase', 'schema', 'model', 'isolation', 'agentType'];
481
+ const KNOWN_AGENT_OPTS = ['label', 'phase', 'schema', 'model', 'isolation', 'agentType', 'stallMs'];
470
482
  globalThis.agent = vmAsync(function (prompt, agentOpts) {
471
483
  agentOpts = agentOpts || {};
472
484
  const keys = Object.keys(agentOpts);
@@ -639,15 +651,64 @@ function createWorkflowSandbox(opts) {
639
651
  });
640
652
  };
641
653
  }
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
- ));
654
+ // --- workflow (nested, single-level) ---
655
+ // Mirrors agent(): args cross vm\u2192host verbatim (safe direction), the
656
+ // single result is revived back into the vm realm via JSON round-trip
657
+ // (same T1/T8/T14 escape defense as agent / parallel / pipeline). The
658
+ // host impl resolves a saved workflow and runs it sharing this run's
659
+ // agent-count cap + token budget. When __b.hasWorkflow is false, the
660
+ // sandbox is either bare (no resolver wired) OR is itself a nested
661
+ // workflow \u2014 in both cases workflow() must throw, which is how the
662
+ // single-level nesting limit is enforced (a nested sandbox is created
663
+ // without a workflow impl, so its workflow() lands in the else branch).
664
+ if (__b.hasWorkflow) {
665
+ const callWorkflow = vmAsync(function (nameOrRef, wfArgs) {
666
+ // Sanitize args through a JSON round-trip BEFORE crossing so the
667
+ // host only ever sees vm-realm plain objects (same defense as
668
+ // agent()'s safeOpts). nameOrRef may be a string or {scriptPath}.
669
+ var safeRef;
670
+ var safeArgs;
671
+ try {
672
+ safeRef = nameOrRef === undefined
673
+ ? undefined
674
+ : JSON.parse(JSON.stringify(nameOrRef));
675
+ safeArgs = wfArgs === undefined
676
+ ? undefined
677
+ : JSON.parse(JSON.stringify(wfArgs));
678
+ } catch (e) {
679
+ throw new Error(
680
+ 'workflow() received a non-JSON-serializable argument: ' +
681
+ String(e && e.message != null ? e.message : e)
682
+ );
683
+ }
684
+ return __b.hostWorkflow(safeRef, safeArgs).then(function (value) {
685
+ if (value === null || typeof value !== 'object') {
686
+ return value;
687
+ }
688
+ try {
689
+ return JSON.parse(JSON.stringify(value));
690
+ } catch (e) {
691
+ __b.logRevivalFailure(0, String(e && e.message != null ? e.message : e));
692
+ return null;
693
+ }
694
+ });
649
695
  });
650
- };
696
+ globalThis.workflow = function workflow(nameOrRef, wfArgs) {
697
+ return callWorkflow(nameOrRef, wfArgs);
698
+ };
699
+ } else {
700
+ globalThis.workflow = function workflow() {
701
+ return new Promise(function (_, reject) {
702
+ reject(new Error(
703
+ "workflow() is unavailable here. Either this sandbox was created " +
704
+ "without a saved-workflow resolver, or this script is already " +
705
+ "running as a nested workflow \u2014 workflow() nesting is limited to " +
706
+ "a single level (a workflow cannot call another workflow that " +
707
+ "itself calls workflow())."
708
+ ));
709
+ });
710
+ };
711
+ }
651
712
 
652
713
  // --- budget ---
653
714
  const safeBudget = Object.create(null);
@@ -813,6 +874,231 @@ var WorkflowBudgetExceededError = class extends Error {
813
874
  }
814
875
  };
815
876
 
877
+ // packages/core/src/agents/runtime/workflow-stall.ts
878
+ init_esbuild_shims();
879
+ var DEFAULT_STALL_MS = 6e4;
880
+ var MAX_STALL_ATTEMPTS = 3;
881
+ var MAX_WORKFLOW_STALL_MS_ENV = "QWEN_CODE_WORKFLOW_STALL_SECONDS";
882
+ function resolveStallMs(perCall, env = process.env) {
883
+ if (typeof perCall === "number" && Number.isFinite(perCall)) {
884
+ if (perCall === 0) return 0;
885
+ if (perCall > 0) return perCall;
886
+ }
887
+ const raw = env[MAX_WORKFLOW_STALL_MS_ENV];
888
+ if (raw !== void 0 && raw.trim() !== "") {
889
+ const sec = Number(raw);
890
+ if (Number.isFinite(sec) && sec > 0) return sec * 1e3;
891
+ if (sec === 0) return 0;
892
+ }
893
+ return DEFAULT_STALL_MS;
894
+ }
895
+ __name(resolveStallMs, "resolveStallMs");
896
+ var debugLogger3 = createDebugLogger("WORKFLOW_STALL");
897
+ function attachStallWatchdog(emitter, controller, stallMs) {
898
+ if (stallMs <= 0) {
899
+ return { stalled: /* @__PURE__ */ __name(() => false, "stalled"), dispose: /* @__PURE__ */ __name(() => {
900
+ }, "dispose") };
901
+ }
902
+ let inFlightTools = 0;
903
+ let fired = false;
904
+ let timer;
905
+ let disposed = false;
906
+ const clear = /* @__PURE__ */ __name(() => {
907
+ if (timer) {
908
+ clearTimeout(timer);
909
+ timer = void 0;
910
+ }
911
+ }, "clear");
912
+ const arm = /* @__PURE__ */ __name(() => {
913
+ clear();
914
+ if (disposed || fired) return;
915
+ if (inFlightTools > 0) return;
916
+ timer = setTimeout(() => {
917
+ if (disposed || fired) return;
918
+ fired = true;
919
+ debugLogger3.warn(
920
+ `[Workflow] agent dispatch stalled \u2014 no progress for ${stallMs}ms; aborting.`
921
+ );
922
+ try {
923
+ controller.abort("stalled");
924
+ } catch (e) {
925
+ debugLogger3.warn("stall watchdog abort threw:", e);
926
+ }
927
+ }, stallMs);
928
+ if (typeof timer.unref === "function") {
929
+ timer.unref();
930
+ }
931
+ }, "arm");
932
+ const onActivity = /* @__PURE__ */ __name(() => arm(), "onActivity");
933
+ const onToolCall = /* @__PURE__ */ __name(() => {
934
+ inFlightTools += 1;
935
+ clear();
936
+ }, "onToolCall");
937
+ const onToolResult = /* @__PURE__ */ __name(() => {
938
+ inFlightTools = Math.max(0, inFlightTools - 1);
939
+ arm();
940
+ }, "onToolResult");
941
+ emitter.on("round_start" /* ROUND_START */, onActivity);
942
+ emitter.on("round_end" /* ROUND_END */, onActivity);
943
+ emitter.on("stream_text" /* STREAM_TEXT */, onActivity);
944
+ emitter.on("usage_metadata" /* USAGE_METADATA */, onActivity);
945
+ emitter.on("tool_call" /* TOOL_CALL */, onToolCall);
946
+ emitter.on("tool_result" /* TOOL_RESULT */, onToolResult);
947
+ return {
948
+ stalled: /* @__PURE__ */ __name(() => fired, "stalled"),
949
+ dispose: /* @__PURE__ */ __name(() => {
950
+ if (disposed) return;
951
+ disposed = true;
952
+ clear();
953
+ emitter.off("round_start" /* ROUND_START */, onActivity);
954
+ emitter.off("round_end" /* ROUND_END */, onActivity);
955
+ emitter.off("stream_text" /* STREAM_TEXT */, onActivity);
956
+ emitter.off("usage_metadata" /* USAGE_METADATA */, onActivity);
957
+ emitter.off("tool_call" /* TOOL_CALL */, onToolCall);
958
+ emitter.off("tool_result" /* TOOL_RESULT */, onToolResult);
959
+ }, "dispose")
960
+ };
961
+ }
962
+ __name(attachStallWatchdog, "attachStallWatchdog");
963
+ async function runStallResilient(attemptFn, opts) {
964
+ const { stallMs, signal, label } = opts;
965
+ if (stallMs <= 0) {
966
+ const emitter = new AgentEventEmitter();
967
+ return attemptFn(signal ?? new AbortController().signal, emitter);
968
+ }
969
+ let attempt = 0;
970
+ for (; ; ) {
971
+ attempt += 1;
972
+ const controller = new AbortController();
973
+ let onParentAbort;
974
+ if (signal) {
975
+ if (signal.aborted) {
976
+ controller.abort(signal.reason);
977
+ } else {
978
+ onParentAbort = /* @__PURE__ */ __name(() => controller.abort(signal.reason), "onParentAbort");
979
+ signal.addEventListener("abort", onParentAbort);
980
+ }
981
+ }
982
+ const emitter = new AgentEventEmitter();
983
+ const watchdog = attachStallWatchdog(emitter, controller, stallMs);
984
+ try {
985
+ return await attemptFn(controller.signal, emitter);
986
+ } catch (err) {
987
+ if (signal?.aborted) throw err;
988
+ if (watchdog.stalled() && attempt < MAX_STALL_ATTEMPTS) {
989
+ debugLogger3.warn(
990
+ `[Workflow] agent "${label ?? "workflow-agent"}" stalled (attempt ${attempt}/${MAX_STALL_ATTEMPTS}) \u2014 retrying.`
991
+ );
992
+ continue;
993
+ }
994
+ if (watchdog.stalled()) {
995
+ throw new Error(
996
+ `agent "${label ?? "workflow-agent"}" stalled on all ${MAX_STALL_ATTEMPTS} attempts (no progress for ${stallMs}ms each).`
997
+ );
998
+ }
999
+ throw err;
1000
+ } finally {
1001
+ watchdog.dispose();
1002
+ if (onParentAbort && signal) {
1003
+ signal.removeEventListener("abort", onParentAbort);
1004
+ }
1005
+ }
1006
+ }
1007
+ }
1008
+ __name(runStallResilient, "runStallResilient");
1009
+
1010
+ // packages/core/src/agents/runtime/workflow-journal.ts
1011
+ init_esbuild_shims();
1012
+ import { createHash } from "node:crypto";
1013
+ var debugLogger4 = createDebugLogger("WORKFLOW_JOURNAL");
1014
+ var JOURNAL_KEY_VERSION = "v2";
1015
+ function canonicalizeAgentOpts(opts) {
1016
+ const projected = {};
1017
+ for (const k of ["schema", "model", "isolation", "agentType"]) {
1018
+ const v = opts[k];
1019
+ if (v === void 0 || typeof v === "function") continue;
1020
+ projected[k] = v;
1021
+ }
1022
+ const sortDeep = /* @__PURE__ */ __name((val) => {
1023
+ if (typeof val === "function") return void 0;
1024
+ if (Array.isArray(val)) return val.map(sortDeep);
1025
+ if (val && typeof val === "object") {
1026
+ const out = {};
1027
+ for (const key of Object.keys(val).sort()) {
1028
+ if (key === "__proto__") continue;
1029
+ out[key] = sortDeep(val[key]);
1030
+ }
1031
+ return out;
1032
+ }
1033
+ return val;
1034
+ }, "sortDeep");
1035
+ try {
1036
+ return JSON.stringify(sortDeep(projected));
1037
+ } catch {
1038
+ return "{}";
1039
+ }
1040
+ }
1041
+ __name(canonicalizeAgentOpts, "canonicalizeAgentOpts");
1042
+ function deriveAgentKey(prefixHash, prompt, opts) {
1043
+ const hash = createHash("sha256");
1044
+ hash.update(prefixHash);
1045
+ hash.update("\0");
1046
+ hash.update(prompt);
1047
+ hash.update("\0");
1048
+ hash.update(canonicalizeAgentOpts(opts));
1049
+ return `${JOURNAL_KEY_VERSION}:${hash.digest("hex")}`;
1050
+ }
1051
+ __name(deriveAgentKey, "deriveAgentKey");
1052
+ function deriveArgsSeed(args) {
1053
+ const hash = createHash("sha256");
1054
+ let serialized;
1055
+ try {
1056
+ serialized = JSON.stringify(args ?? null) ?? "null";
1057
+ } catch {
1058
+ serialized = "non-serializable-args";
1059
+ }
1060
+ hash.update(serialized);
1061
+ return `${JOURNAL_KEY_VERSION}:${hash.digest("hex")}`;
1062
+ }
1063
+ __name(deriveArgsSeed, "deriveArgsSeed");
1064
+ function buildReplay(entries) {
1065
+ const results = /* @__PURE__ */ new Map();
1066
+ const started = /* @__PURE__ */ new Map();
1067
+ for (const e of entries) {
1068
+ if (e.type === "result") {
1069
+ results.set(e.key, e);
1070
+ } else if (e.type === "started") {
1071
+ const list = started.get(e.key);
1072
+ if (list) list.push(e);
1073
+ else started.set(e.key, [e]);
1074
+ }
1075
+ }
1076
+ return { results, started };
1077
+ }
1078
+ __name(buildReplay, "buildReplay");
1079
+ var WorkflowJournal = class {
1080
+ constructor(path2) {
1081
+ this.path = path2;
1082
+ }
1083
+ static {
1084
+ __name(this, "WorkflowJournal");
1085
+ }
1086
+ /** Load + parse all entries into replay maps. Empty maps if no file. */
1087
+ async load() {
1088
+ try {
1089
+ const entries = await read(this.path);
1090
+ return buildReplay(entries);
1091
+ } catch (e) {
1092
+ debugLogger4.warn(`WorkflowJournal.load failed for ${this.path}: ${e}`);
1093
+ return { results: /* @__PURE__ */ new Map(), started: /* @__PURE__ */ new Map() };
1094
+ }
1095
+ }
1096
+ /** Append one entry. Rejects only on I/O error (callers `.catch`). */
1097
+ append(entry) {
1098
+ return writeLine(this.path, entry);
1099
+ }
1100
+ };
1101
+
816
1102
  // packages/core/src/agents/runtime/workflow-prompts.ts
817
1103
  init_esbuild_shims();
818
1104
  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.';
@@ -946,48 +1232,65 @@ function sanitizeForErrorMessage(value) {
946
1232
  __name(sanitizeForErrorMessage, "sanitizeForErrorMessage");
947
1233
  function createProductionDispatch(config, signal, onTokens) {
948
1234
  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",
955
- 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
- );
1235
+ const stallMs = resolveStallMs(
1236
+ typeof opts.stallMs === "number" ? opts.stallMs : void 0
1237
+ );
1238
+ return runStallResilient(
1239
+ (attemptSignal, emitter) => runSingleDispatch(config, prompt, opts, attemptSignal, emitter, onTokens),
1240
+ {
1241
+ stallMs,
1242
+ signal,
1243
+ label: typeof opts.label === "string" ? opts.label : void 0
984
1244
  }
985
- return subagent.getFinalText();
986
- }
987
- return runOverridePath(config, ctx, opts, signal, onTokens);
1245
+ );
988
1246
  };
989
1247
  }
990
1248
  __name(createProductionDispatch, "createProductionDispatch");
1249
+ async function runSingleDispatch(config, prompt, opts, attemptSignal, emitter, onTokens) {
1250
+ const { AgentHeadless, ContextState } = await import("./agent-headless-ZMTUWMZJ.js");
1251
+ const ctx = new ContextState();
1252
+ ctx.set("task_prompt", prompt);
1253
+ if (opts.agentType === void 0 && opts.model === void 0 && opts.isolation === void 0 && opts.schema === void 0) {
1254
+ const subagent = await AgentHeadless.create(
1255
+ opts.label ?? "workflow-agent",
1256
+ config,
1257
+ {
1258
+ systemPrompt: WORKFLOW_SUBAGENT_SYSTEM_PROMPT,
1259
+ initialMessages: []
1260
+ },
1261
+ {},
1262
+ // T11 (PR #4732 R1): bound resource ceiling so a single agent() call
1263
+ // cannot loop the model indefinitely. Without this, runConfig was {}
1264
+ // and the loop guards never tripped — combined with the cancellation
1265
+ // bug below, workflows were effectively unkillable.
1266
+ {
1267
+ max_turns: WORKFLOW_SUBAGENT_MAX_TURNS,
1268
+ max_time_minutes: WORKFLOW_SUBAGENT_MAX_TIME_MINUTES
1269
+ },
1270
+ // T11 (PR #4732 R1): disallow SendMessage / ExitPlanMode to align with
1271
+ // upstream Tg8 — closes the back-channel that would let a subagent
1272
+ // deliver its answer via user message instead of the script's read.
1273
+ { tools: ["*"], disallowedTools: WORKFLOW_SUBAGENT_DISALLOWED_TOOLS },
1274
+ // P-stall: the stall-watchdog emitter observes reasoning-loop events
1275
+ // (round/tool/usage) to detect a hang and abort `attemptSignal`.
1276
+ emitter
1277
+ );
1278
+ try {
1279
+ await subagent.execute(ctx, attemptSignal);
1280
+ } finally {
1281
+ reportTokens(subagent, opts, onTokens);
1282
+ }
1283
+ const mode = subagent.getTerminateMode();
1284
+ if (mode !== "GOAL" /* GOAL */) {
1285
+ throw new Error(
1286
+ `Workflow subagent did not complete (terminate mode: ${mode}).`
1287
+ );
1288
+ }
1289
+ return subagent.getFinalText();
1290
+ }
1291
+ return runOverridePath(config, ctx, opts, attemptSignal, onTokens, emitter);
1292
+ }
1293
+ __name(runSingleDispatch, "runSingleDispatch");
991
1294
  function reportTokens(subagent, opts, onTokens) {
992
1295
  if (!onTokens) return;
993
1296
  try {
@@ -998,7 +1301,7 @@ function reportTokens(subagent, opts, onTokens) {
998
1301
  }
999
1302
  }
1000
1303
  __name(reportTokens, "reportTokens");
1001
- async function runOverridePath(config, ctx, opts, signal, onTokens) {
1304
+ async function runOverridePath(config, ctx, opts, signal, onTokens, emitter) {
1002
1305
  if (opts.isolation === "remote") {
1003
1306
  throw new Error(
1004
1307
  "agent({isolation:'remote'}) is not available in this build."
@@ -1079,7 +1382,10 @@ ${WORKFLOW_SUBAGENT_SYSTEM_PROMPT_WITH_SCHEMA}` : WORKFLOW_SUBAGENT_SYSTEM_PROMP
1079
1382
  schemaState.abortController = child;
1080
1383
  dispatchSignal = child.signal;
1081
1384
  }
1082
- const eventEmitter = schemaState ? createSchemaEventEmitter(schemaState) : void 0;
1385
+ const eventEmitter = emitter ?? (schemaState ? new AgentEventEmitter() : void 0);
1386
+ if (schemaState && eventEmitter) {
1387
+ attachSchemaListeners(eventEmitter, schemaState);
1388
+ }
1083
1389
  const { subagent, dispose } = await subagentMgr.createAgentHeadless(
1084
1390
  augmented,
1085
1391
  effectiveContext,
@@ -1318,8 +1624,7 @@ function createSchemaModeState() {
1318
1624
  };
1319
1625
  }
1320
1626
  __name(createSchemaModeState, "createSchemaModeState");
1321
- function createSchemaEventEmitter(state) {
1322
- const emitter = new AgentEventEmitter();
1627
+ function attachSchemaListeners(emitter, state) {
1323
1628
  const targetTool = ToolNames.STRUCTURED_OUTPUT;
1324
1629
  emitter.on("tool_call" /* TOOL_CALL */, (evt) => {
1325
1630
  if (evt.name !== targetTool) return;
@@ -1341,9 +1646,8 @@ function createSchemaEventEmitter(state) {
1341
1646
  state.abortController.abort();
1342
1647
  }
1343
1648
  });
1344
- return emitter;
1345
1649
  }
1346
- __name(createSchemaEventEmitter, "createSchemaEventEmitter");
1650
+ __name(attachSchemaListeners, "attachSchemaListeners");
1347
1651
  async function createSchemaConfigOverride(base, schema) {
1348
1652
  const override = Object.create(base);
1349
1653
  await rebuildToolRegistryOnOverride(override, base);
@@ -1367,7 +1671,46 @@ var WorkflowOrchestrator = class {
1367
1671
  let agentCount = 0;
1368
1672
  const emitter = req.emitter;
1369
1673
  const budget = req.budget;
1674
+ const journal = req.journal;
1675
+ const replay = req.resumeReplay;
1676
+ let prefixHash = deriveArgsSeed(req.args);
1677
+ let hadMiss = false;
1678
+ let journalAgentId = 0;
1370
1679
  const countedDispatch = /* @__PURE__ */ __name((prompt, opts) => {
1680
+ let journalKey;
1681
+ let journalEntryId;
1682
+ if (journal) {
1683
+ journalKey = deriveAgentKey(prefixHash, prompt, opts);
1684
+ prefixHash = journalKey;
1685
+ if (!hadMiss && replay) {
1686
+ const cached = replay.results.get(journalKey);
1687
+ if (cached !== void 0) {
1688
+ const respawns = replay.started.get(journalKey);
1689
+ if (respawns && respawns.length > 0) {
1690
+ debugLogger.info(
1691
+ `[Workflow] resume cache hit after ${respawns.length} prior respawn(s) for runId=${runId}.`
1692
+ );
1693
+ }
1694
+ const label2 = typeof opts.label === "string" ? opts.label : void 0;
1695
+ try {
1696
+ emitter?.agentDispatched?.(label2);
1697
+ } catch (e) {
1698
+ debugLogger.warn("emitter.agentDispatched threw:", e);
1699
+ }
1700
+ try {
1701
+ emitter?.agentCompleted?.(label2);
1702
+ } catch (e) {
1703
+ debugLogger.warn("emitter.agentCompleted threw:", e);
1704
+ }
1705
+ return Promise.resolve(cached.result);
1706
+ }
1707
+ }
1708
+ hadMiss = true;
1709
+ journalEntryId = String(journalAgentId += 1);
1710
+ journal.append({ type: "started", key: journalKey, agentId: journalEntryId }).catch(
1711
+ (e) => debugLogger.warn(`journal started-append failed: ${e}`)
1712
+ );
1713
+ }
1371
1714
  if (budget && budget.total !== null && budget.remaining() <= 0) {
1372
1715
  debugLogger.warn(
1373
1716
  `[Workflow] budget gate refused dispatch at entry: runId=${runId} spent=${budget.spent()} total=${budget.total}`
@@ -1409,6 +1752,16 @@ var WorkflowOrchestrator = class {
1409
1752
  } catch (e) {
1410
1753
  debugLogger.warn("emitter.agentCompleted threw:", e);
1411
1754
  }
1755
+ if (journal && journalKey !== void 0) {
1756
+ journal.append({
1757
+ type: "result",
1758
+ key: journalKey,
1759
+ agentId: journalEntryId ?? "",
1760
+ result
1761
+ }).catch(
1762
+ (e) => debugLogger.warn(`journal result-append failed: ${e}`)
1763
+ );
1764
+ }
1412
1765
  if (budget) {
1413
1766
  try {
1414
1767
  emitter?.budgetUpdated?.(budget.spent(), budget.total);
@@ -1438,11 +1791,27 @@ var WorkflowOrchestrator = class {
1438
1791
  }, "countedDispatch");
1439
1792
  const parallelImpl = makeParallelImpl(signal);
1440
1793
  const pipelineImpl = makePipelineImpl(signal);
1794
+ const resolveSavedWorkflow = req.resolveSavedWorkflow;
1795
+ const workflowImpl = resolveSavedWorkflow ? async (nameOrRef, nestedArgs) => {
1796
+ const resolved = await resolveSavedWorkflow(nameOrRef);
1797
+ const nestedSandbox = createWorkflowSandbox({
1798
+ args: nestedArgs,
1799
+ dispatch: countedDispatch,
1800
+ parallel: parallelImpl,
1801
+ pipeline: pipelineImpl,
1802
+ abortOnTimeout: req.abortOnTimeout,
1803
+ emitter,
1804
+ budget
1805
+ // No `workflow` — single-level nesting limit.
1806
+ });
1807
+ return nestedSandbox.run(resolved.script);
1808
+ } : void 0;
1441
1809
  const sandbox = createWorkflowSandbox({
1442
1810
  args: req.args,
1443
1811
  dispatch: countedDispatch,
1444
1812
  parallel: parallelImpl,
1445
1813
  pipeline: pipelineImpl,
1814
+ workflow: workflowImpl,
1446
1815
  abortOnTimeout: req.abortOnTimeout,
1447
1816
  emitter,
1448
1817
  budget
@@ -1466,19 +1835,31 @@ var WorkflowOrchestrator = class {
1466
1835
  }
1467
1836
  }
1468
1837
  };
1469
- async function settleToNullArray(thunks, signal) {
1838
+ async function settleToNullArray(thunks, signal, kind = "parallel") {
1470
1839
  const settled = await Promise.allSettled(
1471
1840
  thunks.map((t) => Promise.resolve().then(t))
1472
1841
  );
1473
1842
  if (signal?.aborted)
1474
1843
  throw new DOMException("Workflow run aborted.", "AbortError");
1475
- return settled.map((r, i) => {
1844
+ let budgetDropped = 0;
1845
+ const result = settled.map((r, i) => {
1476
1846
  if (r.status === "fulfilled") return r.value;
1477
- debugLogger.warn(
1478
- `Workflow thunk at index ${i} rejected: ${String(r.reason?.message ?? r.reason)}`
1479
- );
1847
+ const reason = r.reason;
1848
+ if (reason?.name === "WorkflowBudgetExceededError") {
1849
+ budgetDropped += 1;
1850
+ } else {
1851
+ debugLogger.warn(
1852
+ `Workflow thunk at index ${i} rejected: ${String(reason?.message ?? r.reason)}`
1853
+ );
1854
+ }
1480
1855
  return null;
1481
1856
  });
1857
+ if (budgetDropped > 0) {
1858
+ debugLogger.warn(
1859
+ `${kind}: ${budgetDropped} slot${budgetDropped === 1 ? "" : "s"} dropped \u2014 token budget exceeded.`
1860
+ );
1861
+ }
1862
+ return result;
1482
1863
  }
1483
1864
  __name(settleToNullArray, "settleToNullArray");
1484
1865
  function makeParallelImpl(signal) {
@@ -1524,7 +1905,7 @@ function makePipelineImpl(signal) {
1524
1905
  const chains = items.map(
1525
1906
  (item, idx) => () => runPipelineChain(item, idx, stages)
1526
1907
  );
1527
- return settleToNullArray(chains, signal);
1908
+ return settleToNullArray(chains, signal, "pipeline");
1528
1909
  };
1529
1910
  }
1530
1911
  __name(makePipelineImpl, "makePipelineImpl");
@@ -1549,6 +1930,7 @@ __name(extractErrorMessage, "extractErrorMessage");
1549
1930
 
1550
1931
  // packages/core/src/tools/workflow/workflow.ts
1551
1932
  import { randomBytes as randomBytes2 } from "node:crypto";
1933
+ import * as path from "node:path";
1552
1934
  var WORKFLOW_PARAM_SCHEMA = {
1553
1935
  type: "object",
1554
1936
  properties: {
@@ -1556,11 +1938,22 @@ var WORKFLOW_PARAM_SCHEMA = {
1556
1938
  type: "string",
1557
1939
  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
1940
  },
1941
+ scriptPath: {
1942
+ type: "string",
1943
+ 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."
1944
+ },
1559
1945
  args: {
1560
1946
  description: "Optional structured value bound to the `args` global. Pass actual JSON, not a stringified value."
1947
+ },
1948
+ resumeFromRunId: {
1949
+ type: "string",
1950
+ 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
1951
  }
1562
- },
1563
- required: ["script"]
1952
+ }
1953
+ // `script` is required UNLESS `scriptPath` is supplied; this XOR can't be
1954
+ // expressed as a plain `required` list, so it's enforced in
1955
+ // `validateToolParamValues`. Inline authoring (the LLM path) should always
1956
+ // pass `script`; the `scriptPath` property description states the XOR.
1564
1957
  };
1565
1958
  var WorkflowToolInvocation = class extends BaseToolInvocation {
1566
1959
  constructor(config, toolOptions, params) {
@@ -1572,7 +1965,10 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
1572
1965
  __name(this, "WorkflowToolInvocation");
1573
1966
  }
1574
1967
  getDescription() {
1575
- return `Run a workflow script (${this.params.script.length} chars)`;
1968
+ if (this.params.scriptPath && this.params.script === void 0) {
1969
+ return `Run saved workflow (${path.basename(this.params.scriptPath)})`;
1970
+ }
1971
+ return `Run a workflow script (${this.params.script?.length ?? 0} chars)`;
1576
1972
  }
1577
1973
  toolLocations() {
1578
1974
  return [];
@@ -1592,7 +1988,26 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
1592
1988
  (outputTokens) => budget.recordSpent(outputTokens)
1593
1989
  );
1594
1990
  const orchestrator = new WorkflowOrchestrator(dispatch);
1595
- const runId = `wf_${randomBytes2(8).toString("hex")}`;
1991
+ let resolvedScript = this.params.script ?? "";
1992
+ let resolvedScriptPath = this.params.scriptPath;
1993
+ if (this.params.scriptPath && this.params.script === void 0) {
1994
+ const loaded = await resolveSavedWorkflowScript(
1995
+ { scriptPath: this.params.scriptPath },
1996
+ this.config
1997
+ );
1998
+ resolvedScript = loaded.script;
1999
+ resolvedScriptPath = loaded.scriptPath;
2000
+ }
2001
+ const runId = this.params.resumeFromRunId ?? `wf_${randomBytes2(8).toString("hex")}`;
2002
+ let journal;
2003
+ let resumeReplay;
2004
+ const storage = this.config.storage;
2005
+ if (storage) {
2006
+ journal = new WorkflowJournal(storage.getWorkflowRunJournalPath(runId));
2007
+ if (this.params.resumeFromRunId) {
2008
+ resumeReplay = await journal.load();
2009
+ }
2010
+ }
1596
2011
  const registry = this.config.getWorkflowRunRegistry?.();
1597
2012
  const registryEntry = registry?.register({
1598
2013
  runId,
@@ -1606,7 +2021,13 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
1606
2021
  // P5: seed the cap so the dialog can render the `M / N` form
1607
2022
  // immediately, before the first `budgetUpdated` fires. Stays
1608
2023
  // `null` when no env override.
1609
- tokenBudgetTotal: budget.total
2024
+ tokenBudgetTotal: budget.total,
2025
+ // P7b: carry the script source so a completed run can be snapshotted
2026
+ // to disk and saved to `.qwen/workflows/<name>.js` from the dialog.
2027
+ // `scriptPath` is set when the run was launched from a saved file (run
2028
+ // provenance for the snapshot).
2029
+ script: resolvedScript,
2030
+ scriptPath: resolvedScriptPath
1610
2031
  });
1611
2032
  const emitter = {
1612
2033
  phaseStarted: /* @__PURE__ */ __name((title) => {
@@ -1629,12 +2050,18 @@ var WorkflowToolInvocation = class extends BaseToolInvocation {
1629
2050
  };
1630
2051
  try {
1631
2052
  const outcome = await orchestrator.run({
1632
- script: this.params.script,
2053
+ script: resolvedScript,
1633
2054
  args: this.params.args,
1634
2055
  abortOnTimeout: dispatchController,
1635
2056
  runId,
1636
2057
  emitter,
1637
- budget
2058
+ budget,
2059
+ // P-nested: resolve `workflow('<name>')` / `workflow({scriptPath})`
2060
+ // against the saved-workflow scripts in `.qwen/workflows/`.
2061
+ resolveSavedWorkflow: /* @__PURE__ */ __name((ref) => resolveSavedWorkflowScript(ref, this.config), "resolveSavedWorkflow"),
2062
+ // P6: resume journal (always wired) + replay maps (resume only).
2063
+ journal,
2064
+ resumeReplay
1638
2065
  });
1639
2066
  if (registryEntry) {
1640
2067
  registryEntry.meta = outcome.meta;
@@ -1704,6 +2131,23 @@ ${safeStringifyDisplayPayload({
1704
2131
  };
1705
2132
  } finally {
1706
2133
  dispatchController.abort();
2134
+ if (registryEntry && registryEntry.status !== "running") {
2135
+ await writeWorkflowSnapshot(this.config, registryEntry);
2136
+ try {
2137
+ logWorkflowRun(
2138
+ this.config,
2139
+ new WorkflowRunEvent({
2140
+ status: registryEntry.status,
2141
+ agents_dispatched: registryEntry.agentsDispatched,
2142
+ agents_completed: registryEntry.agentsCompleted,
2143
+ phase_count: registryEntry.phases.length,
2144
+ tokens_spent: registryEntry.tokensSpent,
2145
+ duration_ms: (registryEntry.endTime ?? registryEntry.startTime) - registryEntry.startTime
2146
+ })
2147
+ );
2148
+ } catch {
2149
+ }
2150
+ }
1707
2151
  }
1708
2152
  }
1709
2153
  };
@@ -1803,7 +2247,7 @@ var WorkflowTool = class extends BaseDeclarativeTool {
1803
2247
  super(
1804
2248
  ToolNames.WORKFLOW,
1805
2249
  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.",
2250
+ "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
2251
  "other" /* Other */,
1808
2252
  WORKFLOW_PARAM_SCHEMA,
1809
2253
  /* isOutputMarkdown */
@@ -1818,8 +2262,16 @@ var WorkflowTool = class extends BaseDeclarativeTool {
1818
2262
  __name(this, "WorkflowTool");
1819
2263
  }
1820
2264
  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.";
2265
+ const hasScript = typeof params.script === "string" && params.script.length > 0;
2266
+ const hasPath = typeof params.scriptPath === "string" && params.scriptPath.length > 0;
2267
+ if (!hasScript && !hasPath) {
2268
+ return "WorkflowTool: provide `script` (inline source) or `scriptPath` (a saved workflow file).";
2269
+ }
2270
+ if (hasScript && hasPath) {
2271
+ return "WorkflowTool: provide exactly one of `script` or `scriptPath`, not both.";
2272
+ }
2273
+ if (params.resumeFromRunId !== void 0 && !/^wf_[0-9a-f]+$/.test(params.resumeFromRunId)) {
2274
+ return "WorkflowTool: `resumeFromRunId` must match the generated id format `wf_<hex>`.";
1823
2275
  }
1824
2276
  return null;
1825
2277
  }