@qwen-code/qwen-code 0.21.12-preview.3 → 0.21.12-preview.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +10 -0
  2. package/bundled/qc-helper/docs/features/code-review.md +1 -1
  3. package/bundled/qc-helper/docs/qwen-serve.md +34 -34
  4. package/bundled/review/SKILL.md +55 -36
  5. package/chunks/{MaxSizedBox-EIK4BHBQ.js → MaxSizedBox-GFI5RYXH.js} +41 -41
  6. package/chunks/{StandaloneSessionPicker-NHVJDRYD.js → StandaloneSessionPicker-JFWRY4V2.js} +60 -60
  7. package/chunks/{acp-startup-profiler-JMJBZDVO.js → acp-startup-profiler-TVI2OVUN.js} +2 -2
  8. package/chunks/{acpAgent-37UDZP64.js → acpAgent-7YC6SNIS.js} +672 -428
  9. package/chunks/{agent-FAWBG7PP.js → agent-43KVQSB5.js} +38 -38
  10. package/chunks/{agent-headless-SHK4PCCH.js → agent-headless-P2N7PDGQ.js} +38 -38
  11. package/chunks/{anthropicContentGenerator-4JSC3ZFL.js → anthropicContentGenerator-ZBBX5VMY.js} +6 -6
  12. package/chunks/{artifact-tool-FRMBPDPB.js → artifact-tool-RWJAKYBZ.js} +2 -2
  13. package/chunks/{askUserQuestion-7G3LI3IZ.js → askUserQuestion-IQCA2SOX.js} +2 -2
  14. package/chunks/{bridge-DEAYNDCI.js → bridge-ZBMNALLA.js} +44 -44
  15. package/chunks/{channel-management-service-SKAN6NOB.js → channel-management-service-5ZYX4ROW.js} +4 -4
  16. package/chunks/{channel-settings-store-UIGYER6R.js → channel-settings-store-ZJWM7EDP.js} +45 -45
  17. package/chunks/{channel-worker-group-YPTB5ASD.js → channel-worker-group-QFJKXO7R.js} +5 -5
  18. package/chunks/{channel-worker-manager-4EHJSPRH.js → channel-worker-manager-PWD2UURZ.js} +5 -5
  19. package/chunks/{channel-worker-supervisor-DZKHYFHV.js → channel-worker-supervisor-XQJBGFCM.js} +3 -3
  20. package/chunks/{chunk-GZGDJ4E6.js → chunk-2ASWIM4A.js} +1 -1
  21. package/chunks/{chunk-DP3IHZGG.js → chunk-2AUM35J5.js} +59 -7
  22. package/chunks/{chunk-T4FTABSW.js → chunk-2N6CV4PW.js} +1 -1
  23. package/chunks/{chunk-5PWLQ7SK.js → chunk-2RTRFLWH.js} +11 -4
  24. package/chunks/{chunk-TYGKUOEG.js → chunk-2U3UCXZ3.js} +2 -1
  25. package/chunks/{chunk-QZ5G26ZE.js → chunk-32SNBMNP.js} +12 -12
  26. package/chunks/{chunk-NPE3STIW.js → chunk-3JI5D6RU.js} +3 -3
  27. package/chunks/{chunk-E5BWLU5J.js → chunk-3MJ44LNC.js} +59 -23
  28. package/chunks/{chunk-QUESTNOP.js → chunk-4JS2QK7P.js} +1 -1
  29. package/chunks/{chunk-L7T742G2.js → chunk-4X5J3V2I.js} +47 -3
  30. package/chunks/{chunk-IQFYO5BF.js → chunk-5KZNWF2M.js} +1 -1
  31. package/chunks/{chunk-EXG2R5UR.js → chunk-62TIEFNN.js} +8 -8
  32. package/chunks/{chunk-T6W4KACQ.js → chunk-67F2BEYW.js} +1 -1
  33. package/chunks/{chunk-NELCY6JT.js → chunk-6LDLDK6E.js} +1 -1
  34. package/chunks/{chunk-5I5NMQCU.js → chunk-6NQWER7D.js} +3 -3
  35. package/chunks/{chunk-732MOPEM.js → chunk-6OJDN5ZT.js} +1 -1
  36. package/chunks/{chunk-GLWWPFTW.js → chunk-6SU6OW5Z.js} +1 -1
  37. package/chunks/{chunk-TEKFBSMY.js → chunk-6T5HCY34.js} +3 -3
  38. package/chunks/{chunk-AQHNAA7E.js → chunk-7JL5YBSA.js} +1 -1
  39. package/chunks/{chunk-NWPO6I7V.js → chunk-7WUMS2UA.js} +1 -1
  40. package/chunks/{chunk-O5G7IQGM.js → chunk-A2QIWDFO.js} +347 -85
  41. package/chunks/{chunk-KT4OWAAZ.js → chunk-A4BAHMJF.js} +3 -3
  42. package/chunks/{chunk-N7NBMAMW.js → chunk-A6GQUQ7I.js} +2 -2
  43. package/chunks/{chunk-XLQS3VI6.js → chunk-AAZWJAPQ.js} +2 -2
  44. package/chunks/{chunk-LT532KF4.js → chunk-ADJDLEVO.js} +1 -1
  45. package/chunks/{chunk-VWD7SNNN.js → chunk-APQTLUZ3.js} +2120 -2085
  46. package/chunks/{chunk-AJX4ITUG.js → chunk-ARL4UGRW.js} +3 -3
  47. package/chunks/{chunk-ZQSNP4TG.js → chunk-B2BKFWJK.js} +2 -2
  48. package/chunks/{chunk-SAQHDAUJ.js → chunk-B66LYK4B.js} +452 -57
  49. package/chunks/{chunk-6ZIIHBNV.js → chunk-B7IBCWDW.js} +3 -3
  50. package/chunks/{chunk-5UPJ774B.js → chunk-BGIKUE5J.js} +1 -1
  51. package/chunks/{chunk-2J53A6MV.js → chunk-BNRIQWXW.js} +3 -3
  52. package/chunks/{chunk-CZXQ4UZA.js → chunk-BXAGPCYH.js} +1 -1
  53. package/chunks/{chunk-IEP44U2R.js → chunk-C2DR57L6.js} +1 -1
  54. package/chunks/{chunk-TBVNYG5B.js → chunk-CDDLHCC2.js} +3 -3
  55. package/chunks/{chunk-CG3OQDNY.js → chunk-CJNKGZLC.js} +6 -6
  56. package/chunks/{chunk-UZPWH6SP.js → chunk-CTEGMF77.js} +285 -125
  57. package/chunks/{chunk-3TT6MZHJ.js → chunk-DUFZ3OW6.js} +35 -35
  58. package/chunks/{chunk-ZWPWQEF5.js → chunk-E74YSVIN.js} +1 -1
  59. package/chunks/{chunk-RQVVXDHS.js → chunk-ECDXUCEO.js} +4 -4
  60. package/chunks/{chunk-47FQVRCO.js → chunk-EGB2PIYM.js} +1 -1
  61. package/chunks/{chunk-JL3LC3CQ.js → chunk-FB5CQZMK.js} +1 -1
  62. package/chunks/{chunk-U6PTKAOW.js → chunk-FNVF5RR4.js} +1 -1
  63. package/chunks/{chunk-O4BBDP2G.js → chunk-FTGU6G45.js} +2 -2
  64. package/chunks/{chunk-ZGWY4YUB.js → chunk-FVHLDSQS.js} +2 -2
  65. package/chunks/{chunk-RRQJPCRQ.js → chunk-FXWGMPAP.js} +2 -2
  66. package/chunks/{chunk-P64FPV3G.js → chunk-GDNDZJSG.js} +2 -2
  67. package/chunks/{chunk-M6HXP2SG.js → chunk-GHOUZ5X4.js} +1892 -622
  68. package/chunks/{chunk-M6SXIXBV.js → chunk-H2U4FK62.js} +6 -6
  69. package/chunks/{chunk-EFIMD5VA.js → chunk-H6BFLALJ.js} +1 -1
  70. package/chunks/{chunk-TYCXSMZU.js → chunk-HOJZ2QQA.js} +3 -3
  71. package/chunks/{chunk-Y66OOMKS.js → chunk-HWCHDINS.js} +21 -21
  72. package/chunks/{chunk-4GLFFNP3.js → chunk-HY5OHJEC.js} +5 -5
  73. package/chunks/{chunk-P2UCMHDT.js → chunk-IJCZP2MA.js} +2 -2
  74. package/chunks/{chunk-I4XSOFH2.js → chunk-JBZYGFIB.js} +1 -1
  75. package/chunks/{chunk-HBZUU4AE.js → chunk-JGD35ZSJ.js} +4 -4
  76. package/chunks/{chunk-DAX3G67A.js → chunk-JOVJCXN4.js} +1 -1
  77. package/chunks/{chunk-YI6UGZF5.js → chunk-JRMUA53D.js} +12 -12
  78. package/chunks/{chunk-CTQE2NB2.js → chunk-JRTJEGSP.js} +1 -1
  79. package/chunks/{chunk-MZSJ43WV.js → chunk-JVY7FHUZ.js} +15 -2
  80. package/chunks/{chunk-K7JW6V5O.js → chunk-JW5UEE3V.js} +1 -1
  81. package/chunks/{chunk-GYBDYWMV.js → chunk-JXS2JNMZ.js} +2 -2
  82. package/chunks/{chunk-L2GTEEEU.js → chunk-K5IDV3PC.js} +44 -1
  83. package/chunks/{chunk-N3FJOQX7.js → chunk-KB4ISUT3.js} +4 -4
  84. package/chunks/{chunk-GJJQV4PY.js → chunk-KK3FEHPJ.js} +1 -1
  85. package/chunks/{chunk-2AZMF6G5.js → chunk-KTWUFHS4.js} +2 -2
  86. package/chunks/{chunk-7D4KEFOT.js → chunk-L3YACXS2.js} +3 -3
  87. package/chunks/{chunk-575MI5K3.js → chunk-LIBTBTHP.js} +4 -4
  88. package/chunks/{chunk-JS4Q5NG5.js → chunk-LSMCI42W.js} +3 -3
  89. package/chunks/{chunk-YZJVVQD3.js → chunk-MTV5W6WN.js} +7 -7
  90. package/chunks/{chunk-UOMZKPI5.js → chunk-MUN34TTF.js} +7 -7
  91. package/chunks/{chunk-LHY6HBRA.js → chunk-N3J3CO35.js} +4 -4
  92. package/chunks/{chunk-TRYJ3BVE.js → chunk-N56NYJWY.js} +7 -7
  93. package/chunks/{chunk-3ZYX7AUR.js → chunk-NAOHSM56.js} +1 -1
  94. package/chunks/{chunk-URK542T4.js → chunk-NF5J2WFA.js} +15 -2
  95. package/chunks/{chunk-OPBATTFQ.js → chunk-NHZF4VCD.js} +1 -1
  96. package/chunks/{chunk-QTI7SRXI.js → chunk-NM33GGOM.js} +3 -3
  97. package/chunks/{chunk-F6AOBFUN.js → chunk-NW7SPXVG.js} +1 -1
  98. package/chunks/{chunk-J7DNMZFO.js → chunk-NX5QZVRS.js} +1 -1
  99. package/chunks/{chunk-WFRHWDBT.js → chunk-O4MVJKSX.js} +5 -5
  100. package/chunks/{chunk-NC4O6UE6.js → chunk-O6SLWH4X.js} +2 -2
  101. package/chunks/{chunk-V4MJ56RS.js → chunk-OIZWCOYC.js} +5 -5
  102. package/chunks/{chunk-JXK3WAP7.js → chunk-ORR5EFCL.js} +4 -4
  103. package/chunks/{chunk-EYY4IBPV.js → chunk-OSA2TFDI.js} +2 -2
  104. package/chunks/{chunk-KPVVWKF3.js → chunk-PSTHNTHF.js} +1 -1
  105. package/chunks/{chunk-4M2F7OG7.js → chunk-PYLVQ6RT.js} +6 -6
  106. package/chunks/{chunk-6AECVSVX.js → chunk-Q7ALOKK7.js} +3 -3
  107. package/chunks/{chunk-EYW54TBD.js → chunk-QEWAHAW2.js} +3 -3
  108. package/chunks/{chunk-N5ULBHP3.js → chunk-QSDPJROT.js} +2 -2
  109. package/chunks/{chunk-DYVCDQW2.js → chunk-QSMZHJ62.js} +1 -1
  110. package/chunks/{chunk-MDFUBQAQ.js → chunk-QWAI7FNT.js} +17 -17
  111. package/chunks/{chunk-M4OYAR6J.js → chunk-QXFAQDBV.js} +2 -2
  112. package/chunks/{chunk-ILVATFYJ.js → chunk-SFBRH5RY.js} +19 -15
  113. package/chunks/{chunk-EYS3GGM3.js → chunk-SKRHR6N2.js} +1 -1
  114. package/chunks/{chunk-6LYDH7VT.js → chunk-SNHBRO4C.js} +2 -2
  115. package/chunks/{chunk-5TXOGH4I.js → chunk-T4G33L3W.js} +3 -3
  116. package/chunks/{chunk-32VOOMEF.js → chunk-TB6DPBE4.js} +4 -4
  117. package/chunks/{chunk-DEG7R6Z6.js → chunk-TN3REXN4.js} +8 -8
  118. package/chunks/{chunk-MWZYNOCG.js → chunk-TNETSI2A.js} +3 -3
  119. package/chunks/{chunk-ZV4XVYL3.js → chunk-TROB4PZY.js} +4 -4
  120. package/chunks/{chunk-O5AZPHYZ.js → chunk-U5C2GIN2.js} +24 -16
  121. package/chunks/{chunk-3GCU5O2E.js → chunk-U7ROFHSH.js} +1 -1
  122. package/chunks/{chunk-HB6QW4LM.js → chunk-UAAWNTOC.js} +15 -12
  123. package/chunks/{chunk-HHGQGTJQ.js → chunk-UFHPAMAV.js} +4 -0
  124. package/chunks/{chunk-V3LXMASR.js → chunk-UHF5VBKO.js} +1 -1
  125. package/chunks/{chunk-FRH4SSGX.js → chunk-UPUAGRKY.js} +2 -2
  126. package/chunks/{chunk-6S52N6PG.js → chunk-UQPLUR4A.js} +2 -2
  127. package/chunks/{chunk-KIFRFCCB.js → chunk-UWIJU22K.js} +66 -19
  128. package/chunks/{chunk-HGCQ5SE7.js → chunk-UXEO7E3V.js} +21 -0
  129. package/chunks/{chunk-M2PY7CNK.js → chunk-V2U6FOJB.js} +2 -2
  130. package/chunks/{chunk-7SUQZ7QH.js → chunk-V3NMFQD2.js} +2 -2
  131. package/chunks/{chunk-6XZERB6P.js → chunk-VPZMLGD3.js} +3 -3
  132. package/chunks/{chunk-UNCIELQJ.js → chunk-VRQD5D7R.js} +1 -1
  133. package/chunks/{chunk-YTYPRVIZ.js → chunk-VUTOV2HG.js} +2 -2
  134. package/chunks/{chunk-7LZ7DK4D.js → chunk-VYDQD5J4.js} +1 -1
  135. package/chunks/{chunk-XCGIMOLN.js → chunk-WCCLLK7X.js} +14 -1
  136. package/chunks/{chunk-JEMR2FTD.js → chunk-WIHSDI6U.js} +4 -4
  137. package/chunks/{chunk-VJNBRRZG.js → chunk-WZMH7II3.js} +1 -1
  138. package/chunks/{chunk-XWUQ4IH5.js → chunk-XJ6IMYUS.js} +7 -7
  139. package/chunks/{chunk-3XZYK76R.js → chunk-XL6GYJL2.js} +1 -1
  140. package/chunks/{chunk-KNXA5XXK.js → chunk-XUBM2A4F.js} +7 -7
  141. package/chunks/{chunk-ENEEQMGM.js → chunk-XY7DGTIC.js} +1 -1
  142. package/chunks/{chunk-SSAOTDK7.js → chunk-Y2EOB7WZ.js} +1 -1
  143. package/chunks/{chunk-VQZXRLEX.js → chunk-Y2HK3ELT.js} +3 -3
  144. package/chunks/{chunk-FDWH6CBK.js → chunk-Y5C24BUY.js} +5 -5
  145. package/chunks/{chunk-5HBFERG5.js → chunk-YI5G32RU.js} +3 -3
  146. package/chunks/{chunk-MPBRV3UU.js → chunk-YMB77M76.js} +15 -0
  147. package/chunks/{chunk-KNQZXSLW.js → chunk-YY23TR4M.js} +23 -9
  148. package/chunks/{chunk-4ETA3KRC.js → chunk-ZA2JN5IZ.js} +3 -3
  149. package/chunks/{chunk-IX7CFQGA.js → chunk-ZPZANKVP.js} +3 -3
  150. package/chunks/{chunk-XTH2OMDS.js → chunk-ZRT36RSF.js} +1 -1
  151. package/chunks/{chunk-M2NMFAFR.js → chunk-ZZ7RUTJ4.js} +1 -1
  152. package/chunks/{computer-use-S4JEU5P7.js → computer-use-J5VUY257.js} +38 -38
  153. package/chunks/{config-utils-TXVKR27S.js → config-utils-7JZQN6L2.js} +4 -4
  154. package/chunks/{contextCommand-2H5OH2HW.js → contextCommand-RCTGC36R.js} +40 -40
  155. package/chunks/{core-runtime-IAQ4DD4Y.js → core-runtime-REBZ5ZYE.js} +38 -38
  156. package/chunks/{create-sub-session-Y4WYDZGC.js → create-sub-session-23ULO5PO.js} +2 -2
  157. package/chunks/{create-sub-session-EKHKXJAA.js → create-sub-session-TEEUROAZ.js} +38 -38
  158. package/chunks/{cron-create-ZOVA3CC2.js → cron-create-5WUTNKNF.js} +4 -4
  159. package/chunks/{cron-delete-7Z3H4LJY.js → cron-delete-JEQ27YPS.js} +4 -4
  160. package/chunks/{cron-list-UHGX3IQG.js → cron-list-IXGCA7UR.js} +4 -4
  161. package/chunks/{daemon-PXIC4ZDK.js → daemon-UBVOQMWY.js} +2 -1
  162. package/chunks/{daemon-status-provider-LPYR2GXY.js → daemon-status-provider-SV7KRLJ4.js} +49 -49
  163. package/chunks/{daemon-trust-policy-7JOBVFH3.js → daemon-trust-policy-LFUJ4NGF.js} +44 -44
  164. package/chunks/{daemon-trust-policy-monitor-OU3NRHAR.js → daemon-trust-policy-monitor-BQZ77NDD.js} +44 -44
  165. package/chunks/{deferred-core-runtime-SFT3KI2C.js → deferred-core-runtime-F4XOQJQL.js} +38 -38
  166. package/chunks/{dispatch-B53LNEO4.js → dispatch-FW7DX2CR.js} +7 -1
  167. package/chunks/{display-image-ZE3GZNIK.js → display-image-CAD7RAUM.js} +4 -4
  168. package/chunks/{dist-BNWP6IZL.js → dist-362MN6CP.js} +2 -2
  169. package/chunks/{dist-EFJILGIS.js → dist-5VDE7U3A.js} +1 -1
  170. package/chunks/{dist-AVUYBK7L.js → dist-6RK4U6VU.js} +1 -1
  171. package/chunks/{dist-KTYDJNYM.js → dist-B3ODKYEB.js} +1 -1
  172. package/chunks/{dist-NPS52B2V.js → dist-CCUH2Z4C.js} +1 -1
  173. package/chunks/{dist-BW2LDPV3.js → dist-DANKRAB3.js} +1 -1
  174. package/chunks/{dist-PKSRQAR2.js → dist-EZHCZSW6.js} +1 -1
  175. package/chunks/{dist-ZWDH5HLS.js → dist-M3XMEIP2.js} +1 -1
  176. package/chunks/{earlyInputCapture-27RPWE2D.js → earlyInputCapture-JAJXDT2N.js} +39 -39
  177. package/chunks/{edit-WXVZ7FHS.js → edit-OXBMFY5B.js} +38 -38
  178. package/chunks/{enter-worktree-TYMVXFLA.js → enter-worktree-XS4JX4PO.js} +38 -38
  179. package/chunks/{enterPlanMode-FT4MRU5N.js → enterPlanMode-J6PDPFFT.js} +38 -38
  180. package/chunks/{environment-Z6OMA34I.js → environment-BQW6FAZL.js} +40 -40
  181. package/chunks/{errors-YMXK2GG3.js → errors-TMSN7AZN.js} +40 -40
  182. package/chunks/{exit-worktree-ODZUQLGJ.js → exit-worktree-2RIE6DAO.js} +38 -38
  183. package/chunks/{exitPlanMode-MBPAPBBV.js → exitPlanMode-QQL27HU4.js} +38 -38
  184. package/chunks/{fast-path-ZU5T6XSN.js → fast-path-TSGUVE5K.js} +4 -4
  185. package/chunks/{gemini-OZK6AIMC.js → gemini-RLTFENFV.js} +86 -86
  186. package/chunks/{geminiContentGenerator-MC6ZKWZG.js → geminiContentGenerator-B6W6PSO7.js} +6 -6
  187. package/chunks/{glob-KJ4A4ZOM.js → glob-JKVAHWL5.js} +38 -38
  188. package/chunks/{goal-tools-JDK2SNMV.js → goal-tools-LQFO4BRY.js} +4 -4
  189. package/chunks/{grep-QWBLG564.js → grep-6CN23ZPS.js} +38 -38
  190. package/chunks/{handleAutoUpdate-M3ACKDKF.js → handleAutoUpdate-Y6BUNMBG.js} +42 -42
  191. package/chunks/{i18n-FPW7XZL5.js → i18n-Y5PM6L5V.js} +39 -39
  192. package/chunks/{image-gen-OTFC2S7L.js → image-gen-DC2IQZ73.js} +10 -10
  193. package/chunks/{initializer-5HKUXXBT.js → initializer-OYKKBNHO.js} +45 -45
  194. package/chunks/{installationInfo-4OA6UW7V.js → installationInfo-63AFHLWA.js} +39 -39
  195. package/chunks/{keychain-token-storage-JTWUYFU7.js → keychain-token-storage-GU75J2T2.js} +2 -2
  196. package/chunks/{list-3TKZ264A.js → list-KA63R3R6.js} +47 -47
  197. package/chunks/{list-agents-4GQ2XNEU.js → list-agents-5PNMK2AM.js} +2 -2
  198. package/chunks/{loadedSettingsAdapter-IRUANLS2.js → loadedSettingsAdapter-IGBJN7C5.js} +44 -44
  199. package/chunks/{loggingContentGenerator-D4URLH2A.js → loggingContentGenerator-Z3NADCTQ.js} +115 -93
  200. package/chunks/{loop-wakeup-HOQI3K5D.js → loop-wakeup-OV65FEGR.js} +5 -5
  201. package/chunks/{ls-FSHISLLA.js → ls-RPRSX26R.js} +4 -4
  202. package/chunks/{lsp-APQJ5ZEZ.js → lsp-IWTJWFLT.js} +2 -2
  203. package/chunks/{managed-npm-update-2O7XSAWJ.js → managed-npm-update-HA262PFM.js} +41 -41
  204. package/chunks/{mcp-AFVHCHKT.js → mcp-T5ZUOKT3.js} +44 -44
  205. package/chunks/{monitor-PY4WDSX3.js → monitor-SLGY7CYB.js} +38 -38
  206. package/chunks/nonInteractiveCli-R5PK5B5G.js +166 -0
  207. package/chunks/{notebook-edit-GEPL33NO.js → notebook-edit-STSSB5KQ.js} +38 -38
  208. package/chunks/{openaiContentGenerator-ACYSXQ6R.js → openaiContentGenerator-OQED57JE.js} +24 -24
  209. package/chunks/{opentui-entry-SBAOWW7M.js → opentui-entry-UTJ6MHDI.js} +116 -97
  210. package/chunks/{pidfile-SUNYCAA4.js → pidfile-GES3MIHH.js} +39 -39
  211. package/chunks/{processUtils-F7LP7YUV.js → processUtils-FU6VMUOL.js} +2 -2
  212. package/chunks/{qwenContentGenerator-BB6IPELF.js → qwenContentGenerator-HWJSEGUL.js} +43 -43
  213. package/chunks/{qwenOAuth2-OU3WGDOI.js → qwenOAuth2-PAIR7XEW.js} +9 -9
  214. package/chunks/{read-file-GORBXJTS.js → read-file-IYEBTQT5.js} +12 -12
  215. package/chunks/{read-mcp-resource-TJSJRH4F.js → read-mcp-resource-THCSZHXO.js} +2 -2
  216. package/chunks/{read-package-up-TCM6I7S2.js → read-package-up-K6RKTL5D.js} +1 -1
  217. package/chunks/{record-artifact-FXF5LHPE.js → record-artifact-76YYQA5F.js} +3 -3
  218. package/chunks/{resumeHistoryUtils-FOAJJJWK.js → resumeHistoryUtils-WP446RP5.js} +44 -44
  219. package/chunks/{ripGrep-RNLIZGCY.js → ripGrep-VV2CRCL2.js} +38 -38
  220. package/chunks/{run-qwen-serve-GVMMX3IU.js → run-qwen-serve-AHQCTALV.js} +160 -71
  221. package/chunks/{runtime-RNBZ5FDD.js → runtime-AUUZGDK6.js} +49 -49
  222. package/chunks/{scheduler-NTRFSPIP.js → scheduler-Y4UPEURR.js} +40 -40
  223. package/chunks/{sdk-exporters-http-2VPMAPFI.js → sdk-exporters-http-A7XLKZO7.js} +11 -7
  224. package/chunks/{sdk-impl-5W3JUCWF.js → sdk-impl-XO4UF6PR.js} +11 -8
  225. package/chunks/{send-message-RBYLV5NY.js → send-message-P5SLP57G.js} +6 -6
  226. package/chunks/{serve-H3PGA26U.js → serve-WI3SE4MY.js} +47 -47
  227. package/chunks/{server-SUXD2F3C.js → server-G6JU6UWL.js} +264 -159
  228. package/chunks/{session-MTFVUWWM.js → session-2AO2UACB.js} +85 -85
  229. package/chunks/{settings-GUJ3TN2J.js → settings-3HRWSH66.js} +43 -43
  230. package/chunks/{shell-C2UP5FF2.js → shell-AR7XFLHA.js} +38 -38
  231. package/chunks/{skill-4XCNK55E.js → skill-K6NOUUYM.js} +16 -16
  232. package/chunks/{skill-settings-Y2BU27XM.js → skill-settings-IOXQYS6X.js} +43 -43
  233. package/chunks/{spawnChannel-UUUUK734.js → spawnChannel-V6P6HF4V.js} +40 -40
  234. package/chunks/{standalone-update-MJ722XZ4.js → standalone-update-K5G3L2OJ.js} +40 -40
  235. package/chunks/{startInteractiveUI-TCPIPNGN.js → startInteractiveUI-TRRP52QX.js} +125 -115
  236. package/chunks/{syntheticOutput-D3Z64LJC.js → syntheticOutput-SEW4NA47.js} +3 -3
  237. package/chunks/{task-create-URFZ5EUX.js → task-create-247EAVF7.js} +10 -10
  238. package/chunks/{task-list-6JDFMPUW.js → task-list-ZJN4QHLK.js} +5 -5
  239. package/chunks/{task-stop-HHUGCD25.js → task-stop-MAYQJ42I.js} +2 -2
  240. package/chunks/{task-update-DVV6CUGI.js → task-update-SU5TMZGG.js} +10 -10
  241. package/chunks/{team-create-WZWH2NJI.js → team-create-IEEEBLE2.js} +38 -38
  242. package/chunks/{team-delete-PZGGBQLM.js → team-delete-3XVRPQBP.js} +5 -5
  243. package/chunks/{team-plan-approval-SUZQJCWJ.js → team-plan-approval-SJGNS5JL.js} +38 -38
  244. package/chunks/{terminal-image-renderer-BCUN3Z3W.js → terminal-image-renderer-C4RQMC67.js} +40 -40
  245. package/chunks/{theme-manager-UGMFDREN.js → theme-manager-IKZQJQ6C.js} +39 -39
  246. package/chunks/{todoWrite-WINAZSZI.js → todoWrite-IE2YTCK7.js} +4 -4
  247. package/chunks/{tool-search-B6F3MPUZ.js → tool-search-4UVNFYWU.js} +16 -16
  248. package/chunks/{total-session-admission-MQLBJ5WL.js → total-session-admission-DIN6FTZP.js} +44 -44
  249. package/chunks/{trustedFolders-2XST7U5C.js → trustedFolders-IAHOLV6A.js} +39 -39
  250. package/chunks/{update-relaunch-OVC7YNGD.js → update-relaunch-5QSJ5CWP.js} +5 -5
  251. package/chunks/{updateCheck-YAKM36WQ.js → updateCheck-N4RT7HOZ.js} +44 -44
  252. package/chunks/{useAutoAcceptIndicator-RF6FVX3S.js → useAutoAcceptIndicator-25T26VZS.js} +46 -46
  253. package/chunks/{validateNonInterActiveAuth-IPPXFNQH.js → validateNonInterActiveAuth-MCTVPLFE.js} +81 -81
  254. package/chunks/{version-4IDFEXOU.js → version-6PLZ7PCV.js} +2 -2
  255. package/chunks/{web-fetch-NUOLHXPN.js → web-fetch-5ANX6FSM.js} +16 -16
  256. package/chunks/{web-search-LVOOV4XZ.js → web-search-KQJWWRHW.js} +9 -9
  257. package/chunks/{workflow-JSTYTG3K.js → workflow-C57ZKFUF.js} +111 -46
  258. package/chunks/{workspace-providers-status-U4EYXA4K.js → workspace-providers-status-3QAE4G4Y.js} +47 -47
  259. package/chunks/{workspace-registration-store-OG66U3CB.js → workspace-registration-store-Q3J5LV6T.js} +1 -1
  260. package/chunks/{workspace-registry-WSHWQRQQ.js → workspace-registry-DSJ5NAII.js} +44 -44
  261. package/chunks/{workspace-service-QZXQHX2F.js → workspace-service-QW5LH7FA.js} +49 -49
  262. package/chunks/{workspace-skills-status-VRBHEX5O.js → workspace-skills-status-N34ALJPZ.js} +45 -45
  263. package/chunks/{workspace-trust-reconciler-FCRIUIOF.js → workspace-trust-reconciler-YTOL7QEV.js} +50 -50
  264. package/chunks/{write-file-PYL3JCCD.js → write-file-MSFRVUZB.js} +38 -38
  265. package/chunks/{zoom-image-RS6MU26F.js → zoom-image-4TQA5GHG.js} +12 -12
  266. package/cli.js +13 -13
  267. package/package.json +4 -4
  268. package/web-shell/assets/{arc-CgGUyHWd.js → arc-lZ04kynw.js} +1 -1
  269. package/web-shell/assets/{architectureDiagram-3BPJPVTR-BR0Qv-1Y.js → architectureDiagram-3BPJPVTR-B1wZVhzD.js} +1 -1
  270. package/web-shell/assets/{blockDiagram-GPEHLZMM-DIoaceaI.js → blockDiagram-GPEHLZMM-CO0e0yJt.js} +1 -1
  271. package/web-shell/assets/{c4Diagram-AAUBKEIU-Bc5k6BbI.js → c4Diagram-AAUBKEIU-Dfpo6Qie.js} +1 -1
  272. package/web-shell/assets/channel-BxvRq3pV.js +1 -0
  273. package/web-shell/assets/{chunk-2J33WTMH-DtPEz2WX.js → chunk-2J33WTMH-BvxArftT.js} +1 -1
  274. package/web-shell/assets/{chunk-4BX2VUAB-Dydo6ydE.js → chunk-4BX2VUAB-BS2XXjGY.js} +1 -1
  275. package/web-shell/assets/{chunk-55IACEB6-DD9_VWXm.js → chunk-55IACEB6-CYL6h3Ph.js} +1 -1
  276. package/web-shell/assets/{chunk-727SXJPM-DVI2m59k.js → chunk-727SXJPM-C-cWPX30.js} +1 -1
  277. package/web-shell/assets/{chunk-AQP2D5EJ-luatmaTN.js → chunk-AQP2D5EJ-CJLxNbVV.js} +1 -1
  278. package/web-shell/assets/{chunk-FMBD7UC4-Duy8NTIi.js → chunk-FMBD7UC4-DwfzKywA.js} +1 -1
  279. package/web-shell/assets/{chunk-ND2GUHAM-CrL1yhms.js → chunk-ND2GUHAM-BI5raYHQ.js} +1 -1
  280. package/web-shell/assets/{chunk-QZHKN3VN-C7BX6bu1.js → chunk-QZHKN3VN-_GkNI90J.js} +1 -1
  281. package/web-shell/assets/classDiagram-4FO5ZUOK-tL8nAxYf.js +1 -0
  282. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-tL8nAxYf.js +1 -0
  283. package/web-shell/assets/{cose-bilkent-S5V4N54A-BTzs7mIi.js → cose-bilkent-S5V4N54A-BAVLNxh9.js} +1 -1
  284. package/web-shell/assets/{dagre-BM42HDAG-3VTUmWts.js → dagre-BM42HDAG-BD4XNLqp.js} +1 -1
  285. package/web-shell/assets/{diagram-2AECGRRQ-Ehdp75GN.js → diagram-2AECGRRQ-WO567p8w.js} +1 -1
  286. package/web-shell/assets/{diagram-5GNKFQAL-B3wu3teE.js → diagram-5GNKFQAL-mAk23VWO.js} +1 -1
  287. package/web-shell/assets/{diagram-KO2AKTUF-DjgTSf2S.js → diagram-KO2AKTUF-YQEeHKze.js} +1 -1
  288. package/web-shell/assets/{diagram-LMA3HP47-Br9mwjY3.js → diagram-LMA3HP47-CMVjxAjv.js} +1 -1
  289. package/web-shell/assets/{diagram-OG6HWLK6-D4xz5M-z.js → diagram-OG6HWLK6-42hPvbM-.js} +1 -1
  290. package/web-shell/assets/{erDiagram-TEJ5UH35-CXayWlG_.js → erDiagram-TEJ5UH35-CXU_cPfu.js} +1 -1
  291. package/web-shell/assets/{flowDiagram-I6XJVG4X-CLonjQTi.js → flowDiagram-I6XJVG4X-D-3TdhMT.js} +1 -1
  292. package/web-shell/assets/{ganttDiagram-6RSMTGT7-BTySFT-1.js → ganttDiagram-6RSMTGT7-CsgkXolz.js} +1 -1
  293. package/web-shell/assets/{gitGraphDiagram-PVQCEYII--2WcUjOe.js → gitGraphDiagram-PVQCEYII-B6Q3PBLD.js} +1 -1
  294. package/web-shell/assets/{index-DPJHkFOG.js → index-BFrkGj2B.js} +1 -1
  295. package/web-shell/assets/index-BgjULKyF.css +5 -0
  296. package/web-shell/assets/index-CxXlPYfl.js +1789 -0
  297. package/web-shell/assets/{infoDiagram-5YYISTIA-9vpgAf1m.js → infoDiagram-5YYISTIA-jiAfSXp8.js} +1 -1
  298. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-DcRpHnAW.js → ishikawaDiagram-YF4QCWOH-BWif5KeJ.js} +1 -1
  299. package/web-shell/assets/{journeyDiagram-JHISSGLW-C2TKorRm.js → journeyDiagram-JHISSGLW-B-GAZthS.js} +1 -1
  300. package/web-shell/assets/{kanban-definition-UN3LZRKU-DdsFwB8b.js → kanban-definition-UN3LZRKU-9TEuATdL.js} +1 -1
  301. package/web-shell/assets/{linear-7PjRvJrf.js → linear-dy_QPfyE.js} +1 -1
  302. package/web-shell/assets/{mermaid.core-raDXa11C.js → mermaid.core-DB2uLAnq.js} +5 -5
  303. package/web-shell/assets/{mindmap-definition-RKZ34NQL-DLHc-PRN.js → mindmap-definition-RKZ34NQL-ey_dyxi-.js} +1 -1
  304. package/web-shell/assets/{pieDiagram-4H26LBE5-BftYpeTW.js → pieDiagram-4H26LBE5-_6BuMdDj.js} +1 -1
  305. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-O-6ygOYn.js → quadrantDiagram-W4KKPZXB-B2rM19W2.js} +1 -1
  306. package/web-shell/assets/{requirementDiagram-4Y6WPE33-BmZWVufJ.js → requirementDiagram-4Y6WPE33-DWj8b7vW.js} +1 -1
  307. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-2x5beiWt.js → sankeyDiagram-5OEKKPKP-D5dtYh0N.js} +1 -1
  308. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-BH8uKokQ.js → sequenceDiagram-3UESZ5HK-DVkdn_qW.js} +1 -1
  309. package/web-shell/assets/{stateDiagram-AJRCARHV-Dq1MFgX_.js → stateDiagram-AJRCARHV-DgwD_fi6.js} +1 -1
  310. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BWGkVGVB.js +1 -0
  311. package/web-shell/assets/{timeline-definition-PNZ67QCA-Cl2WKbv9.js → timeline-definition-PNZ67QCA-vNr_1UNX.js} +1 -1
  312. package/web-shell/assets/{vennDiagram-CIIHVFJN-BqoRo_Q-.js → vennDiagram-CIIHVFJN-ChFcGAcu.js} +1 -1
  313. package/web-shell/assets/{wardley-L42UT6IY-BTxp-Yot.js → wardley-L42UT6IY-C8PXoSWk.js} +1 -1
  314. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-DFXVCSH2.js → wardleyDiagram-YWT4CUSO-C2nqOV6i.js} +1 -1
  315. package/web-shell/assets/{xychartDiagram-2RQKCTM6-qQhWx0aE.js → xychartDiagram-2RQKCTM6-BntaqhSB.js} +1 -1
  316. package/web-shell/index.html +2 -2
  317. package/chunks/nonInteractiveCli-ZHW6F76F.js +0 -166
  318. package/web-shell/assets/channel-D2b9IYpS.js +0 -1
  319. package/web-shell/assets/classDiagram-4FO5ZUOK-DHatTCmD.js +0 -1
  320. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-DHatTCmD.js +0 -1
  321. package/web-shell/assets/index-CIFO52Wx.css +0 -5
  322. package/web-shell/assets/index-bhq3CUUF.js +0 -1789
  323. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-spuAYji6.js +0 -1
@@ -5,23 +5,28 @@ import {
5
5
  } from "./chunk-4NFY2S7N.js";
6
6
  import {
7
7
  formatHistoryGapNotice
8
- } from "./chunk-U6PTKAOW.js";
8
+ } from "./chunk-FNVF5RR4.js";
9
9
  import {
10
10
  loadUndici
11
11
  } from "./chunk-3Z43GZUQ.js";
12
12
  import {
13
+ projectGoalStateToLegacy
14
+ } from "./chunk-GHOUZ5X4.js";
15
+ import {
16
+ parseGoalSnapshotV2,
17
+ parseGoalStateCause,
13
18
  projectUserTranscriptForDisplay
14
- } from "./chunk-SAQHDAUJ.js";
19
+ } from "./chunk-B66LYK4B.js";
15
20
  import {
16
21
  formatVisionBridgeNoticeDisplay,
17
22
  isVisionBridgeNoticeDisplay
18
- } from "./chunk-HB6QW4LM.js";
23
+ } from "./chunk-UAAWNTOC.js";
19
24
  import {
20
25
  ToolNames
21
- } from "./chunk-XTH2OMDS.js";
26
+ } from "./chunk-ZRT36RSF.js";
22
27
  import {
23
28
  createDebugLogger
24
- } from "./chunk-MPBRV3UU.js";
29
+ } from "./chunk-YMB77M76.js";
25
30
  import {
26
31
  writeStderrLine,
27
32
  writeStderrLineSafe
@@ -33,2265 +38,2295 @@ import {
33
38
  __name
34
39
  } from "./chunk-J2S4EL5Y.js";
35
40
 
36
- // packages/cli/src/services/setup-github.ts
41
+ // packages/cli/src/acp-integration/session/history-replayer.ts
37
42
  init_esbuild_shims();
38
- import { promises as fsp } from "node:fs";
39
- import * as path from "node:path";
40
43
 
41
- // packages/cli/src/utils/gitUtils.ts
44
+ // packages/acp-bridge/src/transcript-replay.ts
42
45
  init_esbuild_shims();
43
- import * as childProcess from "node:child_process";
44
- var debugLogger = createDebugLogger("GIT");
45
- async function runGit(args, opts = {}) {
46
- return await new Promise((resolve2, reject) => {
47
- childProcess.execFile(
48
- "git",
49
- args,
50
- {
51
- encoding: "utf-8",
52
- ...opts.cwd ? { cwd: opts.cwd } : {}
53
- },
54
- (err, stdout) => {
55
- if (err) {
56
- reject(err);
57
- return;
58
- }
59
- resolve2(String(stdout ?? "").trim());
60
- }
61
- );
62
- });
46
+
47
+ // packages/core/dist/src/goals/goal-wire.js
48
+ init_esbuild_shims();
49
+
50
+ // packages/core/dist/src/goals/goal-protocol.js
51
+ init_esbuild_shims();
52
+ var GOAL_STATE_VERSION = 2;
53
+ var GOAL_CHECKPOINT_CLAIM_LIMIT = 32;
54
+ var GOAL_CHECKPOINT_CLAIM_MAX_CHARACTERS = 2e3;
55
+ var GOAL_CHECKPOINT_CLAIM_MAX_BYTES = 16e3;
56
+ var GOAL_CHECKPOINT_SOURCE_REFERENCE_LIMIT = 32;
57
+ function isGoalEvidenceProofKind(value) {
58
+ return value === "user_input" || value === "delivered_output" || value === "external_fact";
63
59
  }
64
- __name(runGit, "runGit");
65
- var isGitHubRepositoryAsync = /* @__PURE__ */ __name(async (opts = {}) => {
66
- try {
67
- const remotes = await runGit(["remote", "-v"], opts);
68
- return remotes.split("\n").some((line) => {
69
- const remoteUrl = line.trim().split(/\s+/)[1];
70
- return remoteUrl ? isGitHubRemoteUrl(remoteUrl) : false;
71
- });
72
- } catch (_error) {
73
- debugLogger.debug(`Failed to get git remote:`, _error);
74
- return false;
75
- }
76
- }, "isGitHubRepositoryAsync");
77
- function isGitHubRemoteUrl(remoteUrl) {
78
- if (remoteUrl.startsWith("git@github.com:")) {
79
- return true;
80
- }
81
- if (remoteUrl.startsWith("git@")) {
82
- return false;
60
+ __name(isGoalEvidenceProofKind, "isGoalEvidenceProofKind");
61
+
62
+ // packages/core/dist/src/goals/goal-reducer.js
63
+ init_esbuild_shims();
64
+ var MAX_BLOCKED_AUDIT_COUNT = 3;
65
+ function parseGoalStateRecordPayloadV2(value) {
66
+ if (!isRecord(value) || !hasOnlyKeys(value, [
67
+ "v",
68
+ "cause",
69
+ "snapshot",
70
+ "checkpointPending",
71
+ "blockedAudit"
72
+ ]) || value["v"] !== GOAL_STATE_VERSION || !isGoalStateCause(value["cause"]) || !isCheckpointPending(value["checkpointPending"]) || !isBlockedAudit(value["blockedAudit"])) {
73
+ return void 0;
83
74
  }
84
- try {
85
- return new URL(remoteUrl).hostname === "github.com";
86
- } catch {
87
- return false;
75
+ const parsedSnapshot = parseGoalSnapshotV22(value["snapshot"]);
76
+ if (parsedSnapshot?.activity !== "idle")
77
+ return void 0;
78
+ const checkpointPending = value["checkpointPending"];
79
+ if (checkpointPending && (parsedSnapshot.goal?.status !== "active" || checkpointPending.permit.goalId !== parsedSnapshot.goal.goalId || checkpointPending.permit.revision !== parsedSnapshot.goal.revision || checkpointPending.recordUuid === parsedSnapshot.goal.evidenceCursor.recordId || value["cause"] !== "turn_finished" && value["cause"] !== "verifier_reject")) {
80
+ return void 0;
88
81
  }
82
+ return {
83
+ v: GOAL_STATE_VERSION,
84
+ cause: value["cause"],
85
+ snapshot: parsedSnapshot,
86
+ ...checkpointPending ? { checkpointPending: structuredClone(checkpointPending) } : {},
87
+ ...value["blockedAudit"] ? { blockedAudit: structuredClone(value["blockedAudit"]) } : {}
88
+ };
89
89
  }
90
- __name(isGitHubRemoteUrl, "isGitHubRemoteUrl");
91
- var getGitRepoRootAsync = /* @__PURE__ */ __name(async (opts = {}) => {
92
- const gitRepoRoot = await runGit(["rev-parse", "--show-toplevel"], opts);
93
- if (!gitRepoRoot) {
94
- throw new Error(`Git repo returned empty value`);
90
+ __name(parseGoalStateRecordPayloadV2, "parseGoalStateRecordPayloadV2");
91
+ function parseGoalSnapshotV22(value) {
92
+ if (!isRecord(value) || !hasOnlyKeys(value, ["v", "goal", "activity"]) || value["v"] !== GOAL_STATE_VERSION || !isGoalActivity(value["activity"])) {
93
+ return void 0;
95
94
  }
96
- return gitRepoRoot;
97
- }, "getGitRepoRootAsync");
98
- var getLatestGitHubRelease = /* @__PURE__ */ __name(async (proxy) => {
99
- try {
100
- const controller = new AbortController();
101
- const endpoint = `https://api.github.com/repos/QwenLM/qwen-code-action/releases/latest`;
102
- const dispatcher = proxy ? new (await loadUndici()).ProxyAgent(proxy) : void 0;
103
- const response = await fetch(endpoint, {
104
- method: "GET",
105
- headers: {
106
- Accept: "application/vnd.github+json",
107
- "Content-Type": "application/json",
108
- "X-GitHub-Api-Version": "2022-11-28"
109
- },
110
- dispatcher,
111
- signal: AbortSignal.any([AbortSignal.timeout(3e4), controller.signal])
112
- });
113
- if (!response.ok) {
114
- throw new Error(
115
- `Invalid response code: ${response.status} - ${response.statusText}`
116
- );
117
- }
118
- const releaseTag = (await response.json()).tag_name;
119
- if (!releaseTag) {
120
- throw new Error(`Response did not include tag_name field`);
121
- }
122
- return releaseTag;
123
- } catch (_error) {
124
- debugLogger.debug(
125
- `Failed to determine latest qwen-code-action release:`,
126
- _error
127
- );
128
- throw new Error(
129
- `Unable to determine the latest qwen-code-action release on GitHub.`
130
- );
95
+ if (value["goal"] === null) {
96
+ return {
97
+ v: GOAL_STATE_VERSION,
98
+ goal: null,
99
+ activity: value["activity"]
100
+ };
131
101
  }
132
- }, "getLatestGitHubRelease");
133
- async function getGitHubRepoInfoAsync(opts = {}) {
134
- return parseGitHubRepoInfo(
135
- await runGit(["remote", "get-url", "origin"], opts)
136
- );
102
+ const goal = parseGoalRecord(value["goal"]);
103
+ return goal ? { v: GOAL_STATE_VERSION, goal, activity: value["activity"] } : void 0;
137
104
  }
138
- __name(getGitHubRepoInfoAsync, "getGitHubRepoInfoAsync");
139
- function parseGitHubRepoInfo(remoteUrl) {
140
- let urlToParse = remoteUrl;
141
- if (remoteUrl.startsWith("git@github.com:")) {
142
- urlToParse = remoteUrl.replace("git@github.com:", "");
143
- } else if (remoteUrl.startsWith("git@")) {
144
- throw new Error(
145
- `Owner & repo could not be extracted from remote URL: ${remoteUrl}`
146
- );
105
+ __name(parseGoalSnapshotV22, "parseGoalSnapshotV2");
106
+ function parseGoalStateCause2(value) {
107
+ return isGoalStateCause(value) ? value : void 0;
108
+ }
109
+ __name(parseGoalStateCause2, "parseGoalStateCause");
110
+ function copyCursor(cursor) {
111
+ return { recordId: cursor.recordId };
112
+ }
113
+ __name(copyCursor, "copyCursor");
114
+ function parseGoalRecord(value) {
115
+ if (!isRecord(value) || !hasOnlyKeys(value, [
116
+ "goalId",
117
+ "revision",
118
+ "objective",
119
+ "status",
120
+ "evidenceCursor",
121
+ "turnCount",
122
+ "activeTimeMs",
123
+ "createdAt",
124
+ "updatedAt",
125
+ "evidenceCheckpoint",
126
+ "lastReason"
127
+ ]) || typeof value["goalId"] !== "string" || !value["goalId"] || !isNonNegativeInteger(value["revision"]) || value["revision"] === 0 || typeof value["objective"] !== "string" || !value["objective"].trim() || !isGoalStatus(value["status"]) || !isTranscriptCursor(value["evidenceCursor"]) || !isNonNegativeInteger(value["turnCount"]) || !isNonNegativeNumber(value["activeTimeMs"]) || !isFiniteNumber(value["createdAt"]) || !isFiniteNumber(value["updatedAt"]) || !isGoalEvidenceCheckpoint(value["evidenceCheckpoint"]) || value["lastReason"] !== void 0 && typeof value["lastReason"] !== "string") {
128
+ return void 0;
147
129
  }
148
- let parsedUrl;
149
- try {
150
- parsedUrl = new URL(urlToParse, "https://github.com");
151
- } catch {
152
- throw new Error(
153
- `Owner & repo could not be extracted from remote URL: ${remoteUrl}`
154
- );
130
+ if (value["evidenceCheckpoint"] && value["evidenceCursor"].recordId !== value["evidenceCheckpoint"].checkpointId) {
131
+ return void 0;
155
132
  }
156
- if (parsedUrl.hostname !== "github.com") {
157
- throw new Error(
158
- `Owner & repo could not be extracted from remote URL: ${remoteUrl}`
159
- );
133
+ return {
134
+ goalId: value["goalId"],
135
+ revision: value["revision"],
136
+ objective: value["objective"],
137
+ status: value["status"],
138
+ evidenceCursor: copyCursor(value["evidenceCursor"]),
139
+ turnCount: value["turnCount"],
140
+ activeTimeMs: value["activeTimeMs"],
141
+ createdAt: value["createdAt"],
142
+ updatedAt: value["updatedAt"],
143
+ ...value["evidenceCheckpoint"] === void 0 ? {} : {
144
+ evidenceCheckpoint: structuredClone(value["evidenceCheckpoint"])
145
+ },
146
+ ...value["lastReason"] === void 0 ? {} : { lastReason: value["lastReason"] }
147
+ };
148
+ }
149
+ __name(parseGoalRecord, "parseGoalRecord");
150
+ function isTranscriptCursor(value) {
151
+ return isRecord(value) && hasOnlyKeys(value, ["recordId"]) && (typeof value["recordId"] === "string" || value["recordId"] === null);
152
+ }
153
+ __name(isTranscriptCursor, "isTranscriptCursor");
154
+ function isGoalStatus(value) {
155
+ return value === "active" || value === "paused" || value === "blocked" || value === "usage_limited" || value === "complete";
156
+ }
157
+ __name(isGoalStatus, "isGoalStatus");
158
+ function isGoalActivity(value) {
159
+ return value === "idle" || value === "running" || value === "verifying";
160
+ }
161
+ __name(isGoalActivity, "isGoalActivity");
162
+ function isGoalStateCause(value) {
163
+ return value === "create" || value === "replace" || value === "edit" || value === "pause" || value === "resume" || value === "turn_finished" || value === "checkpoint" || value === "verifier_accept" || value === "verifier_reject" || value === "complete" || value === "blocked" || value === "usage_limited" || value === "clear" || value === "migrated";
164
+ }
165
+ __name(isGoalStateCause, "isGoalStateCause");
166
+ function isGoalEvidenceCheckpoint(value) {
167
+ if (value === void 0)
168
+ return true;
169
+ if (!isRecord(value) || !hasOnlyKeys(value, ["checkpointId", "createdAt", "claims"]) || typeof value["checkpointId"] !== "string" || value["checkpointId"].length === 0 || !isFiniteNumber(value["createdAt"]) || !Array.isArray(value["claims"]) || value["claims"].length === 0 || value["claims"].length > GOAL_CHECKPOINT_CLAIM_LIMIT) {
170
+ return false;
160
171
  }
161
- const parts = parsedUrl.pathname.split("/").filter((part) => part !== "");
162
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
163
- throw new Error(
164
- `Owner & repo could not be extracted from remote URL: ${remoteUrl}`
165
- );
172
+ let checkpointBytes = 0;
173
+ for (const [index, claim] of value["claims"].entries()) {
174
+ if (!isRecord(claim) || !hasOnlyKeys(claim, ["id", "proofKind", "claim", "sourceRefs"]) || claim["id"] !== `${value["checkpointId"]}:${index + 1}` || !isGoalEvidenceProofKind(claim["proofKind"]) || typeof claim["claim"] !== "string" || claim["claim"].trim().length === 0 || [...claim["claim"]].length > GOAL_CHECKPOINT_CLAIM_MAX_CHARACTERS || !Array.isArray(claim["sourceRefs"]) || claim["sourceRefs"].length === 0 || claim["sourceRefs"].length > GOAL_CHECKPOINT_SOURCE_REFERENCE_LIMIT || new Set(claim["sourceRefs"]).size !== claim["sourceRefs"].length || claim["sourceRefs"].some((reference) => typeof reference !== "string" || reference.length === 0)) {
175
+ return false;
176
+ }
177
+ checkpointBytes += new TextEncoder().encode(claim["claim"]).byteLength;
178
+ if (checkpointBytes > GOAL_CHECKPOINT_CLAIM_MAX_BYTES)
179
+ return false;
166
180
  }
167
- return { owner: parts[0], repo: parts[1].replace(/\.git$/, "") };
181
+ return true;
168
182
  }
169
- __name(parseGitHubRepoInfo, "parseGitHubRepoInfo");
170
-
171
- // packages/cli/src/services/setup-github.ts
172
- var debugLogger2 = createDebugLogger("SETUP_GITHUB");
173
- var GITHUB_WORKFLOW_PATHS = [
174
- "qwen-dispatch/qwen-dispatch.yml",
175
- "qwen-assistant/qwen-invoke.yml",
176
- "issue-triage/qwen-triage.yml",
177
- "issue-triage/qwen-scheduled-triage.yml",
178
- "pr-review/qwen-review.yml"
179
- ];
180
- var GITIGNORE_ENTRIES = [".qwen/", "gha-creds-*.json"];
181
- var MAX_WORKFLOW_DOWNLOAD_BYTES = 5 * 1024 * 1024;
182
- var SetupGithubError = class extends Error {
183
- static {
184
- __name(this, "SetupGithubError");
185
- }
186
- code;
187
- status;
188
- partial;
189
- partialResult;
190
- constructor(code, message, status, partialResult) {
191
- super(message);
192
- this.name = "SetupGithubError";
193
- this.code = code;
194
- this.status = status;
195
- this.partial = partialResult !== void 0;
196
- this.partialResult = partialResult;
183
+ __name(isGoalEvidenceCheckpoint, "isGoalEvidenceCheckpoint");
184
+ function isCheckpointPending(value) {
185
+ return value === void 0 || isRecord(value) && hasOnlyKeys(value, ["permit", "recordUuid"]) && isGoalTurnPermit(value["permit"]) && typeof value["recordUuid"] === "string" && value["recordUuid"].length > 0;
186
+ }
187
+ __name(isCheckpointPending, "isCheckpointPending");
188
+ function isGoalTurnPermit(value) {
189
+ return isRecord(value) && hasOnlyKeys(value, ["goalId", "revision", "turnId"]) && typeof value["goalId"] === "string" && value["goalId"].length > 0 && isNonNegativeInteger(value["revision"]) && value["revision"] > 0 && typeof value["turnId"] === "string" && value["turnId"].length > 0;
190
+ }
191
+ __name(isGoalTurnPermit, "isGoalTurnPermit");
192
+ function isBlockedAudit(value) {
193
+ return value === void 0 || isRecord(value) && hasOnlyKeys(value, ["fingerprint", "count", "turnIds"]) && typeof value["fingerprint"] === "string" && value["fingerprint"].length > 0 && isNonNegativeInteger(value["count"]) && value["count"] > 0 && value["count"] <= MAX_BLOCKED_AUDIT_COUNT && Array.isArray(value["turnIds"]) && value["turnIds"].length === value["count"] && value["turnIds"].every((turnId) => typeof turnId === "string" && turnId.length > 0);
194
+ }
195
+ __name(isBlockedAudit, "isBlockedAudit");
196
+ function isRecord(value) {
197
+ return typeof value === "object" && value !== null && !Array.isArray(value);
198
+ }
199
+ __name(isRecord, "isRecord");
200
+ function hasOnlyKeys(value, keys) {
201
+ return Object.keys(value).every((key) => keys.includes(key));
202
+ }
203
+ __name(hasOnlyKeys, "hasOnlyKeys");
204
+ function isNonNegativeInteger(value) {
205
+ return typeof value === "number" && Number.isInteger(value) && value >= 0;
206
+ }
207
+ __name(isNonNegativeInteger, "isNonNegativeInteger");
208
+ function isNonNegativeNumber(value) {
209
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
210
+ }
211
+ __name(isNonNegativeNumber, "isNonNegativeNumber");
212
+ function isFiniteNumber(value) {
213
+ return typeof value === "number" && Number.isFinite(value);
214
+ }
215
+ __name(isFiniteNumber, "isFiniteNumber");
216
+
217
+ // packages/core/dist/src/goals/goal-legacy-projection.js
218
+ init_esbuild_shims();
219
+ function projectGoalStateToLegacy2(payload, previousGoal = null) {
220
+ const snapshotGoal = payload.snapshot.goal;
221
+ const displayGoal = snapshotGoal ?? previousGoal;
222
+ const kind = legacyStatusKind(payload);
223
+ const goalStatus = {
224
+ type: "goal_status",
225
+ kind,
226
+ condition: displayGoal?.objective ?? "",
227
+ ...displayGoal ? { iterations: displayGoal.turnCount } : {},
228
+ ...displayGoal ? { setAt: displayGoal.createdAt } : {},
229
+ ...displayGoal ? { durationMs: displayGoal.activeTimeMs } : {},
230
+ ...displayGoal?.lastReason === void 0 ? {} : { lastReason: displayGoal.lastReason }
231
+ };
232
+ const terminalKind = kind === "achieved" || kind === "failed" || kind === "aborted" ? kind : void 0;
233
+ return {
234
+ activeGoal: snapshotGoal?.status === "active" ? {
235
+ condition: snapshotGoal.objective,
236
+ iterations: snapshotGoal.turnCount,
237
+ setAt: snapshotGoal.createdAt,
238
+ ...snapshotGoal.lastReason === void 0 ? {} : { lastReason: snapshotGoal.lastReason }
239
+ } : null,
240
+ goalStatus,
241
+ goalTerminal: terminalKind && displayGoal ? {
242
+ kind: terminalKind,
243
+ condition: displayGoal.objective,
244
+ iterations: displayGoal.turnCount,
245
+ durationMs: displayGoal.activeTimeMs,
246
+ ...displayGoal.lastReason === void 0 ? {} : { lastReason: displayGoal.lastReason }
247
+ } : null
248
+ };
249
+ }
250
+ __name(projectGoalStateToLegacy2, "projectGoalStateToLegacy");
251
+ function isGoalCheckpointBookkeepingTransition(previous, next) {
252
+ const previousGoal = previous?.goal;
253
+ const nextGoal = next.goal;
254
+ if (!previousGoal || !nextGoal)
255
+ return false;
256
+ return previousGoal.goalId === nextGoal.goalId && previousGoal.revision === nextGoal.revision && previousGoal.objective === nextGoal.objective && previousGoal.status === nextGoal.status && previousGoal.turnCount === nextGoal.turnCount && previousGoal.createdAt === nextGoal.createdAt && previousGoal.lastReason === nextGoal.lastReason;
257
+ }
258
+ __name(isGoalCheckpointBookkeepingTransition, "isGoalCheckpointBookkeepingTransition");
259
+ function isGoalCheckpointBookkeepingCause(cause, previousCause) {
260
+ if (cause === "checkpoint")
261
+ return true;
262
+ return cause === "verifier_reject" && (previousCause === "verifier_reject" || previousCause === "checkpoint");
263
+ }
264
+ __name(isGoalCheckpointBookkeepingCause, "isGoalCheckpointBookkeepingCause");
265
+ function isGoalCheckpointBookkeepingRecord(input) {
266
+ return isGoalCheckpointBookkeepingTransition(input.previous, input.next) && isGoalCheckpointBookkeepingCause(input.cause, input.previousCause);
267
+ }
268
+ __name(isGoalCheckpointBookkeepingRecord, "isGoalCheckpointBookkeepingRecord");
269
+ function legacyStatusKind(payload) {
270
+ switch (payload.cause) {
271
+ case "create":
272
+ case "replace":
273
+ case "edit":
274
+ case "resume":
275
+ return "set";
276
+ case "complete":
277
+ return "achieved";
278
+ case "clear":
279
+ return "cleared";
280
+ // A migrated goal is always persisted `paused` (`createMigratedGoalState`),
281
+ // and nothing drives a paused goal. Projecting it as `set` would re-assert
282
+ // "active" to every client that derives the live goal from the newest card,
283
+ // leaving a phantom running goal behind a resumed pre-v2 transcript.
284
+ case "migrated":
285
+ case "pause":
286
+ return "paused";
287
+ case "blocked":
288
+ case "usage_limited":
289
+ return "aborted";
290
+ case "turn_finished":
291
+ case "checkpoint":
292
+ case "verifier_accept":
293
+ case "verifier_reject":
294
+ return payload.snapshot.goal?.status === "complete" ? "achieved" : payload.snapshot.goal?.status === "blocked" || payload.snapshot.goal?.status === "usage_limited" ? "aborted" : "checking";
295
+ default:
296
+ return assertNever(payload.cause);
197
297
  }
198
- };
199
- function isWorkspaceGenerationClosed(error) {
200
- return Boolean(
201
- error && typeof error === "object" && "code" in error && error.code === "workspace_generation_closed"
202
- );
203
298
  }
204
- __name(isWorkspaceGenerationClosed, "isWorkspaceGenerationClosed");
205
- var nodeFileOps = {
206
- assertCanWrite() {
207
- },
208
- async ensureWorkflowDirectory(gitRepoRoot) {
209
- await fsp.mkdir(path.join(gitRepoRoot, ".github", "workflows"), {
210
- recursive: true
211
- });
212
- },
213
- async writeTextFile(gitRepoRoot, relativePath, content) {
214
- const target = path.join(gitRepoRoot, relativePath);
215
- await fsp.writeFile(target, content, { mode: 420 });
216
- return { sizeBytes: Buffer.byteLength(content, "utf8") };
217
- },
218
- async readTextFile(gitRepoRoot, relativePath) {
219
- try {
220
- return await fsp.readFile(path.join(gitRepoRoot, relativePath), "utf8");
221
- } catch (error) {
222
- if (error.code === "ENOENT") {
223
- return void 0;
299
+ __name(legacyStatusKind, "legacyStatusKind");
300
+ function assertNever(value) {
301
+ throw new Error(`Unsupported Goal state cause: ${String(value)}`);
302
+ }
303
+ __name(assertNever, "assertNever");
304
+
305
+ // packages/acp-bridge/src/transcript-replay.ts
306
+ var MISSING_TRANSCRIPT_TOOL_RESULT_MESSAGE = "Tool result missing from saved history; the previous run likely ended before this tool completed.";
307
+ var TRANSCRIPT_GOAL_STATUS_KINDS = /* @__PURE__ */ new Set([
308
+ "set",
309
+ "achieved",
310
+ "cleared",
311
+ "failed",
312
+ "aborted",
313
+ // A paused goal is not running, and dropping the card here is not neutral:
314
+ // the replay stream is what feeds the goal renderer, so the older `set` card
315
+ // stays newest and every surface keeps claiming autonomous work is under way.
316
+ // Kept in step with `GOAL_STATUS_KINDS`, which the daemon-side reader
317
+ // (`parseGoalStatusItem`) validates the same on-disk cards against.
318
+ "paused",
319
+ "checking"
320
+ ]);
321
+ function isObjectRecord(value) {
322
+ return typeof value === "object" && value !== null && !Array.isArray(value);
323
+ }
324
+ __name(isObjectRecord, "isObjectRecord");
325
+ function replaceTextPartsForDisplay(parts, displayText) {
326
+ const projected = [];
327
+ let replacedText = false;
328
+ for (const part of parts ?? []) {
329
+ if (isObjectRecord(part) && typeof part["text"] === "string") {
330
+ if (!replacedText && displayText.length > 0) {
331
+ projected.push({ text: displayText });
224
332
  }
225
- throw error;
333
+ replacedText = true;
334
+ } else {
335
+ projected.push(part);
226
336
  }
227
337
  }
228
- };
229
- async function setupGithub(options = {}) {
230
- const cwd = options.cwd ?? process.cwd();
231
- const fileOps = options.fileOps ?? nodeFileOps;
232
- if (!await isGitHubRepositoryAsync({ cwd })) {
233
- throw new SetupGithubError(
234
- "github_repository_not_found",
235
- "Unable to determine the GitHub repository. /setup-github must be run from a git repository.",
236
- 400
237
- );
238
- }
239
- let gitRepoRoot;
240
- try {
241
- gitRepoRoot = await getGitRepoRootAsync({ cwd });
242
- } catch (error) {
243
- debugLogger2.debug("Failed to get git repo root:", error);
244
- throw new SetupGithubError(
245
- "github_repository_not_found",
246
- "Unable to determine the GitHub repository. /setup-github must be run from a git repository.",
247
- 400
248
- );
249
- }
250
- if (options.workspaceRoot) {
251
- const [gitRootReal, workspaceReal] = await Promise.all([
252
- realpathOrResolve(gitRepoRoot),
253
- realpathOrResolve(options.workspaceRoot)
254
- ]);
255
- if (gitRootReal !== workspaceReal) {
256
- throw new SetupGithubError(
257
- "github_git_root_mismatch",
258
- "The Git repository root must match the daemon workspace root.",
259
- 400
260
- );
261
- }
338
+ if (!replacedText && displayText.length > 0) {
339
+ projected.push({ text: displayText });
262
340
  }
263
- fileOps.assertCanWrite?.();
264
- let releaseTag;
265
- try {
266
- releaseTag = await getLatestGitHubRelease(options.proxy);
267
- } catch (error) {
268
- writeStderrLine(
269
- `qwen setup-github: failed to determine latest qwen-code-action release: ${error instanceof Error ? error.message : String(error)}`
270
- );
271
- debugLogger2.debug(
272
- "Failed to determine latest qwen-code-action release:",
273
- error
274
- );
275
- throw new SetupGithubError(
276
- "github_release_lookup_failed",
277
- "Unable to determine the latest qwen-code-action release on GitHub.",
278
- 502
279
- );
341
+ return projected;
342
+ }
343
+ __name(replaceTextPartsForDisplay, "replaceTextPartsForDisplay");
344
+ function toTranscriptEpochMs(timestamp) {
345
+ if (typeof timestamp === "number") {
346
+ return Number.isFinite(timestamp) ? timestamp : void 0;
280
347
  }
281
- const readmeUrl = `https://github.com/QwenLM/qwen-code-action/blob/${releaseTag}/README.md#quick-start`;
282
- const secretsUrl = await resolveSecretsUrl(cwd);
283
- const downloads = await downloadWorkflows({
284
- releaseTag,
285
- proxy: options.proxy,
286
- abortSignal: options.abortSignal,
287
- fetchImpl: options.fetchImpl ?? fetch
288
- });
289
- const result = {
290
- kind: "github_setup",
291
- workspaceCwd: options.workspaceRoot ?? gitRepoRoot,
292
- gitRepoRoot,
293
- releaseTag,
294
- readmeUrl,
295
- ...secretsUrl ? { secretsUrl } : {},
296
- workflows: [],
297
- gitignore: { path: ".gitignore", status: "skipped" },
298
- warnings: []
348
+ if (typeof timestamp !== "string") return void 0;
349
+ const epochMs = new Date(timestamp).getTime();
350
+ return Number.isFinite(epochMs) ? epochMs : void 0;
351
+ }
352
+ __name(toTranscriptEpochMs, "toTranscriptEpochMs");
353
+ function buildUpdateMeta(options) {
354
+ const timestamp = toTranscriptEpochMs(options.timestamp);
355
+ const sourceRecordIds = dedupeStrings(options.sourceRecordIds ?? []);
356
+ const qwenTranscript = {
357
+ ...sourceRecordIds.length > 0 ? { sourceRecordIds } : {},
358
+ ...options.planToolCallId ? { planToolCallId: options.planToolCallId } : {}
299
359
  };
300
- result.gitignore = await updateGitignore(gitRepoRoot, fileOps);
301
- if (result.gitignore.status === "failed") {
302
- result.warnings.push("Failed to update .gitignore.");
303
- }
304
- try {
305
- await fileOps.ensureWorkflowDirectory(gitRepoRoot);
306
- for (const workflow of downloads) {
307
- const relativePath = path.posix.join(
308
- ".github",
309
- "workflows",
310
- path.posix.basename(workflow.sourcePath)
311
- );
312
- try {
313
- const write = await fileOps.writeTextFile(
314
- gitRepoRoot,
315
- relativePath,
316
- workflow.content
317
- );
318
- result.workflows.push({
319
- sourcePath: workflow.sourcePath,
320
- path: relativePath,
321
- status: "written",
322
- sizeBytes: write.sizeBytes
323
- });
324
- } catch (error) {
325
- if (isWorkspaceGenerationClosed(error)) throw error;
326
- result.partial = true;
327
- result.workflows.push({
328
- sourcePath: workflow.sourcePath,
329
- path: relativePath,
330
- status: "failed",
331
- error: error instanceof Error ? error.message : String(error)
332
- });
333
- throw new SetupGithubError(
334
- "github_workflow_write_failed",
335
- `Unable to write ${relativePath}.`,
336
- 500,
337
- result
338
- );
360
+ const meta = {
361
+ ...options.extra ?? {},
362
+ ...timestamp !== void 0 ? { timestamp } : {},
363
+ ...Object.keys(qwenTranscript).length > 0 ? { qwenTranscript } : {}
364
+ };
365
+ return Object.keys(meta).length > 0 ? meta : void 0;
366
+ }
367
+ __name(buildUpdateMeta, "buildUpdateMeta");
368
+ function createTranscriptMessageUpdate(options) {
369
+ const meta = buildUpdateMeta(options);
370
+ return {
371
+ sessionUpdate: options.role === "user" ? "user_message_chunk" : options.thought ? "agent_thought_chunk" : "agent_message_chunk",
372
+ content: { type: "text", text: options.text },
373
+ ...meta ? { _meta: meta } : {}
374
+ };
375
+ }
376
+ __name(createTranscriptMessageUpdate, "createTranscriptMessageUpdate");
377
+ function createTranscriptImageUpdate(options) {
378
+ const meta = buildUpdateMeta(options);
379
+ return {
380
+ sessionUpdate: "user_message_chunk",
381
+ content: { type: "image", data: options.data, mimeType: options.mimeType },
382
+ ...meta ? { _meta: meta } : {}
383
+ };
384
+ }
385
+ __name(createTranscriptImageUpdate, "createTranscriptImageUpdate");
386
+ function createTranscriptUsageUpdate(usageMetadata, options = {}) {
387
+ const usage = {
388
+ inputTokens: finiteNumber(usageMetadata.promptTokenCount) ?? 0,
389
+ outputTokens: finiteNumber(usageMetadata.candidatesTokenCount) ?? 0,
390
+ totalTokens: finiteNumber(usageMetadata.totalTokenCount) ?? 0,
391
+ ...finiteNumber(usageMetadata.thoughtsTokenCount) !== void 0 ? { thoughtTokens: finiteNumber(usageMetadata.thoughtsTokenCount) } : {},
392
+ ...finiteNumber(usageMetadata.cachedContentTokenCount) !== void 0 ? {
393
+ cachedReadTokens: finiteNumber(usageMetadata.cachedContentTokenCount)
394
+ } : {}
395
+ };
396
+ const meta = buildUpdateMeta({
397
+ ...options,
398
+ extra: { usage, ...options.extra ?? {} }
399
+ });
400
+ return {
401
+ sessionUpdate: "agent_message_chunk",
402
+ content: { type: "text", text: options.text ?? "" },
403
+ _meta: meta
404
+ };
405
+ }
406
+ __name(createTranscriptUsageUpdate, "createTranscriptUsageUpdate");
407
+ function createTranscriptToolCallStartUpdate(options) {
408
+ const provenance = resolveToolProvenance(options.toolName);
409
+ return {
410
+ sessionUpdate: options.asUpdate ? "tool_call_update" : "tool_call",
411
+ toolCallId: options.callId,
412
+ status: options.status ?? "pending",
413
+ title: options.metadata.title,
414
+ content: [],
415
+ locations: [...options.metadata.locations],
416
+ kind: options.metadata.kind,
417
+ rawInput: options.args ?? {},
418
+ _meta: buildUpdateMeta({
419
+ ...options,
420
+ extra: {
421
+ toolName: options.toolName,
422
+ provenance: provenance.provenance,
423
+ ...provenance.serverId ? { serverId: provenance.serverId } : {},
424
+ ...options.extra ?? {}
339
425
  }
340
- }
341
- } catch (error) {
342
- if (isWorkspaceGenerationClosed(error)) throw error;
343
- if (error instanceof SetupGithubError) throw error;
344
- throw new SetupGithubError(
345
- "github_workflow_write_failed",
346
- "Unable to create .github/workflows.",
347
- 500,
348
- result
349
- );
426
+ })
427
+ };
428
+ }
429
+ __name(createTranscriptToolCallStartUpdate, "createTranscriptToolCallStartUpdate");
430
+ function createTranscriptToolCallResultUpdate(options) {
431
+ const provenance = resolveToolProvenance(options.toolName);
432
+ const content = buildToolResultContent(options);
433
+ const update = {
434
+ sessionUpdate: "tool_call_update",
435
+ toolCallId: options.callId,
436
+ status: options.success ? "completed" : "failed",
437
+ content,
438
+ _meta: buildUpdateMeta({
439
+ ...options,
440
+ extra: {
441
+ toolName: options.toolName,
442
+ provenance: provenance.provenance,
443
+ ...provenance.serverId ? { serverId: provenance.serverId } : {},
444
+ ...options.artifacts && options.artifacts.length > 0 ? { artifacts: options.artifacts } : {},
445
+ ...options.extra ?? {}
446
+ }
447
+ })
448
+ };
449
+ if (options.resultDisplay !== void 0 && !isTruncatedSessionDiffDisplay(options.resultDisplay)) {
450
+ update["rawOutput"] = options.resultDisplay;
350
451
  }
351
- return result;
452
+ return update;
352
453
  }
353
- __name(setupGithub, "setupGithub");
354
- async function updateGitignore(gitRepoRoot, fileOps = nodeFileOps) {
355
- try {
356
- const existingContent = await fileOps.readTextFile(
357
- gitRepoRoot,
358
- ".gitignore"
359
- );
360
- if (existingContent === void 0) {
361
- const content = GITIGNORE_ENTRIES.join("\n") + "\n";
362
- await fileOps.writeTextFile(gitRepoRoot, ".gitignore", content);
363
- return {
364
- path: ".gitignore",
365
- status: "created",
366
- added: [...GITIGNORE_ENTRIES]
367
- };
454
+ __name(createTranscriptToolCallResultUpdate, "createTranscriptToolCallResultUpdate");
455
+ function createTranscriptPlanUpdate(todos, cumulativeUsage, options = {}) {
456
+ const meta = buildUpdateMeta({
457
+ ...options,
458
+ extra: {
459
+ ...cumulativeUsage ? { stats: { ...cumulativeUsage } } : {},
460
+ ...options.todoPlanId ? { qwenTodoPlan: { id: options.todoPlanId } } : {},
461
+ ...options.extra ?? {}
368
462
  }
369
- const missingEntries = GITIGNORE_ENTRIES.filter(
370
- (entry) => !existingContent.split(/\r?\n/).some((line) => line.split("#")[0].trim() === entry)
463
+ });
464
+ return {
465
+ sessionUpdate: "plan",
466
+ entries: todos.map((todo) => ({
467
+ content: todo.content,
468
+ priority: "medium",
469
+ status: todo.status,
470
+ ...todo.id || todo.blockedBy ? {
471
+ _meta: {
472
+ qwenTodo: {
473
+ ...todo.id ? { id: todo.id } : {},
474
+ ...todo.blockedBy ? { blockedBy: [...todo.blockedBy] } : {}
475
+ }
476
+ }
477
+ } : {}
478
+ })),
479
+ ...meta ? { _meta: meta } : {}
480
+ };
481
+ }
482
+ __name(createTranscriptPlanUpdate, "createTranscriptPlanUpdate");
483
+ function extractTranscriptTodoPlan(resultDisplay, args) {
484
+ const fromDisplay = extractTodoPlanFromDisplay(resultDisplay);
485
+ if (fromDisplay) return fromDisplay;
486
+ if (resultDisplay !== null && resultDisplay !== void 0) return null;
487
+ return args && Array.isArray(args["todos"]) ? { todos: normalizeTodos(args["todos"]) } : null;
488
+ }
489
+ __name(extractTranscriptTodoPlan, "extractTranscriptTodoPlan");
490
+ function createTranscriptReplayMachine(options = {}) {
491
+ return new DefaultTranscriptReplayMachine(options);
492
+ }
493
+ __name(createTranscriptReplayMachine, "createTranscriptReplayMachine");
494
+ var DefaultTranscriptReplayMachine = class {
495
+ constructor(options) {
496
+ this.options = options;
497
+ const initialState = parseInitialState(
498
+ options.initialState,
499
+ options.onDiagnostic
371
500
  );
372
- if (missingEntries.length === 0) {
373
- return { path: ".gitignore", status: "unchanged" };
501
+ this.usage = { ...initialState.cumulativeUsage };
502
+ this.goalState = initialState.goalState;
503
+ this.goalCause = initialState.goalCause;
504
+ for (const pending of initialState.pendingToolCalls) {
505
+ this.pendingToolCalls.set(pending.callId, pending);
506
+ this.usedToolCallIds.add(pending.callId);
507
+ }
508
+ for (const gap of options.gaps ?? []) {
509
+ if (!this.gapByChild.has(gap.childUuid)) {
510
+ this.gapByChild.set(gap.childUuid, gap);
511
+ }
374
512
  }
375
- const nextContent = existingContent + "\n" + missingEntries.join("\n") + "\n";
376
- await fileOps.writeTextFile(gitRepoRoot, ".gitignore", nextContent);
377
- return {
378
- path: ".gitignore",
379
- status: "updated",
380
- added: missingEntries
381
- };
382
- } catch (error) {
383
- if (isWorkspaceGenerationClosed(error)) throw error;
384
- debugLogger2.debug("Failed to update .gitignore:", error);
385
- return {
386
- path: ".gitignore",
387
- status: "failed",
388
- error: error instanceof Error ? error.message : String(error)
389
- };
390
513
  }
391
- }
392
- __name(updateGitignore, "updateGitignore");
393
- async function downloadWorkflows(options) {
394
- const internalAbort = new AbortController();
395
- try {
396
- const dispatcher = options.proxy ? new (await loadUndici()).ProxyAgent(options.proxy) : void 0;
397
- return await Promise.all(
398
- GITHUB_WORKFLOW_PATHS.map(async (workflow) => {
399
- const endpoint = `https://raw.githubusercontent.com/QwenLM/qwen-code-action/refs/tags/${options.releaseTag}/examples/workflows/${workflow}`;
400
- const response = await options.fetchImpl(endpoint, {
401
- method: "GET",
402
- dispatcher,
403
- signal: AbortSignal.any([
404
- AbortSignal.timeout(3e4),
405
- internalAbort.signal,
406
- ...options.abortSignal ? [options.abortSignal] : []
407
- ])
408
- });
409
- if (!response.ok) {
410
- throw new Error(
411
- `Invalid response code downloading ${endpoint}: ${response.status} - ${response.statusText}`
412
- );
413
- }
414
- return {
415
- sourcePath: workflow,
416
- content: await readResponseTextWithLimit(response, workflow)
417
- };
418
- })
419
- );
420
- } catch (error) {
421
- internalAbort.abort();
422
- const message = error instanceof Error ? error.message : String(error);
423
- debugLogger2.debug("Failed to download qwen-code-action workflows:", error);
424
- throw new SetupGithubError(
425
- "github_workflow_download_failed",
426
- `Unable to download qwen-code-action workflows from GitHub. ${message}`,
427
- 502
428
- );
514
+ static {
515
+ __name(this, "DefaultTranscriptReplayMachine");
429
516
  }
430
- }
431
- __name(downloadWorkflows, "downloadWorkflows");
432
- async function readResponseTextWithLimit(response, sourcePath) {
433
- const contentLength = response.headers.get("content-length");
434
- if (contentLength !== null) {
435
- const parsedLength = Number(contentLength);
436
- if (Number.isFinite(parsedLength) && parsedLength > MAX_WORKFLOW_DOWNLOAD_BYTES) {
517
+ pendingToolCalls = /* @__PURE__ */ new Map();
518
+ usedToolCallIds = /* @__PURE__ */ new Set();
519
+ gapByChild = /* @__PURE__ */ new Map();
520
+ usage;
521
+ finalized = false;
522
+ goalState;
523
+ goalCause;
524
+ *project(record) {
525
+ if (this.finalized) {
437
526
  throw new Error(
438
- `${sourcePath} exceeds download limit of ${MAX_WORKFLOW_DOWNLOAD_BYTES} bytes`
527
+ "Cannot project records after transcript replay finalize."
439
528
  );
440
529
  }
441
- }
442
- if (!response.body) return "";
443
- const reader = response.body.getReader();
444
- const chunks = [];
445
- let totalBytes = 0;
446
- try {
447
- while (true) {
448
- const { done, value } = await reader.read();
449
- if (done) break;
450
- if (!value) continue;
451
- totalBytes += value.byteLength;
452
- if (totalBytes > MAX_WORKFLOW_DOWNLOAD_BYTES) {
453
- await reader.cancel().catch(() => {
454
- });
455
- throw new Error(
456
- `${sourcePath} exceeds download limit of ${MAX_WORKFLOW_DOWNLOAD_BYTES} bytes`
530
+ let ordinal = 0;
531
+ const emit = /* @__PURE__ */ __name((update) => ({
532
+ sourceRecordId: record.uuid,
533
+ ...record.timestamp ? { sourceTimestamp: record.timestamp } : {},
534
+ emissionOrdinal: ordinal++,
535
+ update
536
+ }), "emit");
537
+ const meta = {
538
+ timestamp: record.timestamp,
539
+ sourceRecordIds: [record.uuid],
540
+ ...record.subtype === "realtime_message" ? {
541
+ extra: {
542
+ source: "realtime_voice",
543
+ qwenDiscreteMessage: true
544
+ }
545
+ } : {}
546
+ };
547
+ const gap = this.gapByChild.get(record.uuid);
548
+ if (gap) {
549
+ yield emit(
550
+ createTranscriptMessageUpdate({
551
+ role: "assistant",
552
+ text: this.formatGap(gap),
553
+ ...meta,
554
+ extra: { qwenDiscreteMessage: true }
555
+ })
556
+ );
557
+ }
558
+ switch (record.type) {
559
+ case "user":
560
+ yield* this.projectUserRecord(record, emit, meta);
561
+ break;
562
+ case "assistant":
563
+ yield* this.projectAssistantRecord(record, emit, meta);
564
+ break;
565
+ case "tool_result":
566
+ yield* this.projectToolResult(record, emit, meta);
567
+ break;
568
+ case "system":
569
+ yield* this.projectSystemRecord(record, emit, meta);
570
+ break;
571
+ default:
572
+ this.report(
573
+ "unknown_record_or_part",
574
+ "Skipped an unknown transcript record type.",
575
+ record.uuid
457
576
  );
458
- }
459
- chunks.push(value);
460
577
  }
461
- } finally {
462
- reader.releaseLock();
463
- }
464
- const body = new Uint8Array(totalBytes);
465
- let offset = 0;
466
- for (const chunk of chunks) {
467
- body.set(chunk, offset);
468
- offset += chunk.byteLength;
469
- }
470
- return new TextDecoder().decode(body);
471
- }
472
- __name(readResponseTextWithLimit, "readResponseTextWithLimit");
473
- async function resolveSecretsUrl(cwd) {
474
- try {
475
- const repoInfo = await getGitHubRepoInfoAsync({ cwd });
476
- return `https://github.com/${repoInfo.owner}/${repoInfo.repo}/settings/secrets/actions`;
477
- } catch {
478
- return void 0;
479
- }
480
- }
481
- __name(resolveSecretsUrl, "resolveSecretsUrl");
482
- async function realpathOrResolve(input) {
483
- try {
484
- return await fsp.realpath(input);
485
- } catch {
486
- return path.resolve(input);
487
- }
488
- }
489
- __name(realpathOrResolve, "realpathOrResolve");
490
-
491
- // packages/acp-bridge/src/transcript-replay.ts
492
- init_esbuild_shims();
493
-
494
- // packages/core/dist/src/goals/goal-wire.js
495
- init_esbuild_shims();
496
-
497
- // packages/core/dist/src/goals/goal-protocol.js
498
- init_esbuild_shims();
499
- var GOAL_STATE_VERSION = 2;
500
- var GOAL_CHECKPOINT_CLAIM_LIMIT = 32;
501
- var GOAL_CHECKPOINT_CLAIM_MAX_CHARACTERS = 2e3;
502
- var GOAL_CHECKPOINT_CLAIM_MAX_BYTES = 16e3;
503
- var GOAL_CHECKPOINT_SOURCE_REFERENCE_LIMIT = 32;
504
- function isGoalEvidenceProofKind(value) {
505
- return value === "user_input" || value === "delivered_output" || value === "external_fact";
506
- }
507
- __name(isGoalEvidenceProofKind, "isGoalEvidenceProofKind");
508
-
509
- // packages/core/dist/src/goals/goal-reducer.js
510
- init_esbuild_shims();
511
- var MAX_BLOCKED_AUDIT_COUNT = 3;
512
- function parseGoalStateRecordPayloadV2(value) {
513
- if (!isRecord(value) || !hasOnlyKeys(value, [
514
- "v",
515
- "cause",
516
- "snapshot",
517
- "checkpointPending",
518
- "blockedAudit"
519
- ]) || value["v"] !== GOAL_STATE_VERSION || !isGoalStateCause(value["cause"]) || !isCheckpointPending(value["checkpointPending"]) || !isBlockedAudit(value["blockedAudit"])) {
520
- return void 0;
521
578
  }
522
- const parsedSnapshot = parseGoalSnapshotV2(value["snapshot"]);
523
- if (parsedSnapshot?.activity !== "idle")
524
- return void 0;
525
- const checkpointPending = value["checkpointPending"];
526
- if (checkpointPending && (parsedSnapshot.goal?.status !== "active" || checkpointPending.permit.goalId !== parsedSnapshot.goal.goalId || checkpointPending.permit.revision !== parsedSnapshot.goal.revision || checkpointPending.recordUuid === parsedSnapshot.goal.evidenceCursor.recordId || value["cause"] !== "turn_finished" && value["cause"] !== "verifier_reject")) {
527
- return void 0;
528
- }
529
- return {
530
- v: GOAL_STATE_VERSION,
531
- cause: value["cause"],
532
- snapshot: parsedSnapshot,
533
- ...checkpointPending ? { checkpointPending: structuredClone(checkpointPending) } : {},
534
- ...value["blockedAudit"] ? { blockedAudit: structuredClone(value["blockedAudit"]) } : {}
535
- };
536
- }
537
- __name(parseGoalStateRecordPayloadV2, "parseGoalStateRecordPayloadV2");
538
- function parseGoalSnapshotV2(value) {
539
- if (!isRecord(value) || !hasOnlyKeys(value, ["v", "goal", "activity"]) || value["v"] !== GOAL_STATE_VERSION || !isGoalActivity(value["activity"])) {
540
- return void 0;
579
+ *finalize() {
580
+ if (this.finalized) return;
581
+ this.finalized = true;
582
+ let ordinal = 0;
583
+ for (const pending of [...this.pendingToolCalls.values()]) {
584
+ this.pendingToolCalls.delete(pending.callId);
585
+ this.report(
586
+ "missing_tool_result",
587
+ "A transcript tool call has no persisted result.",
588
+ pending.sourceRecordId
589
+ );
590
+ yield {
591
+ sourceRecordId: pending.sourceRecordId,
592
+ ...pending.sourceTimestamp ? { sourceTimestamp: pending.sourceTimestamp } : {},
593
+ emissionOrdinal: ordinal++,
594
+ update: createTranscriptToolCallResultUpdate({
595
+ toolName: pending.toolName,
596
+ callId: pending.callId,
597
+ success: false,
598
+ errorMessage: MISSING_TRANSCRIPT_TOOL_RESULT_MESSAGE,
599
+ timestamp: pending.sourceTimestamp,
600
+ sourceRecordIds: [pending.sourceRecordId]
601
+ })
602
+ };
603
+ }
541
604
  }
542
- if (value["goal"] === null) {
605
+ snapshot() {
543
606
  return {
544
- v: GOAL_STATE_VERSION,
545
- goal: null,
546
- activity: value["activity"]
607
+ v: 1,
608
+ pendingToolCalls: [...this.pendingToolCalls.values()].map((pending) => ({
609
+ ...pending
610
+ })),
611
+ cumulativeUsage: { ...this.usage },
612
+ ...this.goalState ? { goalState: this.goalState } : {},
613
+ ...this.goalCause ? { goalCause: this.goalCause } : {}
547
614
  };
548
615
  }
549
- const goal = parseGoalRecord(value["goal"]);
550
- return goal ? { v: GOAL_STATE_VERSION, goal, activity: value["activity"] } : void 0;
551
- }
552
- __name(parseGoalSnapshotV2, "parseGoalSnapshotV2");
553
- function parseGoalStateCause(value) {
554
- return isGoalStateCause(value) ? value : void 0;
555
- }
556
- __name(parseGoalStateCause, "parseGoalStateCause");
557
- function copyCursor(cursor) {
558
- return { recordId: cursor.recordId };
559
- }
560
- __name(copyCursor, "copyCursor");
561
- function parseGoalRecord(value) {
562
- if (!isRecord(value) || !hasOnlyKeys(value, [
563
- "goalId",
564
- "revision",
565
- "objective",
566
- "status",
567
- "evidenceCursor",
568
- "turnCount",
569
- "activeTimeMs",
570
- "createdAt",
571
- "updatedAt",
572
- "evidenceCheckpoint",
573
- "lastReason"
574
- ]) || typeof value["goalId"] !== "string" || !value["goalId"] || !isNonNegativeInteger(value["revision"]) || value["revision"] === 0 || typeof value["objective"] !== "string" || !value["objective"].trim() || !isGoalStatus(value["status"]) || !isTranscriptCursor(value["evidenceCursor"]) || !isNonNegativeInteger(value["turnCount"]) || !isNonNegativeNumber(value["activeTimeMs"]) || !isFiniteNumber(value["createdAt"]) || !isFiniteNumber(value["updatedAt"]) || !isGoalEvidenceCheckpoint(value["evidenceCheckpoint"]) || value["lastReason"] !== void 0 && typeof value["lastReason"] !== "string") {
575
- return void 0;
576
- }
577
- if (value["evidenceCheckpoint"] && value["evidenceCursor"].recordId !== value["evidenceCheckpoint"].checkpointId) {
578
- return void 0;
579
- }
580
- return {
581
- goalId: value["goalId"],
582
- revision: value["revision"],
583
- objective: value["objective"],
584
- status: value["status"],
585
- evidenceCursor: copyCursor(value["evidenceCursor"]),
586
- turnCount: value["turnCount"],
587
- activeTimeMs: value["activeTimeMs"],
588
- createdAt: value["createdAt"],
589
- updatedAt: value["updatedAt"],
590
- ...value["evidenceCheckpoint"] === void 0 ? {} : {
591
- evidenceCheckpoint: structuredClone(value["evidenceCheckpoint"])
592
- },
593
- ...value["lastReason"] === void 0 ? {} : { lastReason: value["lastReason"] }
594
- };
595
- }
596
- __name(parseGoalRecord, "parseGoalRecord");
597
- function isTranscriptCursor(value) {
598
- return isRecord(value) && hasOnlyKeys(value, ["recordId"]) && (typeof value["recordId"] === "string" || value["recordId"] === null);
599
- }
600
- __name(isTranscriptCursor, "isTranscriptCursor");
601
- function isGoalStatus(value) {
602
- return value === "active" || value === "paused" || value === "blocked" || value === "usage_limited" || value === "complete";
603
- }
604
- __name(isGoalStatus, "isGoalStatus");
605
- function isGoalActivity(value) {
606
- return value === "idle" || value === "running" || value === "verifying";
607
- }
608
- __name(isGoalActivity, "isGoalActivity");
609
- function isGoalStateCause(value) {
610
- return value === "create" || value === "replace" || value === "edit" || value === "pause" || value === "resume" || value === "turn_finished" || value === "checkpoint" || value === "verifier_accept" || value === "verifier_reject" || value === "complete" || value === "blocked" || value === "usage_limited" || value === "clear" || value === "migrated";
611
- }
612
- __name(isGoalStateCause, "isGoalStateCause");
613
- function isGoalEvidenceCheckpoint(value) {
614
- if (value === void 0)
615
- return true;
616
- if (!isRecord(value) || !hasOnlyKeys(value, ["checkpointId", "createdAt", "claims"]) || typeof value["checkpointId"] !== "string" || value["checkpointId"].length === 0 || !isFiniteNumber(value["createdAt"]) || !Array.isArray(value["claims"]) || value["claims"].length === 0 || value["claims"].length > GOAL_CHECKPOINT_CLAIM_LIMIT) {
617
- return false;
618
- }
619
- let checkpointBytes = 0;
620
- for (const [index, claim] of value["claims"].entries()) {
621
- if (!isRecord(claim) || !hasOnlyKeys(claim, ["id", "proofKind", "claim", "sourceRefs"]) || claim["id"] !== `${value["checkpointId"]}:${index + 1}` || !isGoalEvidenceProofKind(claim["proofKind"]) || typeof claim["claim"] !== "string" || claim["claim"].trim().length === 0 || [...claim["claim"]].length > GOAL_CHECKPOINT_CLAIM_MAX_CHARACTERS || !Array.isArray(claim["sourceRefs"]) || claim["sourceRefs"].length === 0 || claim["sourceRefs"].length > GOAL_CHECKPOINT_SOURCE_REFERENCE_LIMIT || new Set(claim["sourceRefs"]).size !== claim["sourceRefs"].length || claim["sourceRefs"].some((reference) => typeof reference !== "string" || reference.length === 0)) {
622
- return false;
616
+ *projectUserRecord(record, emit, meta) {
617
+ const payload = isObjectRecord(record.systemPayload) ? record.systemPayload : void 0;
618
+ if (record.subtype === "goal_runtime" || record.subtype === "notification" || record.subtype === "cron" || record.subtype === "mid_turn_user_message") {
619
+ const displayText = payload && typeof payload["displayText"] === "string" ? payload["displayText"] : void 0;
620
+ if (displayText) {
621
+ const isNotification = record.subtype === "notification";
622
+ const backgroundTask = payload && isObjectRecord(payload["backgroundTask"]) ? payload["backgroundTask"] : void 0;
623
+ yield emit(
624
+ createTranscriptMessageUpdate({
625
+ role: "user",
626
+ text: displayText,
627
+ ...meta,
628
+ ...isNotification ? {
629
+ extra: {
630
+ source: "background_notification",
631
+ qwenDiscreteMessage: true,
632
+ ...backgroundTask ? { backgroundTask } : {}
633
+ }
634
+ } : record.subtype === "cron" ? { extra: { source: "cron" } } : {}
635
+ })
636
+ );
637
+ return;
638
+ }
639
+ if (record.subtype !== "mid_turn_user_message") return;
623
640
  }
624
- checkpointBytes += new TextEncoder().encode(claim["claim"]).byteLength;
625
- if (checkpointBytes > GOAL_CHECKPOINT_CLAIM_MAX_BYTES)
626
- return false;
641
+ const projection = projectUserTranscriptForDisplay(record);
642
+ if (projection.displayText !== void 0) {
643
+ yield* this.projectMessageParts(
644
+ record,
645
+ "user",
646
+ emit,
647
+ meta,
648
+ void 0,
649
+ replaceTextPartsForDisplay(
650
+ record.message?.parts,
651
+ projection.displayText
652
+ )
653
+ );
654
+ return;
655
+ }
656
+ yield* this.projectMessageParts(
657
+ record,
658
+ "user",
659
+ emit,
660
+ meta,
661
+ void 0,
662
+ projection.parts
663
+ );
627
664
  }
628
- return true;
629
- }
630
- __name(isGoalEvidenceCheckpoint, "isGoalEvidenceCheckpoint");
631
- function isCheckpointPending(value) {
632
- return value === void 0 || isRecord(value) && hasOnlyKeys(value, ["permit", "recordUuid"]) && isGoalTurnPermit(value["permit"]) && typeof value["recordUuid"] === "string" && value["recordUuid"].length > 0;
633
- }
634
- __name(isCheckpointPending, "isCheckpointPending");
635
- function isGoalTurnPermit(value) {
636
- return isRecord(value) && hasOnlyKeys(value, ["goalId", "revision", "turnId"]) && typeof value["goalId"] === "string" && value["goalId"].length > 0 && isNonNegativeInteger(value["revision"]) && value["revision"] > 0 && typeof value["turnId"] === "string" && value["turnId"].length > 0;
637
- }
638
- __name(isGoalTurnPermit, "isGoalTurnPermit");
639
- function isBlockedAudit(value) {
640
- return value === void 0 || isRecord(value) && hasOnlyKeys(value, ["fingerprint", "count", "turnIds"]) && typeof value["fingerprint"] === "string" && value["fingerprint"].length > 0 && isNonNegativeInteger(value["count"]) && value["count"] > 0 && value["count"] <= MAX_BLOCKED_AUDIT_COUNT && Array.isArray(value["turnIds"]) && value["turnIds"].length === value["count"] && value["turnIds"].every((turnId) => typeof turnId === "string" && turnId.length > 0);
641
- }
642
- __name(isBlockedAudit, "isBlockedAudit");
643
- function isRecord(value) {
644
- return typeof value === "object" && value !== null && !Array.isArray(value);
645
- }
646
- __name(isRecord, "isRecord");
647
- function hasOnlyKeys(value, keys) {
648
- return Object.keys(value).every((key) => keys.includes(key));
649
- }
650
- __name(hasOnlyKeys, "hasOnlyKeys");
651
- function isNonNegativeInteger(value) {
652
- return typeof value === "number" && Number.isInteger(value) && value >= 0;
653
- }
654
- __name(isNonNegativeInteger, "isNonNegativeInteger");
655
- function isNonNegativeNumber(value) {
656
- return typeof value === "number" && Number.isFinite(value) && value >= 0;
657
- }
658
- __name(isNonNegativeNumber, "isNonNegativeNumber");
659
- function isFiniteNumber(value) {
660
- return typeof value === "number" && Number.isFinite(value);
661
- }
662
- __name(isFiniteNumber, "isFiniteNumber");
663
-
664
- // packages/core/dist/src/goals/goal-legacy-projection.js
665
- init_esbuild_shims();
666
- function projectGoalStateToLegacy(payload, previousGoal = null) {
667
- const snapshotGoal = payload.snapshot.goal;
668
- const displayGoal = snapshotGoal ?? previousGoal;
669
- const kind = legacyStatusKind(payload);
670
- const goalStatus = {
671
- type: "goal_status",
672
- kind,
673
- condition: displayGoal?.objective ?? "",
674
- ...displayGoal ? { iterations: displayGoal.turnCount } : {},
675
- ...displayGoal ? { setAt: displayGoal.createdAt } : {},
676
- ...displayGoal ? { durationMs: displayGoal.activeTimeMs } : {},
677
- ...displayGoal?.lastReason === void 0 ? {} : { lastReason: displayGoal.lastReason }
678
- };
679
- const terminalKind = kind === "achieved" || kind === "failed" || kind === "aborted" ? kind : void 0;
680
- return {
681
- activeGoal: snapshotGoal?.status === "active" ? {
682
- condition: snapshotGoal.objective,
683
- iterations: snapshotGoal.turnCount,
684
- setAt: snapshotGoal.createdAt,
685
- ...snapshotGoal.lastReason === void 0 ? {} : { lastReason: snapshotGoal.lastReason }
686
- } : null,
687
- goalStatus,
688
- goalTerminal: terminalKind && displayGoal ? {
689
- kind: terminalKind,
690
- condition: displayGoal.objective,
691
- iterations: displayGoal.turnCount,
692
- durationMs: displayGoal.activeTimeMs,
693
- ...displayGoal.lastReason === void 0 ? {} : { lastReason: displayGoal.lastReason }
694
- } : null
695
- };
696
- }
697
- __name(projectGoalStateToLegacy, "projectGoalStateToLegacy");
698
- function isGoalCheckpointBookkeepingTransition(previous, next) {
699
- const previousGoal = previous?.goal;
700
- const nextGoal = next.goal;
701
- if (!previousGoal || !nextGoal)
702
- return false;
703
- return previousGoal.goalId === nextGoal.goalId && previousGoal.revision === nextGoal.revision && previousGoal.objective === nextGoal.objective && previousGoal.status === nextGoal.status && previousGoal.turnCount === nextGoal.turnCount && previousGoal.createdAt === nextGoal.createdAt && previousGoal.lastReason === nextGoal.lastReason;
704
- }
705
- __name(isGoalCheckpointBookkeepingTransition, "isGoalCheckpointBookkeepingTransition");
706
- function isGoalCheckpointBookkeepingCause(cause, previousCause) {
707
- if (cause === "checkpoint")
708
- return true;
709
- return cause === "verifier_reject" && (previousCause === "verifier_reject" || previousCause === "checkpoint");
710
- }
711
- __name(isGoalCheckpointBookkeepingCause, "isGoalCheckpointBookkeepingCause");
712
- function isGoalCheckpointBookkeepingRecord(input) {
713
- return isGoalCheckpointBookkeepingTransition(input.previous, input.next) && isGoalCheckpointBookkeepingCause(input.cause, input.previousCause);
714
- }
715
- __name(isGoalCheckpointBookkeepingRecord, "isGoalCheckpointBookkeepingRecord");
716
- function legacyStatusKind(payload) {
717
- switch (payload.cause) {
718
- case "create":
719
- case "replace":
720
- case "edit":
721
- case "resume":
722
- return "set";
723
- case "complete":
724
- return "achieved";
725
- case "clear":
726
- return "cleared";
727
- // A migrated goal is always persisted `paused` (`createMigratedGoalState`),
728
- // and nothing drives a paused goal. Projecting it as `set` would re-assert
729
- // "active" to every client that derives the live goal from the newest card,
730
- // leaving a phantom running goal behind a resumed pre-v2 transcript.
731
- case "migrated":
732
- case "pause":
733
- return "paused";
734
- case "blocked":
735
- case "usage_limited":
736
- return "aborted";
737
- case "turn_finished":
738
- case "checkpoint":
739
- case "verifier_accept":
740
- case "verifier_reject":
741
- return payload.snapshot.goal?.status === "complete" ? "achieved" : payload.snapshot.goal?.status === "blocked" || payload.snapshot.goal?.status === "usage_limited" ? "aborted" : "checking";
742
- default:
743
- return assertNever(payload.cause);
665
+ *projectAssistantRecord(record, emit, meta) {
666
+ const usageMetadata = isObjectRecord(record.usageMetadata) ? record.usageMetadata : void 0;
667
+ let usageEmitted = false;
668
+ const takeUsageUpdate = /* @__PURE__ */ __name(() => {
669
+ if (!usageMetadata || usageEmitted) return void 0;
670
+ usageEmitted = true;
671
+ this.addUsage(usageMetadata);
672
+ return createTranscriptUsageUpdate(usageMetadata, meta);
673
+ }, "takeUsageUpdate");
674
+ yield* this.projectMessageParts(
675
+ record,
676
+ "assistant",
677
+ emit,
678
+ meta,
679
+ takeUsageUpdate
680
+ );
681
+ const trailingUsage = takeUsageUpdate();
682
+ if (trailingUsage) yield emit(trailingUsage);
744
683
  }
745
- }
746
- __name(legacyStatusKind, "legacyStatusKind");
747
- function assertNever(value) {
748
- throw new Error(`Unsupported Goal state cause: ${String(value)}`);
749
- }
750
- __name(assertNever, "assertNever");
751
-
752
- // packages/acp-bridge/src/transcript-replay.ts
753
- var MISSING_TRANSCRIPT_TOOL_RESULT_MESSAGE = "Tool result missing from saved history; the previous run likely ended before this tool completed.";
754
- var TRANSCRIPT_GOAL_STATUS_KINDS = /* @__PURE__ */ new Set([
755
- "set",
756
- "achieved",
757
- "cleared",
758
- "failed",
759
- "aborted",
760
- // A paused goal is not running, and dropping the card here is not neutral:
761
- // the replay stream is what feeds the goal renderer, so the older `set` card
762
- // stays newest and every surface keeps claiming autonomous work is under way.
763
- // Kept in step with `GOAL_STATUS_KINDS`, which the daemon-side reader
764
- // (`parseGoalStatusItem`) validates the same on-disk cards against.
765
- "paused",
766
- "checking"
767
- ]);
768
- function isObjectRecord(value) {
769
- return typeof value === "object" && value !== null && !Array.isArray(value);
770
- }
771
- __name(isObjectRecord, "isObjectRecord");
772
- function replaceTextPartsForDisplay(parts, displayText) {
773
- const projected = [];
774
- let replacedText = false;
775
- for (const part of parts ?? []) {
776
- if (isObjectRecord(part) && typeof part["text"] === "string") {
777
- if (!replacedText && displayText.length > 0) {
778
- projected.push({ text: displayText });
684
+ *projectMessageParts(record, role, emit, meta, beforeToolCall, partsOverride) {
685
+ const parts = partsOverride ?? record.message?.parts;
686
+ if (!parts) return;
687
+ for (let partIndex = 0; partIndex < parts.length; partIndex += 1) {
688
+ const part = parts[partIndex];
689
+ if (!isObjectRecord(part)) {
690
+ this.report(
691
+ "malformed_part",
692
+ "Skipped a malformed transcript message part.",
693
+ record.uuid,
694
+ `message.parts[${partIndex}]`
695
+ );
696
+ continue;
697
+ }
698
+ let recognized = false;
699
+ if (typeof part["text"] === "string" && part["text"].length > 0) {
700
+ recognized = true;
701
+ yield emit(
702
+ createTranscriptMessageUpdate({
703
+ role,
704
+ text: part["text"],
705
+ thought: role === "assistant" && part["thought"] === true,
706
+ ...meta
707
+ })
708
+ );
709
+ }
710
+ const inlineData = isObjectRecord(part["inlineData"]) ? part["inlineData"] : void 0;
711
+ if (inlineData) {
712
+ recognized = true;
713
+ const data = inlineData["data"];
714
+ const mimeType = inlineData["mimeType"];
715
+ if (role === "user" && typeof data === "string" && typeof mimeType === "string" && mimeType.startsWith("image/")) {
716
+ yield emit(createTranscriptImageUpdate({ data, mimeType, ...meta }));
717
+ } else {
718
+ this.report(
719
+ "malformed_part",
720
+ "Skipped an unsupported or malformed inline transcript part.",
721
+ record.uuid,
722
+ `message.parts[${partIndex}].inlineData`
723
+ );
724
+ }
779
725
  }
780
- replacedText = true;
781
- } else {
782
- projected.push(part);
783
- }
784
- }
785
- if (!replacedText && displayText.length > 0) {
786
- projected.push({ text: displayText });
787
- }
788
- return projected;
789
- }
790
- __name(replaceTextPartsForDisplay, "replaceTextPartsForDisplay");
791
- function toTranscriptEpochMs(timestamp) {
792
- if (typeof timestamp === "number") {
793
- return Number.isFinite(timestamp) ? timestamp : void 0;
794
- }
795
- if (typeof timestamp !== "string") return void 0;
796
- const epochMs = new Date(timestamp).getTime();
797
- return Number.isFinite(epochMs) ? epochMs : void 0;
798
- }
799
- __name(toTranscriptEpochMs, "toTranscriptEpochMs");
800
- function buildUpdateMeta(options) {
801
- const timestamp = toTranscriptEpochMs(options.timestamp);
802
- const sourceRecordIds = dedupeStrings(options.sourceRecordIds ?? []);
803
- const qwenTranscript = {
804
- ...sourceRecordIds.length > 0 ? { sourceRecordIds } : {},
805
- ...options.planToolCallId ? { planToolCallId: options.planToolCallId } : {}
806
- };
807
- const meta = {
808
- ...options.extra ?? {},
809
- ...timestamp !== void 0 ? { timestamp } : {},
810
- ...Object.keys(qwenTranscript).length > 0 ? { qwenTranscript } : {}
811
- };
812
- return Object.keys(meta).length > 0 ? meta : void 0;
813
- }
814
- __name(buildUpdateMeta, "buildUpdateMeta");
815
- function createTranscriptMessageUpdate(options) {
816
- const meta = buildUpdateMeta(options);
817
- return {
818
- sessionUpdate: options.role === "user" ? "user_message_chunk" : options.thought ? "agent_thought_chunk" : "agent_message_chunk",
819
- content: { type: "text", text: options.text },
820
- ...meta ? { _meta: meta } : {}
821
- };
822
- }
823
- __name(createTranscriptMessageUpdate, "createTranscriptMessageUpdate");
824
- function createTranscriptImageUpdate(options) {
825
- const meta = buildUpdateMeta(options);
826
- return {
827
- sessionUpdate: "user_message_chunk",
828
- content: { type: "image", data: options.data, mimeType: options.mimeType },
829
- ...meta ? { _meta: meta } : {}
830
- };
831
- }
832
- __name(createTranscriptImageUpdate, "createTranscriptImageUpdate");
833
- function createTranscriptUsageUpdate(usageMetadata, options = {}) {
834
- const usage = {
835
- inputTokens: finiteNumber(usageMetadata.promptTokenCount) ?? 0,
836
- outputTokens: finiteNumber(usageMetadata.candidatesTokenCount) ?? 0,
837
- totalTokens: finiteNumber(usageMetadata.totalTokenCount) ?? 0,
838
- ...finiteNumber(usageMetadata.thoughtsTokenCount) !== void 0 ? { thoughtTokens: finiteNumber(usageMetadata.thoughtsTokenCount) } : {},
839
- ...finiteNumber(usageMetadata.cachedContentTokenCount) !== void 0 ? {
840
- cachedReadTokens: finiteNumber(usageMetadata.cachedContentTokenCount)
841
- } : {}
842
- };
843
- const meta = buildUpdateMeta({
844
- ...options,
845
- extra: { usage, ...options.extra ?? {} }
846
- });
847
- return {
848
- sessionUpdate: "agent_message_chunk",
849
- content: { type: "text", text: options.text ?? "" },
850
- _meta: meta
851
- };
852
- }
853
- __name(createTranscriptUsageUpdate, "createTranscriptUsageUpdate");
854
- function createTranscriptToolCallStartUpdate(options) {
855
- const provenance = resolveToolProvenance(options.toolName);
856
- return {
857
- sessionUpdate: options.asUpdate ? "tool_call_update" : "tool_call",
858
- toolCallId: options.callId,
859
- status: options.status ?? "pending",
860
- title: options.metadata.title,
861
- content: [],
862
- locations: [...options.metadata.locations],
863
- kind: options.metadata.kind,
864
- rawInput: options.args ?? {},
865
- _meta: buildUpdateMeta({
866
- ...options,
867
- extra: {
868
- toolName: options.toolName,
869
- provenance: provenance.provenance,
870
- ...provenance.serverId ? { serverId: provenance.serverId } : {},
871
- ...options.extra ?? {}
726
+ const functionCall = isObjectRecord(part["functionCall"]) ? part["functionCall"] : void 0;
727
+ if (functionCall) {
728
+ recognized = true;
729
+ const toolName = typeof functionCall["name"] === "string" ? functionCall["name"] : "";
730
+ const args = isObjectRecord(functionCall["args"]) ? functionCall["args"] : {};
731
+ if (!toolName) {
732
+ this.report(
733
+ "malformed_part",
734
+ "Skipped a tool call without a tool name.",
735
+ record.uuid,
736
+ `message.parts[${partIndex}].functionCall`
737
+ );
738
+ continue;
739
+ }
740
+ const preToolUpdate = beforeToolCall?.();
741
+ if (preToolUpdate) yield emit(preToolUpdate);
742
+ if (toolName === "todo_write") continue;
743
+ const explicitId = typeof functionCall["id"] === "string" && functionCall["id"].length > 0 ? functionCall["id"] : void 0;
744
+ const callId = this.allocateToolCallId(
745
+ explicitId ?? `qwen-replay-tool:${record.uuid}:${partIndex}`
746
+ );
747
+ const update = createTranscriptToolCallStartUpdate({
748
+ toolName,
749
+ callId,
750
+ args,
751
+ status: "in_progress",
752
+ metadata: this.resolveToolMetadata(toolName, args, record.uuid),
753
+ ...meta
754
+ });
755
+ yield emit(update);
756
+ if (role === "assistant") {
757
+ this.pendingToolCalls.set(callId, {
758
+ callId,
759
+ toolName,
760
+ sourceRecordId: record.uuid,
761
+ ...record.timestamp ? { sourceTimestamp: record.timestamp } : {}
762
+ });
763
+ }
872
764
  }
873
- })
874
- };
875
- }
876
- __name(createTranscriptToolCallStartUpdate, "createTranscriptToolCallStartUpdate");
877
- function createTranscriptToolCallResultUpdate(options) {
878
- const provenance = resolveToolProvenance(options.toolName);
879
- const content = buildToolResultContent(options);
880
- const update = {
881
- sessionUpdate: "tool_call_update",
882
- toolCallId: options.callId,
883
- status: options.success ? "completed" : "failed",
884
- content,
885
- _meta: buildUpdateMeta({
886
- ...options,
887
- extra: {
888
- toolName: options.toolName,
889
- provenance: provenance.provenance,
890
- ...provenance.serverId ? { serverId: provenance.serverId } : {},
891
- ...options.artifacts && options.artifacts.length > 0 ? { artifacts: options.artifacts } : {},
892
- ...options.extra ?? {}
765
+ if (!recognized && !("functionResponse" in part)) {
766
+ this.report(
767
+ "unknown_record_or_part",
768
+ "Skipped an unknown transcript message part.",
769
+ record.uuid,
770
+ `message.parts[${partIndex}]`
771
+ );
893
772
  }
894
- })
895
- };
896
- if (options.resultDisplay !== void 0 && !isTruncatedSessionDiffDisplay(options.resultDisplay)) {
897
- update["rawOutput"] = options.resultDisplay;
773
+ }
898
774
  }
899
- return update;
900
- }
901
- __name(createTranscriptToolCallResultUpdate, "createTranscriptToolCallResultUpdate");
902
- function createTranscriptPlanUpdate(todos, cumulativeUsage, options = {}) {
903
- const meta = buildUpdateMeta({
904
- ...options,
905
- extra: {
906
- ...cumulativeUsage ? { stats: { ...cumulativeUsage } } : {},
907
- ...options.todoPlanId ? { qwenTodoPlan: { id: options.todoPlanId } } : {},
908
- ...options.extra ?? {}
775
+ *projectToolResult(record, emit, meta) {
776
+ const result = isObjectRecord(record.toolCallResult) ? record.toolCallResult : void 0;
777
+ const toolName = extractToolName(record);
778
+ if (!toolName) {
779
+ this.report(
780
+ "malformed_part",
781
+ "A transcript tool result has no tool name.",
782
+ record.uuid,
783
+ "message.parts"
784
+ );
909
785
  }
910
- });
911
- return {
912
- sessionUpdate: "plan",
913
- entries: todos.map((todo) => ({
914
- content: todo.content,
915
- priority: "medium",
916
- status: todo.status,
917
- ...todo.id || todo.blockedBy ? {
918
- _meta: {
919
- qwenTodo: {
920
- ...todo.id ? { id: todo.id } : {},
921
- ...todo.blockedBy ? { blockedBy: [...todo.blockedBy] } : {}
922
- }
923
- }
924
- } : {}
925
- })),
926
- ...meta ? { _meta: meta } : {}
927
- };
928
- }
929
- __name(createTranscriptPlanUpdate, "createTranscriptPlanUpdate");
930
- function extractTranscriptTodoPlan(resultDisplay, args) {
931
- const fromDisplay = extractTodoPlanFromDisplay(resultDisplay);
932
- if (fromDisplay) return fromDisplay;
933
- if (resultDisplay !== null && resultDisplay !== void 0) return null;
934
- return args && Array.isArray(args["todos"]) ? { todos: normalizeTodos(args["todos"]) } : null;
935
- }
936
- __name(extractTranscriptTodoPlan, "extractTranscriptTodoPlan");
937
- function createTranscriptReplayMachine(options = {}) {
938
- return new DefaultTranscriptReplayMachine(options);
939
- }
940
- __name(createTranscriptReplayMachine, "createTranscriptReplayMachine");
941
- var DefaultTranscriptReplayMachine = class {
942
- constructor(options) {
943
- this.options = options;
944
- const initialState = parseInitialState(
945
- options.initialState,
946
- options.onDiagnostic
947
- );
948
- this.usage = { ...initialState.cumulativeUsage };
949
- this.goalState = initialState.goalState;
950
- this.goalCause = initialState.goalCause;
951
- for (const pending of initialState.pendingToolCalls) {
952
- this.pendingToolCalls.set(pending.callId, pending);
953
- this.usedToolCallIds.add(pending.callId);
786
+ const explicitCallId = extractToolResultCallId(record, result);
787
+ const callId = explicitCallId ? this.allocateToolCallId(explicitCallId, true) : this.correlateResultCallId(toolName, record.uuid);
788
+ this.pendingToolCalls.delete(callId);
789
+ const resultDisplay = result?.["resultDisplay"];
790
+ if (toolName === "todo_write") {
791
+ const plan = extractTranscriptTodoPlan(resultDisplay);
792
+ if (plan) {
793
+ yield emit(
794
+ createTranscriptPlanUpdate(plan.todos, this.usage, {
795
+ ...meta,
796
+ planToolCallId: callId,
797
+ todoPlanId: plan.planId
798
+ })
799
+ );
800
+ }
801
+ return;
954
802
  }
955
- for (const gap of options.gaps ?? []) {
956
- if (!this.gapByChild.has(gap.childUuid)) {
957
- this.gapByChild.set(gap.childUuid, gap);
803
+ yield emit(
804
+ createTranscriptToolCallResultUpdate({
805
+ toolName,
806
+ callId,
807
+ success: result?.["status"] === void 0 ? !result?.["error"] : result["status"] === "success" && !result["error"],
808
+ errorMessage: extractErrorMessage(result?.["error"]),
809
+ message: record.message?.parts,
810
+ resultDisplay,
811
+ artifacts: Array.isArray(result?.["artifacts"]) ? result["artifacts"] : void 0,
812
+ contentPrefix: this.buildToolResultContentPrefix(
813
+ resultDisplay,
814
+ record.uuid
815
+ ),
816
+ ...meta
817
+ })
818
+ );
819
+ if (isTaskExecutionDisplay(resultDisplay)) {
820
+ const usage = usageFromTaskExecution(resultDisplay);
821
+ if (Object.keys(usage).length > 0) {
822
+ this.addUsage(usage);
823
+ yield emit(createTranscriptUsageUpdate(usage, meta));
958
824
  }
959
825
  }
960
826
  }
961
- static {
962
- __name(this, "DefaultTranscriptReplayMachine");
963
- }
964
- pendingToolCalls = /* @__PURE__ */ new Map();
965
- usedToolCallIds = /* @__PURE__ */ new Set();
966
- gapByChild = /* @__PURE__ */ new Map();
967
- usage;
968
- finalized = false;
969
- goalState;
970
- goalCause;
971
- *project(record) {
972
- if (this.finalized) {
973
- throw new Error(
974
- "Cannot project records after transcript replay finalize."
827
+ *projectSystemRecord(record, emit, meta) {
828
+ if (record.subtype === "goal_state") {
829
+ const payload2 = parseGoalStateRecordPayloadV2(record.systemPayload);
830
+ if (!payload2) {
831
+ this.report(
832
+ "malformed_goal_state",
833
+ "Skipped a malformed Goal state transcript record.",
834
+ record.uuid,
835
+ "systemPayload"
836
+ );
837
+ return;
838
+ }
839
+ const bookkeepingOnly = isGoalCheckpointBookkeepingRecord({
840
+ cause: payload2.cause,
841
+ previousCause: this.goalCause,
842
+ previous: this.goalState,
843
+ next: payload2.snapshot
844
+ });
845
+ const projection = projectGoalStateToLegacy2(
846
+ payload2,
847
+ this.goalState?.goal ?? null
848
+ );
849
+ this.goalState = payload2.snapshot;
850
+ this.goalCause = payload2.cause;
851
+ if (bookkeepingOnly) return;
852
+ const { type: _type, ...goalStatus } = projection.goalStatus;
853
+ yield emit(
854
+ createTranscriptMessageUpdate({
855
+ role: "assistant",
856
+ text: "",
857
+ ...meta,
858
+ extra: {
859
+ goalState: payload2.snapshot,
860
+ goalStatus,
861
+ ...projection.goalTerminal ? { goalTerminal: projection.goalTerminal } : {},
862
+ "qwen.session.recordId": record.uuid
863
+ }
864
+ })
975
865
  );
866
+ return;
976
867
  }
977
- let ordinal = 0;
978
- const emit = /* @__PURE__ */ __name((update) => ({
979
- sourceRecordId: record.uuid,
980
- ...record.timestamp ? { sourceTimestamp: record.timestamp } : {},
981
- emissionOrdinal: ordinal++,
982
- update
983
- }), "emit");
984
- const meta = {
985
- timestamp: record.timestamp,
986
- sourceRecordIds: [record.uuid],
987
- ...record.subtype === "realtime_message" ? {
988
- extra: {
989
- source: "realtime_voice",
990
- qwenDiscreteMessage: true
868
+ if (record.subtype !== "slash_command") return;
869
+ const payload = isObjectRecord(record.systemPayload) ? record.systemPayload : void 0;
870
+ if (payload?.["phase"] !== "result") return;
871
+ const items = Array.isArray(payload["outputHistoryItems"]) ? payload["outputHistoryItems"] : [];
872
+ for (const item of items) {
873
+ const goalStatus = parseTranscriptGoalStatus(item);
874
+ if (goalStatus) {
875
+ if (goalStatus.condition.length === 0) {
876
+ this.report(
877
+ "malformed_part",
878
+ "Skipped replay of a goal card whose condition is empty.",
879
+ record.uuid,
880
+ "systemPayload.outputHistoryItems.goalStatus.condition"
881
+ );
882
+ } else if (goalStatus.kind !== "checking") {
883
+ yield emit(
884
+ createTranscriptMessageUpdate({
885
+ role: "assistant",
886
+ text: "",
887
+ ...meta,
888
+ extra: { goalStatus }
889
+ })
890
+ );
991
891
  }
992
- } : {}
993
- };
994
- const gap = this.gapByChild.get(record.uuid);
995
- if (gap) {
892
+ continue;
893
+ }
894
+ if (!isObjectRecord(item) || typeof item["text"] !== "string") continue;
996
895
  yield emit(
997
896
  createTranscriptMessageUpdate({
998
897
  role: "assistant",
999
- text: this.formatGap(gap),
898
+ text: item["text"].replace(/\n/g, " \n"),
1000
899
  ...meta,
1001
- extra: { qwenDiscreteMessage: true }
900
+ extra: { source: "slash_command" }
1002
901
  })
1003
902
  );
1004
903
  }
1005
- switch (record.type) {
1006
- case "user":
1007
- yield* this.projectUserRecord(record, emit, meta);
1008
- break;
1009
- case "assistant":
1010
- yield* this.projectAssistantRecord(record, emit, meta);
1011
- break;
1012
- case "tool_result":
1013
- yield* this.projectToolResult(record, emit, meta);
1014
- break;
1015
- case "system":
1016
- yield* this.projectSystemRecord(record, emit, meta);
1017
- break;
1018
- default:
1019
- this.report(
1020
- "unknown_record_or_part",
1021
- "Skipped an unknown transcript record type.",
1022
- record.uuid
1023
- );
904
+ }
905
+ addUsage(metadata) {
906
+ this.usage.promptTokens += finiteNumber(metadata["promptTokenCount"]) ?? 0;
907
+ this.usage.candidateTokens += finiteNumber(metadata["candidatesTokenCount"]) ?? 0;
908
+ this.usage.cachedTokens += finiteNumber(metadata["cachedContentTokenCount"]) ?? 0;
909
+ }
910
+ correlateResultCallId(toolName, recordId) {
911
+ const candidates = [...this.pendingToolCalls.values()].filter(
912
+ (pending) => pending.toolName === toolName
913
+ );
914
+ if (candidates.length === 1) return candidates[0].callId;
915
+ this.report(
916
+ "ambiguous_tool_call_correlation",
917
+ "A tool result could not be matched to exactly one pending tool call.",
918
+ recordId
919
+ );
920
+ return this.allocateToolCallId(`qwen-replay-tool:${recordId}:result`);
921
+ }
922
+ allocateToolCallId(candidate, reuse = false) {
923
+ if (reuse && this.pendingToolCalls.has(candidate)) {
924
+ this.usedToolCallIds.add(candidate);
925
+ return candidate;
926
+ }
927
+ if (!this.usedToolCallIds.has(candidate)) {
928
+ this.usedToolCallIds.add(candidate);
929
+ return candidate;
930
+ }
931
+ let occurrence = 2;
932
+ while (this.usedToolCallIds.has(`${candidate}:${occurrence}`)) {
933
+ occurrence += 1;
1024
934
  }
935
+ const id = `${candidate}:${occurrence}`;
936
+ this.usedToolCallIds.add(id);
937
+ return id;
1025
938
  }
1026
- *finalize() {
1027
- if (this.finalized) return;
1028
- this.finalized = true;
1029
- let ordinal = 0;
1030
- for (const pending of [...this.pendingToolCalls.values()]) {
1031
- this.pendingToolCalls.delete(pending.callId);
939
+ resolveToolMetadata(toolName, args, recordId) {
940
+ try {
941
+ return this.options.presentation?.resolveToolMetadata(toolName, args) ?? fallbackToolMetadata(toolName, args);
942
+ } catch {
1032
943
  this.report(
1033
- "missing_tool_result",
1034
- "A transcript tool call has no persisted result.",
1035
- pending.sourceRecordId
944
+ "presentation_fallback",
945
+ "Tool presentation metadata fell back to deterministic defaults.",
946
+ recordId,
947
+ void 0,
948
+ false
1036
949
  );
1037
- yield {
1038
- sourceRecordId: pending.sourceRecordId,
1039
- ...pending.sourceTimestamp ? { sourceTimestamp: pending.sourceTimestamp } : {},
1040
- emissionOrdinal: ordinal++,
1041
- update: createTranscriptToolCallResultUpdate({
1042
- toolName: pending.toolName,
1043
- callId: pending.callId,
1044
- success: false,
1045
- errorMessage: MISSING_TRANSCRIPT_TOOL_RESULT_MESSAGE,
1046
- timestamp: pending.sourceTimestamp,
1047
- sourceRecordIds: [pending.sourceRecordId]
1048
- })
1049
- };
950
+ return fallbackToolMetadata(toolName, args);
1050
951
  }
1051
952
  }
1052
- snapshot() {
1053
- return {
1054
- v: 1,
1055
- pendingToolCalls: [...this.pendingToolCalls.values()].map((pending) => ({
1056
- ...pending
1057
- })),
1058
- cumulativeUsage: { ...this.usage },
1059
- ...this.goalState ? { goalState: this.goalState } : {},
1060
- ...this.goalCause ? { goalCause: this.goalCause } : {}
1061
- };
1062
- }
1063
- *projectUserRecord(record, emit, meta) {
1064
- const payload = isObjectRecord(record.systemPayload) ? record.systemPayload : void 0;
1065
- if (record.subtype === "goal_runtime" || record.subtype === "notification" || record.subtype === "cron" || record.subtype === "mid_turn_user_message") {
1066
- const displayText = payload && typeof payload["displayText"] === "string" ? payload["displayText"] : void 0;
1067
- if (displayText) {
1068
- const isNotification = record.subtype === "notification";
1069
- const backgroundTask = payload && isObjectRecord(payload["backgroundTask"]) ? payload["backgroundTask"] : void 0;
1070
- yield emit(
1071
- createTranscriptMessageUpdate({
1072
- role: "user",
1073
- text: displayText,
1074
- ...meta,
1075
- ...isNotification ? {
1076
- extra: {
1077
- source: "background_notification",
1078
- qwenDiscreteMessage: true,
1079
- ...backgroundTask ? { backgroundTask } : {}
1080
- }
1081
- } : record.subtype === "cron" ? { extra: { source: "cron" } } : {}
1082
- })
1083
- );
1084
- return;
1085
- }
1086
- if (record.subtype !== "mid_turn_user_message") return;
953
+ formatGap(gap) {
954
+ try {
955
+ return this.options.presentation?.formatHistoryGap(gap) ?? "Some earlier messages are unavailable because the saved history is incomplete.";
956
+ } catch {
957
+ this.report(
958
+ "presentation_fallback",
959
+ "History gap presentation fell back to deterministic defaults.",
960
+ gap.childUuid,
961
+ void 0,
962
+ false
963
+ );
964
+ return "Some earlier messages are unavailable because the saved history is incomplete.";
1087
965
  }
1088
- const projection = projectUserTranscriptForDisplay(record);
1089
- if (projection.displayText !== void 0) {
1090
- yield* this.projectMessageParts(
1091
- record,
1092
- "user",
1093
- emit,
1094
- meta,
966
+ }
967
+ buildToolResultContentPrefix(resultDisplay, recordId) {
968
+ try {
969
+ return this.options.presentation?.buildToolResultContentPrefix?.(
970
+ resultDisplay
971
+ ) ?? defaultToolResultContentPrefix(resultDisplay);
972
+ } catch {
973
+ this.report(
974
+ "presentation_fallback",
975
+ "Tool result content presentation fell back to deterministic defaults.",
976
+ recordId,
1095
977
  void 0,
1096
- replaceTextPartsForDisplay(
1097
- record.message?.parts,
1098
- projection.displayText
1099
- )
978
+ false
1100
979
  );
1101
- return;
980
+ return defaultToolResultContentPrefix(resultDisplay);
1102
981
  }
1103
- yield* this.projectMessageParts(
1104
- record,
1105
- "user",
1106
- emit,
1107
- meta,
1108
- void 0,
1109
- projection.parts
1110
- );
1111
982
  }
1112
- *projectAssistantRecord(record, emit, meta) {
1113
- const usageMetadata = isObjectRecord(record.usageMetadata) ? record.usageMetadata : void 0;
1114
- let usageEmitted = false;
1115
- const takeUsageUpdate = /* @__PURE__ */ __name(() => {
1116
- if (!usageMetadata || usageEmitted) return void 0;
1117
- usageEmitted = true;
1118
- this.addUsage(usageMetadata);
1119
- return createTranscriptUsageUpdate(usageMetadata, meta);
1120
- }, "takeUsageUpdate");
1121
- yield* this.projectMessageParts(
1122
- record,
1123
- "assistant",
1124
- emit,
1125
- meta,
1126
- takeUsageUpdate
1127
- );
1128
- const trailingUsage = takeUsageUpdate();
1129
- if (trailingUsage) yield emit(trailingUsage);
983
+ report(code, message, recordId, path2, affectsCompleteness = true) {
984
+ this.options.onDiagnostic?.({
985
+ code,
986
+ severity: affectsCompleteness ? "warning" : "info",
987
+ message,
988
+ affectsCompleteness,
989
+ ...recordId ? { recordId } : {},
990
+ ...path2 ? { path: path2 } : {}
991
+ });
1130
992
  }
1131
- *projectMessageParts(record, role, emit, meta, beforeToolCall, partsOverride) {
1132
- const parts = partsOverride ?? record.message?.parts;
1133
- if (!parts) return;
1134
- for (let partIndex = 0; partIndex < parts.length; partIndex += 1) {
1135
- const part = parts[partIndex];
1136
- if (!isObjectRecord(part)) {
1137
- this.report(
1138
- "malformed_part",
1139
- "Skipped a malformed transcript message part.",
1140
- record.uuid,
1141
- `message.parts[${partIndex}]`
1142
- );
1143
- continue;
1144
- }
1145
- let recognized = false;
1146
- if (typeof part["text"] === "string" && part["text"].length > 0) {
1147
- recognized = true;
1148
- yield emit(
1149
- createTranscriptMessageUpdate({
1150
- role,
1151
- text: part["text"],
1152
- thought: role === "assistant" && part["thought"] === true,
1153
- ...meta
1154
- })
1155
- );
1156
- }
1157
- const inlineData = isObjectRecord(part["inlineData"]) ? part["inlineData"] : void 0;
1158
- if (inlineData) {
1159
- recognized = true;
1160
- const data = inlineData["data"];
1161
- const mimeType = inlineData["mimeType"];
1162
- if (role === "user" && typeof data === "string" && typeof mimeType === "string" && mimeType.startsWith("image/")) {
1163
- yield emit(createTranscriptImageUpdate({ data, mimeType, ...meta }));
1164
- } else {
1165
- this.report(
1166
- "malformed_part",
1167
- "Skipped an unsupported or malformed inline transcript part.",
1168
- record.uuid,
1169
- `message.parts[${partIndex}].inlineData`
1170
- );
1171
- }
993
+ };
994
+ function parseTranscriptGoalStatus(value) {
995
+ if (!isObjectRecord(value) || value["type"] !== "goal_status") {
996
+ return void 0;
997
+ }
998
+ const kind = value["kind"];
999
+ const condition = value["condition"];
1000
+ if (typeof kind !== "string" || !TRANSCRIPT_GOAL_STATUS_KINDS.has(kind) || typeof condition !== "string") {
1001
+ return void 0;
1002
+ }
1003
+ const iterations = finiteNumber(value["iterations"]);
1004
+ const setAt = finiteNumber(value["setAt"]);
1005
+ const durationMs = finiteNumber(value["durationMs"]);
1006
+ const lastReason = typeof value["lastReason"] === "string" ? value["lastReason"] : void 0;
1007
+ return {
1008
+ kind,
1009
+ condition,
1010
+ ...iterations !== void 0 ? { iterations } : {},
1011
+ ...setAt !== void 0 ? { setAt } : {},
1012
+ ...durationMs !== void 0 ? { durationMs } : {},
1013
+ ...lastReason !== void 0 ? { lastReason } : {}
1014
+ };
1015
+ }
1016
+ __name(parseTranscriptGoalStatus, "parseTranscriptGoalStatus");
1017
+ function defaultToolResultContentPrefix(resultDisplay) {
1018
+ if (!isObjectRecord(resultDisplay) || resultDisplay["type"] !== "vision_bridge_notice" || typeof resultDisplay["summary"] !== "string" || typeof resultDisplay["notice"] !== "string") {
1019
+ return [];
1020
+ }
1021
+ return [
1022
+ {
1023
+ type: "content",
1024
+ content: {
1025
+ type: "text",
1026
+ text: `${resultDisplay["summary"]}
1027
+ ${resultDisplay["notice"]}`
1172
1028
  }
1173
- const functionCall = isObjectRecord(part["functionCall"]) ? part["functionCall"] : void 0;
1174
- if (functionCall) {
1175
- recognized = true;
1176
- const toolName = typeof functionCall["name"] === "string" ? functionCall["name"] : "";
1177
- const args = isObjectRecord(functionCall["args"]) ? functionCall["args"] : {};
1178
- if (!toolName) {
1179
- this.report(
1180
- "malformed_part",
1181
- "Skipped a tool call without a tool name.",
1182
- record.uuid,
1183
- `message.parts[${partIndex}].functionCall`
1184
- );
1185
- continue;
1186
- }
1187
- const preToolUpdate = beforeToolCall?.();
1188
- if (preToolUpdate) yield emit(preToolUpdate);
1189
- if (toolName === "todo_write") continue;
1190
- const explicitId = typeof functionCall["id"] === "string" && functionCall["id"].length > 0 ? functionCall["id"] : void 0;
1191
- const callId = this.allocateToolCallId(
1192
- explicitId ?? `qwen-replay-tool:${record.uuid}:${partIndex}`
1193
- );
1194
- const update = createTranscriptToolCallStartUpdate({
1195
- toolName,
1196
- callId,
1197
- args,
1198
- status: "in_progress",
1199
- metadata: this.resolveToolMetadata(toolName, args, record.uuid),
1200
- ...meta
1029
+ }
1030
+ ];
1031
+ }
1032
+ __name(defaultToolResultContentPrefix, "defaultToolResultContentPrefix");
1033
+ function parseInitialState(value, onDiagnostic) {
1034
+ const empty = {
1035
+ v: 1,
1036
+ pendingToolCalls: [],
1037
+ cumulativeUsage: emptyUsage()
1038
+ };
1039
+ if (value === void 0) return empty;
1040
+ if (!isObjectRecord(value)) {
1041
+ throw new TypeError("Invalid transcript replay state.");
1042
+ }
1043
+ if ("v" in value && value["v"] !== 1) {
1044
+ throw new TypeError("Unsupported transcript replay state version.");
1045
+ }
1046
+ const rawPending = Array.isArray(value["pendingToolCalls"]) ? value["pendingToolCalls"] : [];
1047
+ const pendingToolCalls = rawPending.flatMap(
1048
+ (pending) => {
1049
+ if (!isObjectRecord(pending) || typeof pending["callId"] !== "string" || typeof pending["toolName"] !== "string" || typeof pending["sourceRecordId"] !== "string") {
1050
+ onDiagnostic?.({
1051
+ code: "invalid_replay_state",
1052
+ severity: "warning",
1053
+ message: "Dropped a malformed pending tool call from replay state.",
1054
+ affectsCompleteness: true
1201
1055
  });
1202
- yield emit(update);
1203
- if (role === "assistant") {
1204
- this.pendingToolCalls.set(callId, {
1205
- callId,
1206
- toolName,
1207
- sourceRecordId: record.uuid,
1208
- ...record.timestamp ? { sourceTimestamp: record.timestamp } : {}
1209
- });
1210
- }
1211
- }
1212
- if (!recognized && !("functionResponse" in part)) {
1213
- this.report(
1214
- "unknown_record_or_part",
1215
- "Skipped an unknown transcript message part.",
1216
- record.uuid,
1217
- `message.parts[${partIndex}]`
1218
- );
1056
+ return [];
1219
1057
  }
1058
+ return [
1059
+ {
1060
+ callId: pending["callId"],
1061
+ toolName: pending["toolName"],
1062
+ sourceRecordId: pending["sourceRecordId"],
1063
+ ...typeof pending["sourceTimestamp"] === "string" ? { sourceTimestamp: pending["sourceTimestamp"] } : {}
1064
+ }
1065
+ ];
1066
+ }
1067
+ );
1068
+ const rawUsage = value.cumulativeUsage;
1069
+ const usage = isObjectRecord(rawUsage) ? rawUsage : {};
1070
+ const validUsage = finiteNumber(usage["promptTokens"]) !== void 0 && finiteNumber(usage["cachedTokens"]) !== void 0 && finiteNumber(usage["candidateTokens"]) !== void 0 && finiteNumber(usage["apiTimeMs"]) !== void 0;
1071
+ if (!validUsage) {
1072
+ onDiagnostic?.({
1073
+ code: "invalid_replay_state",
1074
+ severity: "warning",
1075
+ message: "Reset invalid cumulative usage in transcript replay state.",
1076
+ affectsCompleteness: true
1077
+ });
1078
+ }
1079
+ const rawGoalState = value["goalState"];
1080
+ const goalState = rawGoalState === void 0 ? void 0 : parseGoalSnapshotV22(rawGoalState);
1081
+ if (rawGoalState !== void 0 && !goalState) {
1082
+ onDiagnostic?.({
1083
+ code: "invalid_replay_state",
1084
+ severity: "warning",
1085
+ message: "Dropped a malformed Goal state from replay state.",
1086
+ affectsCompleteness: true
1087
+ });
1088
+ }
1089
+ const rawGoalCause = value["goalCause"];
1090
+ const goalCause = rawGoalCause === void 0 ? void 0 : parseGoalStateCause2(rawGoalCause);
1091
+ if (rawGoalCause !== void 0 && !goalCause) {
1092
+ onDiagnostic?.({
1093
+ code: "invalid_replay_state",
1094
+ severity: "warning",
1095
+ message: "Dropped a malformed Goal cause from replay state.",
1096
+ affectsCompleteness: true
1097
+ });
1098
+ }
1099
+ return {
1100
+ v: 1,
1101
+ pendingToolCalls,
1102
+ cumulativeUsage: validUsage ? {
1103
+ promptTokens: usage["promptTokens"],
1104
+ cachedTokens: usage["cachedTokens"],
1105
+ candidateTokens: usage["candidateTokens"],
1106
+ apiTimeMs: usage["apiTimeMs"]
1107
+ } : emptyUsage(),
1108
+ ...goalState ? { goalState } : {},
1109
+ ...goalCause ? { goalCause } : {}
1110
+ };
1111
+ }
1112
+ __name(parseInitialState, "parseInitialState");
1113
+ function emptyUsage() {
1114
+ return {
1115
+ promptTokens: 0,
1116
+ cachedTokens: 0,
1117
+ candidateTokens: 0,
1118
+ apiTimeMs: 0
1119
+ };
1120
+ }
1121
+ __name(emptyUsage, "emptyUsage");
1122
+ function fallbackToolMetadata(toolName, args) {
1123
+ const description = typeof args["description"] === "string" ? args["description"].trim() : "";
1124
+ return {
1125
+ title: description ? `${toolName}: ${description}` : toolName,
1126
+ locations: [],
1127
+ kind: "other"
1128
+ };
1129
+ }
1130
+ __name(fallbackToolMetadata, "fallbackToolMetadata");
1131
+ function resolveToolProvenance(toolName) {
1132
+ if (toolName.startsWith("mcp__")) {
1133
+ const parts = toolName.split("__");
1134
+ if (parts.length >= 3 && parts[1]) {
1135
+ return { provenance: "mcp", serverId: parts[1] };
1220
1136
  }
1221
1137
  }
1222
- *projectToolResult(record, emit, meta) {
1223
- const result = isObjectRecord(record.toolCallResult) ? record.toolCallResult : void 0;
1224
- const toolName = extractToolName(record);
1225
- if (!toolName) {
1226
- this.report(
1227
- "malformed_part",
1228
- "A transcript tool result has no tool name.",
1229
- record.uuid,
1230
- "message.parts"
1231
- );
1232
- }
1233
- const explicitCallId = extractToolResultCallId(record, result);
1234
- const callId = explicitCallId ? this.allocateToolCallId(explicitCallId, true) : this.correlateResultCallId(toolName, record.uuid);
1235
- this.pendingToolCalls.delete(callId);
1236
- const resultDisplay = result?.["resultDisplay"];
1237
- if (toolName === "todo_write") {
1238
- const plan = extractTranscriptTodoPlan(resultDisplay);
1239
- if (plan) {
1240
- yield emit(
1241
- createTranscriptPlanUpdate(plan.todos, this.usage, {
1242
- ...meta,
1243
- planToolCallId: callId,
1244
- todoPlanId: plan.planId
1245
- })
1246
- );
1247
- }
1248
- return;
1249
- }
1250
- yield emit(
1251
- createTranscriptToolCallResultUpdate({
1252
- toolName,
1253
- callId,
1254
- success: result?.["status"] === void 0 ? !result?.["error"] : result["status"] === "success" && !result["error"],
1255
- errorMessage: extractErrorMessage(result?.["error"]),
1256
- message: record.message?.parts,
1257
- resultDisplay,
1258
- artifacts: Array.isArray(result?.["artifacts"]) ? result["artifacts"] : void 0,
1259
- contentPrefix: this.buildToolResultContentPrefix(
1260
- resultDisplay,
1261
- record.uuid
1262
- ),
1263
- ...meta
1264
- })
1265
- );
1266
- if (isTaskExecutionDisplay(resultDisplay)) {
1267
- const usage = usageFromTaskExecution(resultDisplay);
1268
- if (Object.keys(usage).length > 0) {
1269
- this.addUsage(usage);
1270
- yield emit(createTranscriptUsageUpdate(usage, meta));
1138
+ return { provenance: "builtin" };
1139
+ }
1140
+ __name(resolveToolProvenance, "resolveToolProvenance");
1141
+ function buildToolResultContent(options) {
1142
+ const prefix = [...options.contentPrefix ?? []];
1143
+ const diff = extractDiffContent(options.resultDisplay);
1144
+ if (diff) return [...prefix, diff];
1145
+ if (options.errorMessage) {
1146
+ return [
1147
+ ...prefix,
1148
+ {
1149
+ type: "content",
1150
+ content: { type: "text", text: options.errorMessage }
1271
1151
  }
1272
- }
1152
+ ];
1273
1153
  }
1274
- *projectSystemRecord(record, emit, meta) {
1275
- if (record.subtype === "goal_state") {
1276
- const payload2 = parseGoalStateRecordPayloadV2(record.systemPayload);
1277
- if (!payload2) {
1278
- this.report(
1279
- "malformed_goal_state",
1280
- "Skipped a malformed Goal state transcript record.",
1281
- record.uuid,
1282
- "systemPayload"
1283
- );
1284
- return;
1285
- }
1286
- const bookkeepingOnly = isGoalCheckpointBookkeepingRecord({
1287
- cause: payload2.cause,
1288
- previousCause: this.goalCause,
1289
- previous: this.goalState,
1290
- next: payload2.snapshot
1154
+ const content = [...prefix];
1155
+ for (const part of options.message ?? []) {
1156
+ if (!isObjectRecord(part)) continue;
1157
+ if (typeof part["text"] === "string" && part["text"]) {
1158
+ content.push({
1159
+ type: "content",
1160
+ content: { type: "text", text: part["text"] }
1291
1161
  });
1292
- const projection = projectGoalStateToLegacy(
1293
- payload2,
1294
- this.goalState?.goal ?? null
1295
- );
1296
- this.goalState = payload2.snapshot;
1297
- this.goalCause = payload2.cause;
1298
- if (bookkeepingOnly) return;
1299
- const { type: _type, ...goalStatus } = projection.goalStatus;
1300
- yield emit(
1301
- createTranscriptMessageUpdate({
1302
- role: "assistant",
1303
- text: "",
1304
- ...meta,
1305
- extra: {
1306
- goalState: payload2.snapshot,
1307
- goalStatus,
1308
- ...projection.goalTerminal ? { goalTerminal: projection.goalTerminal } : {},
1309
- "qwen.session.recordId": record.uuid
1310
- }
1311
- })
1312
- );
1313
- return;
1314
1162
  }
1315
- if (record.subtype !== "slash_command") return;
1316
- const payload = isObjectRecord(record.systemPayload) ? record.systemPayload : void 0;
1317
- if (payload?.["phase"] !== "result") return;
1318
- const items = Array.isArray(payload["outputHistoryItems"]) ? payload["outputHistoryItems"] : [];
1319
- for (const item of items) {
1320
- const goalStatus = parseTranscriptGoalStatus(item);
1321
- if (goalStatus) {
1322
- if (goalStatus.condition.length === 0) {
1323
- this.report(
1324
- "malformed_part",
1325
- "Skipped replay of a goal card whose condition is empty.",
1326
- record.uuid,
1327
- "systemPayload.outputHistoryItems.goalStatus.condition"
1328
- );
1329
- } else if (goalStatus.kind !== "checking") {
1330
- yield emit(
1331
- createTranscriptMessageUpdate({
1332
- role: "assistant",
1333
- text: "",
1334
- ...meta,
1335
- extra: { goalStatus }
1336
- })
1337
- );
1338
- }
1339
- continue;
1340
- }
1341
- if (!isObjectRecord(item) || typeof item["text"] !== "string") continue;
1342
- yield emit(
1343
- createTranscriptMessageUpdate({
1344
- role: "assistant",
1345
- text: item["text"].replace(/\n/g, " \n"),
1346
- ...meta,
1347
- extra: { source: "slash_command" }
1348
- })
1349
- );
1163
+ const response = isObjectRecord(part["functionResponse"]) ? part["functionResponse"] : void 0;
1164
+ const payload = response && isObjectRecord(response["response"]) ? response["response"] : void 0;
1165
+ if (!payload) continue;
1166
+ try {
1167
+ const output = payload["output"];
1168
+ const error = payload["error"];
1169
+ const text = typeof output === "string" ? output : typeof error === "string" ? error : JSON.stringify(payload);
1170
+ content.push({
1171
+ type: "content",
1172
+ content: { type: "text", text }
1173
+ });
1174
+ } catch {
1350
1175
  }
1351
1176
  }
1352
- addUsage(metadata) {
1353
- this.usage.promptTokens += finiteNumber(metadata["promptTokenCount"]) ?? 0;
1354
- this.usage.candidateTokens += finiteNumber(metadata["candidatesTokenCount"]) ?? 0;
1355
- this.usage.cachedTokens += finiteNumber(metadata["cachedContentTokenCount"]) ?? 0;
1177
+ return content;
1178
+ }
1179
+ __name(buildToolResultContent, "buildToolResultContent");
1180
+ function extractDiffContent(resultDisplay) {
1181
+ if (!isObjectRecord(resultDisplay)) return null;
1182
+ if (!("fileName" in resultDisplay) || !("newContent" in resultDisplay)) {
1183
+ return null;
1356
1184
  }
1357
- correlateResultCallId(toolName, recordId) {
1358
- const candidates = [...this.pendingToolCalls.values()].filter(
1359
- (pending) => pending.toolName === toolName
1360
- );
1361
- if (candidates.length === 1) return candidates[0].callId;
1362
- this.report(
1363
- "ambiguous_tool_call_correlation",
1364
- "A tool result could not be matched to exactly one pending tool call.",
1365
- recordId
1366
- );
1367
- return this.allocateToolCallId(`qwen-replay-tool:${recordId}:result`);
1185
+ if (isTruncatedSessionDiffDisplay(resultDisplay)) {
1186
+ return {
1187
+ type: "content",
1188
+ content: {
1189
+ type: "text",
1190
+ text: buildTruncatedDiffPreviewText(resultDisplay)
1191
+ }
1192
+ };
1368
1193
  }
1369
- allocateToolCallId(candidate, reuse = false) {
1370
- if (reuse && this.pendingToolCalls.has(candidate)) {
1371
- this.usedToolCallIds.add(candidate);
1372
- return candidate;
1373
- }
1374
- if (!this.usedToolCallIds.has(candidate)) {
1375
- this.usedToolCallIds.add(candidate);
1376
- return candidate;
1194
+ return {
1195
+ type: "diff",
1196
+ path: typeof resultDisplay["fileName"] === "string" ? resultDisplay["fileName"] : "",
1197
+ oldText: typeof resultDisplay["originalContent"] === "string" ? resultDisplay["originalContent"] : "",
1198
+ newText: typeof resultDisplay["newContent"] === "string" ? resultDisplay["newContent"] : ""
1199
+ };
1200
+ }
1201
+ __name(extractDiffContent, "extractDiffContent");
1202
+ function isTruncatedSessionDiffDisplay(value) {
1203
+ return isObjectRecord(value) && value["truncatedForSession"] === true && "fileName" in value && "newContent" in value;
1204
+ }
1205
+ __name(isTruncatedSessionDiffDisplay, "isTruncatedSessionDiffDisplay");
1206
+ function buildTruncatedDiffPreviewText(display) {
1207
+ const fileName = typeof display["fileName"] === "string" ? display["fileName"] : "the edited file";
1208
+ const fileDiffLength = typeof display["fileDiffLength"] === "number" ? ` Original fileDiff length: ${display["fileDiffLength"]} chars.` : "";
1209
+ return display["fileDiffTruncated"] === true ? `Full diff omitted from saved session history for ${fileName}.${fileDiffLength}` : `Saved session preview only for ${fileName}; full original and new file contents are unavailable.`;
1210
+ }
1211
+ __name(buildTruncatedDiffPreviewText, "buildTruncatedDiffPreviewText");
1212
+ function extractToolName(record) {
1213
+ for (const part of record.message?.parts ?? []) {
1214
+ if (!isObjectRecord(part) || !isObjectRecord(part["functionResponse"])) {
1215
+ continue;
1377
1216
  }
1378
- let occurrence = 2;
1379
- while (this.usedToolCallIds.has(`${candidate}:${occurrence}`)) {
1380
- occurrence += 1;
1217
+ const name = part["functionResponse"]["name"];
1218
+ if (typeof name === "string") return name;
1219
+ }
1220
+ return "";
1221
+ }
1222
+ __name(extractToolName, "extractToolName");
1223
+ function extractToolResultCallId(record, result) {
1224
+ if (typeof result?.["callId"] === "string" && result["callId"].length > 0) {
1225
+ return result["callId"];
1226
+ }
1227
+ for (const part of record.message?.parts ?? []) {
1228
+ if (!isObjectRecord(part) || !isObjectRecord(part["functionResponse"])) {
1229
+ continue;
1381
1230
  }
1382
- const id = `${candidate}:${occurrence}`;
1383
- this.usedToolCallIds.add(id);
1384
- return id;
1231
+ const id = part["functionResponse"]["id"];
1232
+ if (typeof id === "string" && id.length > 0) return id;
1233
+ }
1234
+ return void 0;
1235
+ }
1236
+ __name(extractToolResultCallId, "extractToolResultCallId");
1237
+ function extractTodoPlanFromDisplay(value) {
1238
+ if (isObjectRecord(value) && value["type"] === "todo_list") {
1239
+ return Array.isArray(value["todos"]) ? {
1240
+ ...typeof value["planId"] === "string" ? { planId: value["planId"] } : {},
1241
+ todos: normalizeTodos(value["todos"])
1242
+ } : null;
1385
1243
  }
1386
- resolveToolMetadata(toolName, args, recordId) {
1387
- try {
1388
- return this.options.presentation?.resolveToolMetadata(toolName, args) ?? fallbackToolMetadata(toolName, args);
1389
- } catch {
1390
- this.report(
1391
- "presentation_fallback",
1392
- "Tool presentation metadata fell back to deterministic defaults.",
1393
- recordId,
1394
- void 0,
1395
- false
1396
- );
1397
- return fallbackToolMetadata(toolName, args);
1244
+ if (typeof value !== "string") return null;
1245
+ try {
1246
+ const parsed = JSON.parse(value);
1247
+ return isObjectRecord(parsed) && parsed["type"] === "todo_list" && Array.isArray(parsed["todos"]) ? {
1248
+ ...typeof parsed["planId"] === "string" ? { planId: parsed["planId"] } : {},
1249
+ todos: normalizeTodos(parsed["todos"])
1250
+ } : null;
1251
+ } catch {
1252
+ return null;
1253
+ }
1254
+ }
1255
+ __name(extractTodoPlanFromDisplay, "extractTodoPlanFromDisplay");
1256
+ function normalizeTodos(values) {
1257
+ return values.flatMap((value) => {
1258
+ if (!isObjectRecord(value) || typeof value["content"] !== "string")
1259
+ return [];
1260
+ const status = value["status"];
1261
+ if (status !== "pending" && status !== "in_progress" && status !== "completed") {
1262
+ return [];
1398
1263
  }
1264
+ return [
1265
+ {
1266
+ ...typeof value["id"] === "string" ? { id: value["id"] } : {},
1267
+ content: value["content"],
1268
+ status,
1269
+ ...Array.isArray(value["blockedBy"]) && value["blockedBy"].every((dependency) => typeof dependency === "string") ? { blockedBy: value["blockedBy"] } : {}
1270
+ }
1271
+ ];
1272
+ });
1273
+ }
1274
+ __name(normalizeTodos, "normalizeTodos");
1275
+ function isTaskExecutionDisplay(value) {
1276
+ return isObjectRecord(value) && value["type"] === "task_execution";
1277
+ }
1278
+ __name(isTaskExecutionDisplay, "isTaskExecutionDisplay");
1279
+ function usageFromTaskExecution(display) {
1280
+ const summary = isObjectRecord(display["executionSummary"]) ? display["executionSummary"] : void 0;
1281
+ if (!summary) return {};
1282
+ return {
1283
+ ...finiteNumber(summary["inputTokens"]) !== void 0 ? { promptTokenCount: summary["inputTokens"] } : {},
1284
+ ...finiteNumber(summary["outputTokens"]) !== void 0 ? { candidatesTokenCount: summary["outputTokens"] } : {},
1285
+ ...finiteNumber(summary["thoughtTokens"]) !== void 0 ? { thoughtsTokenCount: summary["thoughtTokens"] } : {},
1286
+ ...finiteNumber(summary["cachedTokens"]) !== void 0 ? { cachedContentTokenCount: summary["cachedTokens"] } : {},
1287
+ ...finiteNumber(summary["totalTokens"]) !== void 0 ? { totalTokenCount: summary["totalTokens"] } : {}
1288
+ };
1289
+ }
1290
+ __name(usageFromTaskExecution, "usageFromTaskExecution");
1291
+ function finiteNumber(value) {
1292
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1293
+ }
1294
+ __name(finiteNumber, "finiteNumber");
1295
+ function extractErrorMessage(value) {
1296
+ if (value instanceof Error) return value.message;
1297
+ if (!isObjectRecord(value)) return void 0;
1298
+ return typeof value["message"] === "string" ? value["message"] : void 0;
1299
+ }
1300
+ __name(extractErrorMessage, "extractErrorMessage");
1301
+ function dedupeStrings(values) {
1302
+ return [...new Set(values.filter((value) => value.length > 0))];
1303
+ }
1304
+ __name(dedupeStrings, "dedupeStrings");
1305
+
1306
+ // packages/cli/src/acp-integration/session/emitters/tool-call-emitter.ts
1307
+ init_esbuild_shims();
1308
+
1309
+ // packages/cli/src/acp-integration/session/emitters/base-emitter.ts
1310
+ init_esbuild_shims();
1311
+ var BaseEmitter = class {
1312
+ constructor(ctx) {
1313
+ this.ctx = ctx;
1399
1314
  }
1400
- formatGap(gap) {
1401
- try {
1402
- return this.options.presentation?.formatHistoryGap(gap) ?? "Some earlier messages are unavailable because the saved history is incomplete.";
1403
- } catch {
1404
- this.report(
1405
- "presentation_fallback",
1406
- "History gap presentation fell back to deterministic defaults.",
1407
- gap.childUuid,
1408
- void 0,
1409
- false
1410
- );
1411
- return "Some earlier messages are unavailable because the saved history is incomplete.";
1315
+ static {
1316
+ __name(this, "BaseEmitter");
1317
+ }
1318
+ /**
1319
+ * Converts an ISO timestamp string or epoch ms to epoch ms number.
1320
+ * Returns undefined if the input is not a valid timestamp.
1321
+ */
1322
+ static toEpochMs(ts) {
1323
+ if (typeof ts === "number") {
1324
+ return Number.isFinite(ts) ? ts : void 0;
1325
+ }
1326
+ if (typeof ts === "string") {
1327
+ const ms = new Date(ts).getTime();
1328
+ return Number.isFinite(ms) ? ms : void 0;
1412
1329
  }
1330
+ return void 0;
1413
1331
  }
1414
- buildToolResultContentPrefix(resultDisplay, recordId) {
1415
- try {
1416
- return this.options.presentation?.buildToolResultContentPrefix?.(
1417
- resultDisplay
1418
- ) ?? defaultToolResultContentPrefix(resultDisplay);
1419
- } catch {
1420
- this.report(
1421
- "presentation_fallback",
1422
- "Tool result content presentation fell back to deterministic defaults.",
1423
- recordId,
1424
- void 0,
1425
- false
1426
- );
1427
- return defaultToolResultContentPrefix(resultDisplay);
1332
+ /**
1333
+ * Sends a session update to the ACP client.
1334
+ * If a message rewriter is configured, updates pass through it first
1335
+ * (original messages are sent as-is, rewritten versions are appended).
1336
+ */
1337
+ async sendUpdate(update) {
1338
+ if (this.ctx.messageRewriter) {
1339
+ return this.ctx.messageRewriter.interceptUpdate(update);
1428
1340
  }
1341
+ return this.ctx.sendUpdate(update);
1429
1342
  }
1430
- report(code, message, recordId, path2, affectsCompleteness = true) {
1431
- this.options.onDiagnostic?.({
1432
- code,
1433
- severity: affectsCompleteness ? "warning" : "info",
1434
- message,
1435
- affectsCompleteness,
1436
- ...recordId ? { recordId } : {},
1437
- ...path2 ? { path: path2 } : {}
1438
- });
1343
+ /**
1344
+ * Gets the session ID.
1345
+ */
1346
+ get sessionId() {
1347
+ return this.ctx.sessionId;
1439
1348
  }
1440
1349
  };
1441
- function parseTranscriptGoalStatus(value) {
1442
- if (!isObjectRecord(value) || value["type"] !== "goal_status") {
1443
- return void 0;
1350
+
1351
+ // packages/cli/src/acp-integration/session/emitters/PlanEmitter.ts
1352
+ init_esbuild_shims();
1353
+ var PlanEmitter = class extends BaseEmitter {
1354
+ static {
1355
+ __name(this, "PlanEmitter");
1444
1356
  }
1445
- const kind = value["kind"];
1446
- const condition = value["condition"];
1447
- if (typeof kind !== "string" || !TRANSCRIPT_GOAL_STATUS_KINDS.has(kind) || typeof condition !== "string") {
1448
- return void 0;
1357
+ /**
1358
+ * Emits a plan update with the given todo items.
1359
+ *
1360
+ * @param plan - Plan identity and todo items to send as plan entries
1361
+ */
1362
+ async emitPlan(plan, sourceCallId) {
1363
+ const cumulative = this.ctx.cumulativeUsage;
1364
+ await this.sendUpdate(
1365
+ createTranscriptPlanUpdate(plan.todos, cumulative, {
1366
+ planToolCallId: sourceCallId,
1367
+ todoPlanId: plan.planId
1368
+ })
1369
+ );
1449
1370
  }
1450
- const iterations = finiteNumber(value["iterations"]);
1451
- const setAt = finiteNumber(value["setAt"]);
1452
- const durationMs = finiteNumber(value["durationMs"]);
1453
- const lastReason = typeof value["lastReason"] === "string" ? value["lastReason"] : void 0;
1454
- return {
1455
- kind,
1456
- condition,
1457
- ...iterations !== void 0 ? { iterations } : {},
1458
- ...setAt !== void 0 ? { setAt } : {},
1459
- ...durationMs !== void 0 ? { durationMs } : {},
1460
- ...lastReason !== void 0 ? { lastReason } : {}
1461
- };
1462
- }
1463
- __name(parseTranscriptGoalStatus, "parseTranscriptGoalStatus");
1464
- function defaultToolResultContentPrefix(resultDisplay) {
1465
- if (!isObjectRecord(resultDisplay) || resultDisplay["type"] !== "vision_bridge_notice" || typeof resultDisplay["summary"] !== "string" || typeof resultDisplay["notice"] !== "string") {
1466
- return [];
1371
+ /**
1372
+ * Extracts todos from tool result display or args.
1373
+ * Tries multiple sources in priority order:
1374
+ * 1. Result display object with type 'todo_list'
1375
+ * 2. Result display as JSON string
1376
+ * 3. Args with 'todos' array when no result display is available
1377
+ *
1378
+ * @param resultDisplay - The tool result display (object, string, or undefined)
1379
+ * @param args - The tool call arguments (fallback source)
1380
+ * @returns Plan snapshot if found, null otherwise
1381
+ */
1382
+ extractPlan(resultDisplay, args) {
1383
+ const plan = extractTranscriptTodoPlan(resultDisplay, args);
1384
+ if (!plan) return null;
1385
+ return {
1386
+ ...plan.planId ? { planId: plan.planId } : {},
1387
+ todos: plan.todos.map((todo, index) => ({
1388
+ id: todo.id ?? String(index),
1389
+ content: todo.content,
1390
+ status: todo.status,
1391
+ ...todo.blockedBy ? { blockedBy: [...todo.blockedBy] } : {}
1392
+ }))
1393
+ };
1467
1394
  }
1468
- return [
1469
- {
1470
- type: "content",
1471
- content: {
1472
- type: "text",
1473
- text: `${resultDisplay["summary"]}
1474
- ${resultDisplay["notice"]}`
1475
- }
1476
- }
1477
- ];
1395
+ };
1396
+
1397
+ // packages/cli/src/acp-integration/session/types.ts
1398
+ init_esbuild_shims();
1399
+ function hasFullSessionContext(context) {
1400
+ return "config" in context;
1478
1401
  }
1479
- __name(defaultToolResultContentPrefix, "defaultToolResultContentPrefix");
1480
- function parseInitialState(value, onDiagnostic) {
1481
- const empty = {
1482
- v: 1,
1483
- pendingToolCalls: [],
1484
- cumulativeUsage: emptyUsage()
1485
- };
1486
- if (value === void 0) return empty;
1487
- if (!isObjectRecord(value)) {
1488
- throw new TypeError("Invalid transcript replay state.");
1402
+ __name(hasFullSessionContext, "hasFullSessionContext");
1403
+
1404
+ // packages/cli/src/acp-integration/session/emitters/tool-call-emitter.ts
1405
+ var KIND_MAP = {
1406
+ ["read" /* Read */]: "read",
1407
+ ["edit" /* Edit */]: "edit",
1408
+ ["delete" /* Delete */]: "delete",
1409
+ ["move" /* Move */]: "move",
1410
+ ["search" /* Search */]: "search",
1411
+ ["execute" /* Execute */]: "execute",
1412
+ ["think" /* Think */]: "think",
1413
+ ["fetch" /* Fetch */]: "fetch",
1414
+ // ACP defines no 'agent' ToolKind (verified through @agentclientprotocol/sdk
1415
+ // 0.25.1). The daemon's ClientSideConnection Zod-validates every session/update
1416
+ // and session/request_permission from the `qwen --acp` child before fanning out
1417
+ // to SSE clients, so emitting 'agent' is rejected at that hop and the frame is
1418
+ // dropped. Map the internal Kind.Agent to 'other' on the wire to stay
1419
+ // protocol-valid; dedicated agent UI is delivered out-of-band (via _meta.toolName)
1420
+ // in a follow-up rather than via a kind the protocol can't carry.
1421
+ ["agent" /* Agent */]: "other",
1422
+ ["other" /* Other */]: "other"
1423
+ };
1424
+ var ToolCallEmitter = class _ToolCallEmitter extends BaseEmitter {
1425
+ static {
1426
+ __name(this, "ToolCallEmitter");
1489
1427
  }
1490
- if ("v" in value && value["v"] !== 1) {
1491
- throw new TypeError("Unsupported transcript replay state version.");
1428
+ planEmitter;
1429
+ preparedCallIds = /* @__PURE__ */ new Set();
1430
+ constructor(ctx) {
1431
+ super(ctx);
1432
+ this.planEmitter = new PlanEmitter(ctx);
1492
1433
  }
1493
- const rawPending = Array.isArray(value["pendingToolCalls"]) ? value["pendingToolCalls"] : [];
1494
- const pendingToolCalls = rawPending.flatMap(
1495
- (pending) => {
1496
- if (!isObjectRecord(pending) || typeof pending["callId"] !== "string" || typeof pending["toolName"] !== "string" || typeof pending["sourceRecordId"] !== "string") {
1497
- onDiagnostic?.({
1498
- code: "invalid_replay_state",
1499
- severity: "warning",
1500
- message: "Dropped a malformed pending tool call from replay state.",
1501
- affectsCompleteness: true
1502
- });
1503
- return [];
1504
- }
1505
- return [
1506
- {
1507
- callId: pending["callId"],
1508
- toolName: pending["toolName"],
1509
- sourceRecordId: pending["sourceRecordId"],
1510
- ...typeof pending["sourceTimestamp"] === "string" ? { sourceTimestamp: pending["sourceTimestamp"] } : {}
1434
+ /**
1435
+ * Emits a tool call start event.
1436
+ *
1437
+ * @param params - Tool call start parameters
1438
+ * @returns true if event was emitted, false if skipped (e.g., TodoWriteTool)
1439
+ */
1440
+ async emitStart(params) {
1441
+ if (this.isTodoWriteTool(params.toolName)) {
1442
+ return false;
1443
+ }
1444
+ if (params.phase === "preparing" && this.preparedCallIds.has(params.callId)) {
1445
+ return false;
1446
+ }
1447
+ const { title, locations, kind } = this.resolveToolMetadata(
1448
+ params.toolName,
1449
+ params.args
1450
+ );
1451
+ const provenance = _ToolCallEmitter.resolveToolProvenance(
1452
+ params.toolName,
1453
+ params.subagentMeta
1454
+ );
1455
+ const updatesPreparedCall = params.phase !== "preparing" && this.preparedCallIds.delete(params.callId);
1456
+ await this.sendUpdate(
1457
+ createTranscriptToolCallStartUpdate({
1458
+ toolName: params.toolName,
1459
+ callId: params.callId,
1460
+ status: params.status || "pending",
1461
+ args: params.args,
1462
+ metadata: { title, locations, kind },
1463
+ timestamp: params.timestamp,
1464
+ asUpdate: updatesPreparedCall,
1465
+ extra: {
1466
+ ...params.phase ? { phase: params.phase } : {},
1467
+ ...params.subagentMeta,
1468
+ provenance: provenance.provenance,
1469
+ ...provenance.serverId ? { serverId: provenance.serverId } : {}
1511
1470
  }
1512
- ];
1471
+ })
1472
+ );
1473
+ if (params.phase === "preparing") {
1474
+ this.preparedCallIds.add(params.callId);
1513
1475
  }
1514
- );
1515
- const rawUsage = value.cumulativeUsage;
1516
- const usage = isObjectRecord(rawUsage) ? rawUsage : {};
1517
- const validUsage = finiteNumber(usage["promptTokens"]) !== void 0 && finiteNumber(usage["cachedTokens"]) !== void 0 && finiteNumber(usage["candidateTokens"]) !== void 0 && finiteNumber(usage["apiTimeMs"]) !== void 0;
1518
- if (!validUsage) {
1519
- onDiagnostic?.({
1520
- code: "invalid_replay_state",
1521
- severity: "warning",
1522
- message: "Reset invalid cumulative usage in transcript replay state.",
1523
- affectsCompleteness: true
1524
- });
1476
+ return true;
1525
1477
  }
1526
- const rawGoalState = value["goalState"];
1527
- const goalState = rawGoalState === void 0 ? void 0 : parseGoalSnapshotV2(rawGoalState);
1528
- if (rawGoalState !== void 0 && !goalState) {
1529
- onDiagnostic?.({
1530
- code: "invalid_replay_state",
1531
- severity: "warning",
1532
- message: "Dropped a malformed Goal state from replay state.",
1533
- affectsCompleteness: true
1478
+ /**
1479
+ * Emits a terminal frame when a prepared tool call is discarded before
1480
+ * execution. TodoWrite remains represented exclusively by plan updates.
1481
+ *
1482
+ * @param callId - ID of the prepared tool call
1483
+ * @param toolName - Name of the prepared tool
1484
+ */
1485
+ async emitPreparationDiscarded(callId, toolName) {
1486
+ if (this.isTodoWriteTool(toolName)) return;
1487
+ this.preparedCallIds.delete(callId);
1488
+ const provenance = _ToolCallEmitter.resolveToolProvenance(toolName);
1489
+ await this.sendUpdate({
1490
+ sessionUpdate: "tool_call_update",
1491
+ toolCallId: callId,
1492
+ status: "failed",
1493
+ content: [],
1494
+ _meta: {
1495
+ toolName,
1496
+ phase: "preparing",
1497
+ preparationDiscarded: true,
1498
+ provenance: provenance.provenance,
1499
+ ...provenance.serverId ? { serverId: provenance.serverId } : {}
1500
+ }
1534
1501
  });
1535
1502
  }
1536
- const rawGoalCause = value["goalCause"];
1537
- const goalCause = rawGoalCause === void 0 ? void 0 : parseGoalStateCause(rawGoalCause);
1538
- if (rawGoalCause !== void 0 && !goalCause) {
1539
- onDiagnostic?.({
1540
- code: "invalid_replay_state",
1541
- severity: "warning",
1542
- message: "Dropped a malformed Goal cause from replay state.",
1543
- affectsCompleteness: true
1544
- });
1503
+ /**
1504
+ * Emits a tool call result event.
1505
+ * Handles TodoWriteTool specially by routing to plan updates.
1506
+ *
1507
+ * @param params - Tool call result parameters
1508
+ */
1509
+ async emitResult(params) {
1510
+ if (this.isTodoWriteTool(params.toolName)) {
1511
+ if (params.subagentMeta) return;
1512
+ if (!params.success) return;
1513
+ const plan = this.planEmitter.extractPlan(
1514
+ params.resultDisplay,
1515
+ params.args
1516
+ );
1517
+ if (plan && (plan.todos.length > 0 || params.args && Array.isArray(params.args["todos"]))) {
1518
+ await this.planEmitter.emitPlan(plan, params.callId);
1519
+ }
1520
+ return;
1521
+ }
1522
+ this.preparedCallIds.delete(params.callId);
1523
+ const provenance = _ToolCallEmitter.resolveToolProvenance(
1524
+ params.toolName,
1525
+ params.subagentMeta
1526
+ );
1527
+ await this.sendUpdate(
1528
+ createTranscriptToolCallResultUpdate({
1529
+ toolName: params.toolName,
1530
+ callId: params.callId,
1531
+ success: params.success,
1532
+ message: params.message,
1533
+ resultDisplay: params.resultDisplay,
1534
+ errorMessage: params.error?.message,
1535
+ artifacts: params.artifacts,
1536
+ contentPrefix: buildToolResultContentPrefix(params.resultDisplay),
1537
+ timestamp: params.timestamp,
1538
+ extra: {
1539
+ ...params.subagentMeta,
1540
+ provenance: provenance.provenance,
1541
+ ...provenance.serverId ? { serverId: provenance.serverId } : {}
1542
+ }
1543
+ })
1544
+ );
1545
1545
  }
1546
- return {
1547
- v: 1,
1548
- pendingToolCalls,
1549
- cumulativeUsage: validUsage ? {
1550
- promptTokens: usage["promptTokens"],
1551
- cachedTokens: usage["cachedTokens"],
1552
- candidateTokens: usage["candidateTokens"],
1553
- apiTimeMs: usage["apiTimeMs"]
1554
- } : emptyUsage(),
1555
- ...goalState ? { goalState } : {},
1556
- ...goalCause ? { goalCause } : {}
1557
- };
1558
- }
1559
- __name(parseInitialState, "parseInitialState");
1560
- function emptyUsage() {
1561
- return {
1562
- promptTokens: 0,
1563
- cachedTokens: 0,
1564
- candidateTokens: 0,
1565
- apiTimeMs: 0
1566
- };
1567
- }
1568
- __name(emptyUsage, "emptyUsage");
1569
- function fallbackToolMetadata(toolName, args) {
1570
- const description = typeof args["description"] === "string" ? args["description"].trim() : "";
1571
- return {
1572
- title: description ? `${toolName}: ${description}` : toolName,
1573
- locations: [],
1574
- kind: "other"
1575
- };
1576
- }
1577
- __name(fallbackToolMetadata, "fallbackToolMetadata");
1578
- function resolveToolProvenance(toolName) {
1579
- if (toolName.startsWith("mcp__")) {
1580
- const parts = toolName.split("__");
1581
- if (parts.length >= 3 && parts[1]) {
1582
- return { provenance: "mcp", serverId: parts[1] };
1546
+ /**
1547
+ * Emits a tool call error event.
1548
+ * Use this for explicit error handling when not using emitResult.
1549
+ *
1550
+ * @param callId - The tool call ID
1551
+ * @param toolName - The tool name
1552
+ * @param error - The error that occurred
1553
+ * @param subagentMeta - Optional subagent metadata
1554
+ */
1555
+ async emitError(callId, toolName, error, subagentMeta) {
1556
+ this.preparedCallIds.delete(callId);
1557
+ const provenance = _ToolCallEmitter.resolveToolProvenance(
1558
+ toolName,
1559
+ subagentMeta
1560
+ );
1561
+ await this.sendUpdate(
1562
+ createTranscriptToolCallResultUpdate({
1563
+ toolName,
1564
+ callId,
1565
+ success: false,
1566
+ errorMessage: error.message,
1567
+ extra: {
1568
+ ...subagentMeta,
1569
+ provenance: provenance.provenance,
1570
+ ...provenance.serverId ? { serverId: provenance.serverId } : {}
1571
+ }
1572
+ })
1573
+ );
1574
+ }
1575
+ /**
1576
+ * Resolve a tool's provenance for UI dispatch on tool_call events.
1577
+ * The SDK reads `_meta.
1578
+ * provenance` + `_meta.serverId` to render builtin / MCP-server-badge /
1579
+ * subagent-block differently. Without this stamping, the SDK falls
1580
+ * back to string-matching the toolName which can't reliably
1581
+ * distinguish builtin from subagent.
1582
+ *
1583
+ * Resolution rules:
1584
+ * - `subagentMeta` present → `'subagent'` (a Task tool / Codex
1585
+ * subagent / etc. wrapping its own tool calls)
1586
+ * - toolName matches `mcp__<server>__<tool>` → `'mcp'` with
1587
+ * `serverId: <server>`. Naming convention from
1588
+ * `packages/core/src/tools/mcp-tool.ts` in the
1589
+ * `@qwen-code/qwen-code-core` package — mirrors the SDK's same
1590
+ * heuristic fallback so SDK consumers stay consistent with
1591
+ * daemon classification.
1592
+ * - everything else → `'builtin'`
1593
+ *
1594
+ * Static + pure so it can be unit-tested without an emitter
1595
+ * instance. Exported via `ToolCallEmitter.resolveToolProvenance`.
1596
+ */
1597
+ static resolveToolProvenance(toolName, subagentMeta) {
1598
+ if (subagentMeta !== void 0) {
1599
+ return { provenance: "subagent" };
1583
1600
  }
1584
- }
1585
- return { provenance: "builtin" };
1586
- }
1587
- __name(resolveToolProvenance, "resolveToolProvenance");
1588
- function buildToolResultContent(options) {
1589
- const prefix = [...options.contentPrefix ?? []];
1590
- const diff = extractDiffContent(options.resultDisplay);
1591
- if (diff) return [...prefix, diff];
1592
- if (options.errorMessage) {
1593
- return [
1594
- ...prefix,
1595
- {
1596
- type: "content",
1597
- content: { type: "text", text: options.errorMessage }
1601
+ if (toolName.startsWith("mcp__")) {
1602
+ const parts = toolName.split("__");
1603
+ if (parts.length >= 3 && parts[1] && parts[1].length > 0) {
1604
+ return { provenance: "mcp", serverId: parts[1] };
1598
1605
  }
1599
- ];
1606
+ }
1607
+ return { provenance: "builtin" };
1600
1608
  }
1601
- const content = [...prefix];
1602
- for (const part of options.message ?? []) {
1603
- if (!isObjectRecord(part)) continue;
1604
- if (typeof part["text"] === "string" && part["text"]) {
1605
- content.push({
1606
- type: "content",
1607
- content: { type: "text", text: part["text"] }
1608
- });
1609
+ // ==================== Public Utilities ====================
1610
+ /**
1611
+ * Checks if a tool name is the TodoWriteTool.
1612
+ * Exposed for external use in components that need to check this.
1613
+ */
1614
+ isTodoWriteTool(toolName) {
1615
+ return toolName === ToolNames.TODO_WRITE;
1616
+ }
1617
+ /**
1618
+ * Checks if a tool name is the ExitPlanModeTool.
1619
+ */
1620
+ isExitPlanModeTool(toolName) {
1621
+ return toolName === ToolNames.EXIT_PLAN_MODE;
1622
+ }
1623
+ /**
1624
+ * Checks if a tool name is the EnterPlanModeTool.
1625
+ */
1626
+ isEnterPlanModeTool(toolName) {
1627
+ return toolName === ToolNames.ENTER_PLAN_MODE;
1628
+ }
1629
+ /**
1630
+ * Resolves tool metadata from the registry.
1631
+ * Falls back to defaults if tool not found or build fails.
1632
+ *
1633
+ * @param toolName - Name of the tool
1634
+ * @param args - Tool call arguments (used to build invocation)
1635
+ */
1636
+ resolveToolMetadata(toolName, args) {
1637
+ if (!hasFullSessionContext(this.ctx)) {
1638
+ const description = typeof args?.["description"] === "string" ? args["description"].trim() : "";
1639
+ return {
1640
+ title: description ? `${toolName}: ${description}` : toolName,
1641
+ locations: [],
1642
+ kind: "other"
1643
+ };
1609
1644
  }
1610
- const response = isObjectRecord(part["functionResponse"]) ? part["functionResponse"] : void 0;
1611
- const payload = response && isObjectRecord(response["response"]) ? response["response"] : void 0;
1612
- if (!payload) continue;
1613
- try {
1614
- const output = payload["output"];
1615
- const error = payload["error"];
1616
- const text = typeof output === "string" ? output : typeof error === "string" ? error : JSON.stringify(payload);
1617
- content.push({
1618
- type: "content",
1619
- content: { type: "text", text }
1620
- });
1621
- } catch {
1645
+ const toolRegistry = this.ctx.config.getToolRegistry();
1646
+ const tool = toolRegistry.getTool(toolName);
1647
+ let title = tool?.displayName ?? toolName;
1648
+ let locations = [];
1649
+ let kind = "other";
1650
+ if (tool && args) {
1651
+ try {
1652
+ const invocation = tool.build(args);
1653
+ title = `${title}: ${invocation.getDescription()}`;
1654
+ locations = invocation.toolLocations().map((loc) => ({
1655
+ path: loc.path,
1656
+ line: loc.line ?? null
1657
+ }));
1658
+ kind = this.mapToolKind(tool.kind, toolName);
1659
+ } catch {
1660
+ if (typeof args["description"] === "string") {
1661
+ title = `${title}: ${args["description"]}`;
1662
+ }
1663
+ if (tool.kind) {
1664
+ kind = this.mapToolKind(tool.kind, toolName);
1665
+ }
1666
+ }
1622
1667
  }
1668
+ return { title, locations, kind };
1623
1669
  }
1624
- return content;
1625
- }
1626
- __name(buildToolResultContent, "buildToolResultContent");
1627
- function extractDiffContent(resultDisplay) {
1628
- if (!isObjectRecord(resultDisplay)) return null;
1629
- if (!("fileName" in resultDisplay) || !("newContent" in resultDisplay)) {
1630
- return null;
1670
+ /**
1671
+ * Maps core Tool Kind enum to ACP ToolKind string literals.
1672
+ *
1673
+ * @param kind - The core Kind enum value
1674
+ * @param toolName - Optional tool name to handle special cases like exit_plan_mode
1675
+ */
1676
+ mapToolKind(kind, toolName) {
1677
+ if (toolName && (this.isExitPlanModeTool(toolName) || this.isEnterPlanModeTool(toolName))) {
1678
+ return "switch_mode";
1679
+ }
1680
+ return KIND_MAP[kind] ?? "other";
1631
1681
  }
1632
- if (isTruncatedSessionDiffDisplay(resultDisplay)) {
1633
- return {
1682
+ };
1683
+ function buildToolResultContentPrefix(resultDisplay) {
1684
+ if (!isVisionBridgeNoticeDisplay(resultDisplay)) return [];
1685
+ return [
1686
+ {
1634
1687
  type: "content",
1635
1688
  content: {
1636
1689
  type: "text",
1637
- text: buildTruncatedDiffPreviewText(resultDisplay)
1690
+ text: sanitizeTerminalText(
1691
+ formatVisionBridgeNoticeDisplay(resultDisplay)
1692
+ )
1638
1693
  }
1639
- };
1640
- }
1641
- return {
1642
- type: "diff",
1643
- path: typeof resultDisplay["fileName"] === "string" ? resultDisplay["fileName"] : "",
1644
- oldText: typeof resultDisplay["originalContent"] === "string" ? resultDisplay["originalContent"] : "",
1645
- newText: typeof resultDisplay["newContent"] === "string" ? resultDisplay["newContent"] : ""
1646
- };
1647
- }
1648
- __name(extractDiffContent, "extractDiffContent");
1649
- function isTruncatedSessionDiffDisplay(value) {
1650
- return isObjectRecord(value) && value["truncatedForSession"] === true && "fileName" in value && "newContent" in value;
1651
- }
1652
- __name(isTruncatedSessionDiffDisplay, "isTruncatedSessionDiffDisplay");
1653
- function buildTruncatedDiffPreviewText(display) {
1654
- const fileName = typeof display["fileName"] === "string" ? display["fileName"] : "the edited file";
1655
- const fileDiffLength = typeof display["fileDiffLength"] === "number" ? ` Original fileDiff length: ${display["fileDiffLength"]} chars.` : "";
1656
- return display["fileDiffTruncated"] === true ? `Full diff omitted from saved session history for ${fileName}.${fileDiffLength}` : `Saved session preview only for ${fileName}; full original and new file contents are unavailable.`;
1657
- }
1658
- __name(buildTruncatedDiffPreviewText, "buildTruncatedDiffPreviewText");
1659
- function extractToolName(record) {
1660
- for (const part of record.message?.parts ?? []) {
1661
- if (!isObjectRecord(part) || !isObjectRecord(part["functionResponse"])) {
1662
- continue;
1663
- }
1664
- const name = part["functionResponse"]["name"];
1665
- if (typeof name === "string") return name;
1666
- }
1667
- return "";
1668
- }
1669
- __name(extractToolName, "extractToolName");
1670
- function extractToolResultCallId(record, result) {
1671
- if (typeof result?.["callId"] === "string" && result["callId"].length > 0) {
1672
- return result["callId"];
1673
- }
1674
- for (const part of record.message?.parts ?? []) {
1675
- if (!isObjectRecord(part) || !isObjectRecord(part["functionResponse"])) {
1676
- continue;
1677
- }
1678
- const id = part["functionResponse"]["id"];
1679
- if (typeof id === "string" && id.length > 0) return id;
1680
- }
1681
- return void 0;
1682
- }
1683
- __name(extractToolResultCallId, "extractToolResultCallId");
1684
- function extractTodoPlanFromDisplay(value) {
1685
- if (isObjectRecord(value) && value["type"] === "todo_list") {
1686
- return Array.isArray(value["todos"]) ? {
1687
- ...typeof value["planId"] === "string" ? { planId: value["planId"] } : {},
1688
- todos: normalizeTodos(value["todos"])
1689
- } : null;
1690
- }
1691
- if (typeof value !== "string") return null;
1692
- try {
1693
- const parsed = JSON.parse(value);
1694
- return isObjectRecord(parsed) && parsed["type"] === "todo_list" && Array.isArray(parsed["todos"]) ? {
1695
- ...typeof parsed["planId"] === "string" ? { planId: parsed["planId"] } : {},
1696
- todos: normalizeTodos(parsed["todos"])
1697
- } : null;
1698
- } catch {
1699
- return null;
1700
- }
1701
- }
1702
- __name(extractTodoPlanFromDisplay, "extractTodoPlanFromDisplay");
1703
- function normalizeTodos(values) {
1704
- return values.flatMap((value) => {
1705
- if (!isObjectRecord(value) || typeof value["content"] !== "string")
1706
- return [];
1707
- const status = value["status"];
1708
- if (status !== "pending" && status !== "in_progress" && status !== "completed") {
1709
- return [];
1710
1694
  }
1711
- return [
1712
- {
1713
- ...typeof value["id"] === "string" ? { id: value["id"] } : {},
1714
- content: value["content"],
1715
- status,
1716
- ...Array.isArray(value["blockedBy"]) && value["blockedBy"].every((dependency) => typeof dependency === "string") ? { blockedBy: value["blockedBy"] } : {}
1717
- }
1718
- ];
1719
- });
1720
- }
1721
- __name(normalizeTodos, "normalizeTodos");
1722
- function isTaskExecutionDisplay(value) {
1723
- return isObjectRecord(value) && value["type"] === "task_execution";
1724
- }
1725
- __name(isTaskExecutionDisplay, "isTaskExecutionDisplay");
1726
- function usageFromTaskExecution(display) {
1727
- const summary = isObjectRecord(display["executionSummary"]) ? display["executionSummary"] : void 0;
1728
- if (!summary) return {};
1729
- return {
1730
- ...finiteNumber(summary["inputTokens"]) !== void 0 ? { promptTokenCount: summary["inputTokens"] } : {},
1731
- ...finiteNumber(summary["outputTokens"]) !== void 0 ? { candidatesTokenCount: summary["outputTokens"] } : {},
1732
- ...finiteNumber(summary["thoughtTokens"]) !== void 0 ? { thoughtsTokenCount: summary["thoughtTokens"] } : {},
1733
- ...finiteNumber(summary["cachedTokens"]) !== void 0 ? { cachedContentTokenCount: summary["cachedTokens"] } : {},
1734
- ...finiteNumber(summary["totalTokens"]) !== void 0 ? { totalTokenCount: summary["totalTokens"] } : {}
1735
- };
1736
- }
1737
- __name(usageFromTaskExecution, "usageFromTaskExecution");
1738
- function finiteNumber(value) {
1739
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1740
- }
1741
- __name(finiteNumber, "finiteNumber");
1742
- function extractErrorMessage(value) {
1743
- if (value instanceof Error) return value.message;
1744
- if (!isObjectRecord(value)) return void 0;
1745
- return typeof value["message"] === "string" ? value["message"] : void 0;
1746
- }
1747
- __name(extractErrorMessage, "extractErrorMessage");
1748
- function dedupeStrings(values) {
1749
- return [...new Set(values.filter((value) => value.length > 0))];
1695
+ ];
1750
1696
  }
1751
- __name(dedupeStrings, "dedupeStrings");
1752
-
1753
- // packages/cli/src/acp-integration/session/emitters/PlanEmitter.ts
1754
- init_esbuild_shims();
1697
+ __name(buildToolResultContentPrefix, "buildToolResultContentPrefix");
1755
1698
 
1756
- // packages/cli/src/acp-integration/session/emitters/base-emitter.ts
1757
- init_esbuild_shims();
1758
- var BaseEmitter = class {
1699
+ // packages/cli/src/acp-integration/session/history-replayer.ts
1700
+ var HistoryReplayer = class {
1759
1701
  constructor(ctx) {
1760
1702
  this.ctx = ctx;
1703
+ this.toolCallEmitter = new ToolCallEmitter(ctx);
1704
+ this.machine = this.createMachine();
1761
1705
  }
1762
1706
  static {
1763
- __name(this, "BaseEmitter");
1707
+ __name(this, "HistoryReplayer");
1764
1708
  }
1765
- /**
1766
- * Converts an ISO timestamp string or epoch ms to epoch ms number.
1767
- * Returns undefined if the input is not a valid timestamp.
1768
- */
1769
- static toEpochMs(ts) {
1770
- if (typeof ts === "number") {
1771
- return Number.isFinite(ts) ? ts : void 0;
1709
+ toolCallEmitter;
1710
+ machine;
1711
+ async replay(records, gaps, options = {}) {
1712
+ try {
1713
+ if (options.goalBootstrap) {
1714
+ const update = {
1715
+ sessionUpdate: "agent_message_chunk",
1716
+ content: { type: "text", text: "" },
1717
+ _meta: {
1718
+ ...options.goalBootstrap.goalState ? { goalState: options.goalBootstrap.goalState } : {},
1719
+ goalStatus: options.goalBootstrap.goalStatus
1720
+ }
1721
+ };
1722
+ await this.sendUpdate(update);
1723
+ }
1724
+ await this.replayPage(records, {
1725
+ finalizeDangling: true,
1726
+ gaps,
1727
+ ...options.initialGoalState ? { goalState: options.initialGoalState } : {},
1728
+ ...options.initialGoalCause ? { goalCause: options.initialGoalCause } : {}
1729
+ });
1730
+ } finally {
1731
+ this.setActiveRecordId(null);
1772
1732
  }
1773
- if (typeof ts === "string") {
1774
- const ms = new Date(ts).getTime();
1775
- return Number.isFinite(ms) ? ms : void 0;
1733
+ }
1734
+ static v2GoalBootstrap(rawGoalState, rawGoalCause) {
1735
+ const goalState = parseGoalSnapshotV2(rawGoalState);
1736
+ const goalCause = parseGoalStateCause(rawGoalCause);
1737
+ if (!goalState?.goal || goalState.goal.status !== "active" || !goalCause) {
1738
+ return void 0;
1776
1739
  }
1777
- return void 0;
1740
+ const projection = projectGoalStateToLegacy({
1741
+ v: 2,
1742
+ cause: goalCause,
1743
+ snapshot: goalState
1744
+ });
1745
+ const { type: _type, kind, ...goalStatus } = projection.goalStatus;
1746
+ if (kind !== "set" && kind !== "checking") {
1747
+ return void 0;
1748
+ }
1749
+ return { goalStatus: { ...goalStatus, kind }, goalState };
1778
1750
  }
1779
- /**
1780
- * Sends a session update to the ACP client.
1781
- * If a message rewriter is configured, updates pass through it first
1782
- * (original messages are sent as-is, rewritten versions are appended).
1783
- */
1784
- async sendUpdate(update) {
1785
- if (this.ctx.messageRewriter) {
1786
- return this.ctx.messageRewriter.interceptUpdate(update);
1751
+ async replayPage(records, options = {}) {
1752
+ this.machine = this.createMachine(options);
1753
+ let replayError;
1754
+ try {
1755
+ for (const record of records) {
1756
+ for (const emission of this.machine.project(record)) {
1757
+ this.setActiveRecordId(
1758
+ emission.sourceRecordId,
1759
+ emission.sourceTimestamp
1760
+ );
1761
+ await this.sendUpdate(emission.update);
1762
+ }
1763
+ }
1764
+ } catch (error) {
1765
+ replayError = error;
1787
1766
  }
1788
- return this.ctx.sendUpdate(update);
1767
+ let danglingError;
1768
+ if (options.finalizeDangling === true) {
1769
+ for (const emission of this.machine.finalize()) {
1770
+ this.setActiveRecordId(
1771
+ emission.sourceRecordId,
1772
+ emission.sourceTimestamp
1773
+ );
1774
+ try {
1775
+ await this.sendUpdate(emission.update);
1776
+ } catch (error) {
1777
+ danglingError ??= error;
1778
+ }
1779
+ }
1780
+ }
1781
+ const replay = this.machine.snapshot();
1782
+ this.copyCumulativeUsage(replay);
1783
+ const state = {
1784
+ pendingToolCalls: options.finalizeDangling === true ? [] : replay.pendingToolCalls.map(toLegacyPendingToolCall),
1785
+ replay
1786
+ };
1787
+ this.setActiveRecordId(null);
1788
+ if (replayError && danglingError) {
1789
+ throw new AggregateError(
1790
+ [replayError, danglingError],
1791
+ "Replay and dangling-cleanup both failed"
1792
+ );
1793
+ }
1794
+ if (replayError) throw replayError;
1795
+ if (danglingError) throw danglingError;
1796
+ return state;
1789
1797
  }
1790
- /**
1791
- * Gets the session ID.
1792
- */
1793
- get sessionId() {
1794
- return this.ctx.sessionId;
1798
+ getPendingToolCalls() {
1799
+ return this.machine.snapshot().pendingToolCalls.map(toLegacyPendingToolCall);
1795
1800
  }
1796
- };
1797
-
1798
- // packages/cli/src/acp-integration/session/emitters/PlanEmitter.ts
1799
- var PlanEmitter = class extends BaseEmitter {
1800
- static {
1801
- __name(this, "PlanEmitter");
1801
+ getReplayState() {
1802
+ return this.machine.snapshot();
1802
1803
  }
1803
- /**
1804
- * Emits a plan update with the given todo items.
1805
- *
1806
- * @param plan - Plan identity and todo items to send as plan entries
1807
- */
1808
- async emitPlan(plan, sourceCallId) {
1804
+ createMachine(options = {}) {
1809
1805
  const cumulative = this.ctx.cumulativeUsage;
1810
- await this.sendUpdate(
1811
- createTranscriptPlanUpdate(plan.todos, cumulative, {
1812
- planToolCallId: sourceCallId,
1813
- todoPlanId: plan.planId
1814
- })
1815
- );
1806
+ const initialState = {
1807
+ v: 1,
1808
+ pendingToolCalls: (options.pendingToolCalls ?? []).map(
1809
+ toPendingTranscriptToolCall
1810
+ ),
1811
+ cumulativeUsage: cumulative ? { ...cumulative } : {
1812
+ promptTokens: 0,
1813
+ cachedTokens: 0,
1814
+ candidateTokens: 0,
1815
+ apiTimeMs: 0
1816
+ },
1817
+ ...options.goalState ? { goalState: options.goalState } : {},
1818
+ ...options.goalCause ? { goalCause: options.goalCause } : {}
1819
+ };
1820
+ return createTranscriptReplayMachine({
1821
+ initialState,
1822
+ gaps: options.gaps,
1823
+ presentation: this.presentationAdapter(),
1824
+ onDiagnostic: /* @__PURE__ */ __name((diagnostic) => {
1825
+ if (diagnostic.code === "malformed_part" && diagnostic.path === "systemPayload.outputHistoryItems.goalStatus.condition") {
1826
+ writeStderrLineSafe(`qwen: ${diagnostic.message}`);
1827
+ }
1828
+ }, "onDiagnostic")
1829
+ });
1816
1830
  }
1817
- /**
1818
- * Extracts todos from tool result display or args.
1819
- * Tries multiple sources in priority order:
1820
- * 1. Result display object with type 'todo_list'
1821
- * 2. Result display as JSON string
1822
- * 3. Args with 'todos' array when no result display is available
1823
- *
1824
- * @param resultDisplay - The tool result display (object, string, or undefined)
1825
- * @param args - The tool call arguments (fallback source)
1826
- * @returns Plan snapshot if found, null otherwise
1827
- */
1828
- extractPlan(resultDisplay, args) {
1829
- const plan = extractTranscriptTodoPlan(resultDisplay, args);
1830
- if (!plan) return null;
1831
+ presentationAdapter() {
1831
1832
  return {
1832
- ...plan.planId ? { planId: plan.planId } : {},
1833
- todos: plan.todos.map((todo, index) => ({
1834
- id: todo.id ?? String(index),
1835
- content: todo.content,
1836
- status: todo.status,
1837
- ...todo.blockedBy ? { blockedBy: [...todo.blockedBy] } : {}
1838
- }))
1833
+ resolveToolMetadata: /* @__PURE__ */ __name((toolName, args) => this.toolCallEmitter.resolveToolMetadata(toolName, { ...args }), "resolveToolMetadata"),
1834
+ formatHistoryGap: /* @__PURE__ */ __name((gap) => formatHistoryGapNotice(gap), "formatHistoryGap"),
1835
+ buildToolResultContentPrefix
1839
1836
  };
1840
1837
  }
1841
- };
1842
-
1843
- // packages/cli/src/acp-integration/session/emitters/tool-call-emitter.ts
1844
- init_esbuild_shims();
1845
-
1846
- // packages/cli/src/acp-integration/session/types.ts
1847
- init_esbuild_shims();
1848
- function hasFullSessionContext(context) {
1849
- return "config" in context;
1850
- }
1851
- __name(hasFullSessionContext, "hasFullSessionContext");
1852
-
1853
- // packages/cli/src/acp-integration/session/emitters/tool-call-emitter.ts
1854
- var KIND_MAP = {
1855
- ["read" /* Read */]: "read",
1856
- ["edit" /* Edit */]: "edit",
1857
- ["delete" /* Delete */]: "delete",
1858
- ["move" /* Move */]: "move",
1859
- ["search" /* Search */]: "search",
1860
- ["execute" /* Execute */]: "execute",
1861
- ["think" /* Think */]: "think",
1862
- ["fetch" /* Fetch */]: "fetch",
1863
- // ACP defines no 'agent' ToolKind (verified through @agentclientprotocol/sdk
1864
- // 0.25.1). The daemon's ClientSideConnection Zod-validates every session/update
1865
- // and session/request_permission from the `qwen --acp` child before fanning out
1866
- // to SSE clients, so emitting 'agent' is rejected at that hop and the frame is
1867
- // dropped. Map the internal Kind.Agent to 'other' on the wire to stay
1868
- // protocol-valid; dedicated agent UI is delivered out-of-band (via _meta.toolName)
1869
- // in a follow-up rather than via a kind the protocol can't carry.
1870
- ["agent" /* Agent */]: "other",
1871
- ["other" /* Other */]: "other"
1872
- };
1873
- var ToolCallEmitter = class _ToolCallEmitter extends BaseEmitter {
1874
- static {
1875
- __name(this, "ToolCallEmitter");
1838
+ async sendUpdate(update) {
1839
+ if (this.ctx.messageRewriter) {
1840
+ await this.ctx.messageRewriter.interceptUpdate(update);
1841
+ return;
1842
+ }
1843
+ await this.ctx.sendUpdate(update);
1876
1844
  }
1877
- planEmitter;
1878
- preparedCallIds = /* @__PURE__ */ new Set();
1879
- constructor(ctx) {
1880
- super(ctx);
1881
- this.planEmitter = new PlanEmitter(ctx);
1845
+ copyCumulativeUsage(state) {
1846
+ const cumulative = this.ctx.cumulativeUsage;
1847
+ if (!cumulative) return;
1848
+ cumulative.promptTokens = state.cumulativeUsage.promptTokens;
1849
+ cumulative.cachedTokens = state.cumulativeUsage.cachedTokens;
1850
+ cumulative.candidateTokens = state.cumulativeUsage.candidateTokens;
1851
+ cumulative.apiTimeMs = state.cumulativeUsage.apiTimeMs;
1882
1852
  }
1883
- /**
1884
- * Emits a tool call start event.
1885
- *
1886
- * @param params - Tool call start parameters
1887
- * @returns true if event was emitted, false if skipped (e.g., TodoWriteTool)
1888
- */
1889
- async emitStart(params) {
1890
- if (this.isTodoWriteTool(params.toolName)) {
1891
- return false;
1892
- }
1893
- if (params.phase === "preparing" && this.preparedCallIds.has(params.callId)) {
1894
- return false;
1895
- }
1896
- const { title, locations, kind } = this.resolveToolMetadata(
1897
- params.toolName,
1898
- params.args
1899
- );
1900
- const provenance = _ToolCallEmitter.resolveToolProvenance(
1901
- params.toolName,
1902
- params.subagentMeta
1903
- );
1904
- const updatesPreparedCall = params.phase !== "preparing" && this.preparedCallIds.delete(params.callId);
1905
- await this.sendUpdate(
1906
- createTranscriptToolCallStartUpdate({
1907
- toolName: params.toolName,
1908
- callId: params.callId,
1909
- status: params.status || "pending",
1910
- args: params.args,
1911
- metadata: { title, locations, kind },
1912
- timestamp: params.timestamp,
1913
- asUpdate: updatesPreparedCall,
1914
- extra: {
1915
- ...params.phase ? { phase: params.phase } : {},
1916
- ...params.subagentMeta,
1917
- provenance: provenance.provenance,
1918
- ...provenance.serverId ? { serverId: provenance.serverId } : {}
1853
+ setActiveRecordId(recordId, timestamp) {
1854
+ this.ctx.setActiveRecordId?.(recordId, timestamp);
1855
+ }
1856
+ };
1857
+ function toPendingTranscriptToolCall(pending) {
1858
+ return {
1859
+ callId: pending.callId,
1860
+ toolName: pending.toolName,
1861
+ sourceRecordId: pending.recordId,
1862
+ ...pending.timestamp ? { sourceTimestamp: pending.timestamp } : {}
1863
+ };
1864
+ }
1865
+ __name(toPendingTranscriptToolCall, "toPendingTranscriptToolCall");
1866
+ function toLegacyPendingToolCall(pending) {
1867
+ return {
1868
+ callId: pending.callId,
1869
+ toolName: pending.toolName,
1870
+ recordId: pending.sourceRecordId,
1871
+ ...pending.sourceTimestamp ? { timestamp: pending.sourceTimestamp } : {}
1872
+ };
1873
+ }
1874
+ __name(toLegacyPendingToolCall, "toLegacyPendingToolCall");
1875
+
1876
+ // packages/cli/src/services/setup-github.ts
1877
+ init_esbuild_shims();
1878
+ import { promises as fsp } from "node:fs";
1879
+ import * as path from "node:path";
1880
+
1881
+ // packages/cli/src/utils/gitUtils.ts
1882
+ init_esbuild_shims();
1883
+ import * as childProcess from "node:child_process";
1884
+ var debugLogger = createDebugLogger("GIT");
1885
+ async function runGit(args, opts = {}) {
1886
+ return await new Promise((resolve2, reject) => {
1887
+ childProcess.execFile(
1888
+ "git",
1889
+ args,
1890
+ {
1891
+ encoding: "utf-8",
1892
+ ...opts.cwd ? { cwd: opts.cwd } : {}
1893
+ },
1894
+ (err, stdout) => {
1895
+ if (err) {
1896
+ reject(err);
1897
+ return;
1919
1898
  }
1920
- })
1899
+ resolve2(String(stdout ?? "").trim());
1900
+ }
1921
1901
  );
1922
- if (params.phase === "preparing") {
1923
- this.preparedCallIds.add(params.callId);
1924
- }
1902
+ });
1903
+ }
1904
+ __name(runGit, "runGit");
1905
+ var isGitHubRepositoryAsync = /* @__PURE__ */ __name(async (opts = {}) => {
1906
+ try {
1907
+ const remotes = await runGit(["remote", "-v"], opts);
1908
+ return remotes.split("\n").some((line) => {
1909
+ const remoteUrl = line.trim().split(/\s+/)[1];
1910
+ return remoteUrl ? isGitHubRemoteUrl(remoteUrl) : false;
1911
+ });
1912
+ } catch (_error) {
1913
+ debugLogger.debug(`Failed to get git remote:`, _error);
1914
+ return false;
1915
+ }
1916
+ }, "isGitHubRepositoryAsync");
1917
+ function isGitHubRemoteUrl(remoteUrl) {
1918
+ if (remoteUrl.startsWith("git@github.com:")) {
1925
1919
  return true;
1926
1920
  }
1927
- /**
1928
- * Emits a terminal frame when a prepared tool call is discarded before
1929
- * execution. TodoWrite remains represented exclusively by plan updates.
1930
- *
1931
- * @param callId - ID of the prepared tool call
1932
- * @param toolName - Name of the prepared tool
1933
- */
1934
- async emitPreparationDiscarded(callId, toolName) {
1935
- if (this.isTodoWriteTool(toolName)) return;
1936
- this.preparedCallIds.delete(callId);
1937
- const provenance = _ToolCallEmitter.resolveToolProvenance(toolName);
1938
- await this.sendUpdate({
1939
- sessionUpdate: "tool_call_update",
1940
- toolCallId: callId,
1941
- status: "failed",
1942
- content: [],
1943
- _meta: {
1944
- toolName,
1945
- phase: "preparing",
1946
- preparationDiscarded: true,
1947
- provenance: provenance.provenance,
1948
- ...provenance.serverId ? { serverId: provenance.serverId } : {}
1949
- }
1950
- });
1921
+ if (remoteUrl.startsWith("git@")) {
1922
+ return false;
1951
1923
  }
1952
- /**
1953
- * Emits a tool call result event.
1954
- * Handles TodoWriteTool specially by routing to plan updates.
1955
- *
1956
- * @param params - Tool call result parameters
1957
- */
1958
- async emitResult(params) {
1959
- if (this.isTodoWriteTool(params.toolName)) {
1960
- if (params.subagentMeta) return;
1961
- if (!params.success) return;
1962
- const plan = this.planEmitter.extractPlan(
1963
- params.resultDisplay,
1964
- params.args
1924
+ try {
1925
+ return new URL(remoteUrl).hostname === "github.com";
1926
+ } catch {
1927
+ return false;
1928
+ }
1929
+ }
1930
+ __name(isGitHubRemoteUrl, "isGitHubRemoteUrl");
1931
+ var getGitRepoRootAsync = /* @__PURE__ */ __name(async (opts = {}) => {
1932
+ const gitRepoRoot = await runGit(["rev-parse", "--show-toplevel"], opts);
1933
+ if (!gitRepoRoot) {
1934
+ throw new Error(`Git repo returned empty value`);
1935
+ }
1936
+ return gitRepoRoot;
1937
+ }, "getGitRepoRootAsync");
1938
+ var getLatestGitHubRelease = /* @__PURE__ */ __name(async (proxy) => {
1939
+ try {
1940
+ const controller = new AbortController();
1941
+ const endpoint = `https://api.github.com/repos/QwenLM/qwen-code-action/releases/latest`;
1942
+ const dispatcher = proxy ? new (await loadUndici()).ProxyAgent(proxy) : void 0;
1943
+ const response = await fetch(endpoint, {
1944
+ method: "GET",
1945
+ headers: {
1946
+ Accept: "application/vnd.github+json",
1947
+ "Content-Type": "application/json",
1948
+ "X-GitHub-Api-Version": "2022-11-28"
1949
+ },
1950
+ dispatcher,
1951
+ signal: AbortSignal.any([AbortSignal.timeout(3e4), controller.signal])
1952
+ });
1953
+ if (!response.ok) {
1954
+ throw new Error(
1955
+ `Invalid response code: ${response.status} - ${response.statusText}`
1965
1956
  );
1966
- if (plan && (plan.todos.length > 0 || params.args && Array.isArray(params.args["todos"]))) {
1967
- await this.planEmitter.emitPlan(plan, params.callId);
1968
- }
1969
- return;
1970
1957
  }
1971
- this.preparedCallIds.delete(params.callId);
1972
- const provenance = _ToolCallEmitter.resolveToolProvenance(
1973
- params.toolName,
1974
- params.subagentMeta
1958
+ const releaseTag = (await response.json()).tag_name;
1959
+ if (!releaseTag) {
1960
+ throw new Error(`Response did not include tag_name field`);
1961
+ }
1962
+ return releaseTag;
1963
+ } catch (_error) {
1964
+ debugLogger.debug(
1965
+ `Failed to determine latest qwen-code-action release:`,
1966
+ _error
1975
1967
  );
1976
- await this.sendUpdate(
1977
- createTranscriptToolCallResultUpdate({
1978
- toolName: params.toolName,
1979
- callId: params.callId,
1980
- success: params.success,
1981
- message: params.message,
1982
- resultDisplay: params.resultDisplay,
1983
- errorMessage: params.error?.message,
1984
- artifacts: params.artifacts,
1985
- contentPrefix: buildToolResultContentPrefix(params.resultDisplay),
1986
- timestamp: params.timestamp,
1987
- extra: {
1988
- ...params.subagentMeta,
1989
- provenance: provenance.provenance,
1990
- ...provenance.serverId ? { serverId: provenance.serverId } : {}
1991
- }
1992
- })
1968
+ throw new Error(
1969
+ `Unable to determine the latest qwen-code-action release on GitHub.`
1993
1970
  );
1994
1971
  }
1995
- /**
1996
- * Emits a tool call error event.
1997
- * Use this for explicit error handling when not using emitResult.
1998
- *
1999
- * @param callId - The tool call ID
2000
- * @param toolName - The tool name
2001
- * @param error - The error that occurred
2002
- * @param subagentMeta - Optional subagent metadata
2003
- */
2004
- async emitError(callId, toolName, error, subagentMeta) {
2005
- this.preparedCallIds.delete(callId);
2006
- const provenance = _ToolCallEmitter.resolveToolProvenance(
2007
- toolName,
2008
- subagentMeta
1972
+ }, "getLatestGitHubRelease");
1973
+ async function getGitHubRepoInfoAsync(opts = {}) {
1974
+ return parseGitHubRepoInfo(
1975
+ await runGit(["remote", "get-url", "origin"], opts)
1976
+ );
1977
+ }
1978
+ __name(getGitHubRepoInfoAsync, "getGitHubRepoInfoAsync");
1979
+ function parseGitHubRepoInfo(remoteUrl) {
1980
+ let urlToParse = remoteUrl;
1981
+ if (remoteUrl.startsWith("git@github.com:")) {
1982
+ urlToParse = remoteUrl.replace("git@github.com:", "");
1983
+ } else if (remoteUrl.startsWith("git@")) {
1984
+ throw new Error(
1985
+ `Owner & repo could not be extracted from remote URL: ${remoteUrl}`
2009
1986
  );
2010
- await this.sendUpdate(
2011
- createTranscriptToolCallResultUpdate({
2012
- toolName,
2013
- callId,
2014
- success: false,
2015
- errorMessage: error.message,
2016
- extra: {
2017
- ...subagentMeta,
2018
- provenance: provenance.provenance,
2019
- ...provenance.serverId ? { serverId: provenance.serverId } : {}
2020
- }
2021
- })
1987
+ }
1988
+ let parsedUrl;
1989
+ try {
1990
+ parsedUrl = new URL(urlToParse, "https://github.com");
1991
+ } catch {
1992
+ throw new Error(
1993
+ `Owner & repo could not be extracted from remote URL: ${remoteUrl}`
2022
1994
  );
2023
1995
  }
2024
- /**
2025
- * Resolve a tool's provenance for UI dispatch on tool_call events.
2026
- * The SDK reads `_meta.
2027
- * provenance` + `_meta.serverId` to render builtin / MCP-server-badge /
2028
- * subagent-block differently. Without this stamping, the SDK falls
2029
- * back to string-matching the toolName which can't reliably
2030
- * distinguish builtin from subagent.
2031
- *
2032
- * Resolution rules:
2033
- * - `subagentMeta` present → `'subagent'` (a Task tool / Codex
2034
- * subagent / etc. wrapping its own tool calls)
2035
- * - toolName matches `mcp__<server>__<tool>` → `'mcp'` with
2036
- * `serverId: <server>`. Naming convention from
2037
- * `packages/core/src/tools/mcp-tool.ts` in the
2038
- * `@qwen-code/qwen-code-core` package — mirrors the SDK's same
2039
- * heuristic fallback so SDK consumers stay consistent with
2040
- * daemon classification.
2041
- * - everything else → `'builtin'`
2042
- *
2043
- * Static + pure so it can be unit-tested without an emitter
2044
- * instance. Exported via `ToolCallEmitter.resolveToolProvenance`.
2045
- */
2046
- static resolveToolProvenance(toolName, subagentMeta) {
2047
- if (subagentMeta !== void 0) {
2048
- return { provenance: "subagent" };
2049
- }
2050
- if (toolName.startsWith("mcp__")) {
2051
- const parts = toolName.split("__");
2052
- if (parts.length >= 3 && parts[1] && parts[1].length > 0) {
2053
- return { provenance: "mcp", serverId: parts[1] };
2054
- }
2055
- }
2056
- return { provenance: "builtin" };
1996
+ if (parsedUrl.hostname !== "github.com") {
1997
+ throw new Error(
1998
+ `Owner & repo could not be extracted from remote URL: ${remoteUrl}`
1999
+ );
2057
2000
  }
2058
- // ==================== Public Utilities ====================
2059
- /**
2060
- * Checks if a tool name is the TodoWriteTool.
2061
- * Exposed for external use in components that need to check this.
2062
- */
2063
- isTodoWriteTool(toolName) {
2064
- return toolName === ToolNames.TODO_WRITE;
2001
+ const parts = parsedUrl.pathname.split("/").filter((part) => part !== "");
2002
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
2003
+ throw new Error(
2004
+ `Owner & repo could not be extracted from remote URL: ${remoteUrl}`
2005
+ );
2065
2006
  }
2066
- /**
2067
- * Checks if a tool name is the ExitPlanModeTool.
2068
- */
2069
- isExitPlanModeTool(toolName) {
2070
- return toolName === ToolNames.EXIT_PLAN_MODE;
2007
+ return { owner: parts[0], repo: parts[1].replace(/\.git$/, "") };
2008
+ }
2009
+ __name(parseGitHubRepoInfo, "parseGitHubRepoInfo");
2010
+
2011
+ // packages/cli/src/services/setup-github.ts
2012
+ var debugLogger2 = createDebugLogger("SETUP_GITHUB");
2013
+ var GITHUB_WORKFLOW_PATHS = [
2014
+ "qwen-dispatch/qwen-dispatch.yml",
2015
+ "qwen-assistant/qwen-invoke.yml",
2016
+ "issue-triage/qwen-triage.yml",
2017
+ "issue-triage/qwen-scheduled-triage.yml",
2018
+ "pr-review/qwen-review.yml"
2019
+ ];
2020
+ var GITIGNORE_ENTRIES = [".qwen/", "gha-creds-*.json"];
2021
+ var MAX_WORKFLOW_DOWNLOAD_BYTES = 5 * 1024 * 1024;
2022
+ var SetupGithubError = class extends Error {
2023
+ static {
2024
+ __name(this, "SetupGithubError");
2071
2025
  }
2072
- /**
2073
- * Checks if a tool name is the EnterPlanModeTool.
2074
- */
2075
- isEnterPlanModeTool(toolName) {
2076
- return toolName === ToolNames.ENTER_PLAN_MODE;
2026
+ code;
2027
+ status;
2028
+ partial;
2029
+ partialResult;
2030
+ constructor(code, message, status, partialResult) {
2031
+ super(message);
2032
+ this.name = "SetupGithubError";
2033
+ this.code = code;
2034
+ this.status = status;
2035
+ this.partial = partialResult !== void 0;
2036
+ this.partialResult = partialResult;
2077
2037
  }
2078
- /**
2079
- * Resolves tool metadata from the registry.
2080
- * Falls back to defaults if tool not found or build fails.
2081
- *
2082
- * @param toolName - Name of the tool
2083
- * @param args - Tool call arguments (used to build invocation)
2084
- */
2085
- resolveToolMetadata(toolName, args) {
2086
- if (!hasFullSessionContext(this.ctx)) {
2087
- const description = typeof args?.["description"] === "string" ? args["description"].trim() : "";
2088
- return {
2089
- title: description ? `${toolName}: ${description}` : toolName,
2090
- locations: [],
2091
- kind: "other"
2092
- };
2093
- }
2094
- const toolRegistry = this.ctx.config.getToolRegistry();
2095
- const tool = toolRegistry.getTool(toolName);
2096
- let title = tool?.displayName ?? toolName;
2097
- let locations = [];
2098
- let kind = "other";
2099
- if (tool && args) {
2100
- try {
2101
- const invocation = tool.build(args);
2102
- title = `${title}: ${invocation.getDescription()}`;
2103
- locations = invocation.toolLocations().map((loc) => ({
2104
- path: loc.path,
2105
- line: loc.line ?? null
2106
- }));
2107
- kind = this.mapToolKind(tool.kind, toolName);
2108
- } catch {
2109
- if (typeof args["description"] === "string") {
2110
- title = `${title}: ${args["description"]}`;
2111
- }
2112
- if (tool.kind) {
2113
- kind = this.mapToolKind(tool.kind, toolName);
2114
- }
2038
+ };
2039
+ function isWorkspaceGenerationClosed(error) {
2040
+ return Boolean(
2041
+ error && typeof error === "object" && "code" in error && error.code === "workspace_generation_closed"
2042
+ );
2043
+ }
2044
+ __name(isWorkspaceGenerationClosed, "isWorkspaceGenerationClosed");
2045
+ var nodeFileOps = {
2046
+ assertCanWrite() {
2047
+ },
2048
+ async ensureWorkflowDirectory(gitRepoRoot) {
2049
+ await fsp.mkdir(path.join(gitRepoRoot, ".github", "workflows"), {
2050
+ recursive: true
2051
+ });
2052
+ },
2053
+ async writeTextFile(gitRepoRoot, relativePath, content) {
2054
+ const target = path.join(gitRepoRoot, relativePath);
2055
+ await fsp.writeFile(target, content, { mode: 420 });
2056
+ return { sizeBytes: Buffer.byteLength(content, "utf8") };
2057
+ },
2058
+ async readTextFile(gitRepoRoot, relativePath) {
2059
+ try {
2060
+ return await fsp.readFile(path.join(gitRepoRoot, relativePath), "utf8");
2061
+ } catch (error) {
2062
+ if (error.code === "ENOENT") {
2063
+ return void 0;
2115
2064
  }
2065
+ throw error;
2116
2066
  }
2117
- return { title, locations, kind };
2118
- }
2119
- /**
2120
- * Maps core Tool Kind enum to ACP ToolKind string literals.
2121
- *
2122
- * @param kind - The core Kind enum value
2123
- * @param toolName - Optional tool name to handle special cases like exit_plan_mode
2124
- */
2125
- mapToolKind(kind, toolName) {
2126
- if (toolName && (this.isExitPlanModeTool(toolName) || this.isEnterPlanModeTool(toolName))) {
2127
- return "switch_mode";
2128
- }
2129
- return KIND_MAP[kind] ?? "other";
2130
2067
  }
2131
2068
  };
2132
- function buildToolResultContentPrefix(resultDisplay) {
2133
- if (!isVisionBridgeNoticeDisplay(resultDisplay)) return [];
2134
- return [
2135
- {
2136
- type: "content",
2137
- content: {
2138
- type: "text",
2139
- text: sanitizeTerminalText(
2140
- formatVisionBridgeNoticeDisplay(resultDisplay)
2141
- )
2142
- }
2069
+ async function setupGithub(options = {}) {
2070
+ const cwd = options.cwd ?? process.cwd();
2071
+ const fileOps = options.fileOps ?? nodeFileOps;
2072
+ if (!await isGitHubRepositoryAsync({ cwd })) {
2073
+ throw new SetupGithubError(
2074
+ "github_repository_not_found",
2075
+ "Unable to determine the GitHub repository. /setup-github must be run from a git repository.",
2076
+ 400
2077
+ );
2078
+ }
2079
+ let gitRepoRoot;
2080
+ try {
2081
+ gitRepoRoot = await getGitRepoRootAsync({ cwd });
2082
+ } catch (error) {
2083
+ debugLogger2.debug("Failed to get git repo root:", error);
2084
+ throw new SetupGithubError(
2085
+ "github_repository_not_found",
2086
+ "Unable to determine the GitHub repository. /setup-github must be run from a git repository.",
2087
+ 400
2088
+ );
2089
+ }
2090
+ if (options.workspaceRoot) {
2091
+ const [gitRootReal, workspaceReal] = await Promise.all([
2092
+ realpathOrResolve(gitRepoRoot),
2093
+ realpathOrResolve(options.workspaceRoot)
2094
+ ]);
2095
+ if (gitRootReal !== workspaceReal) {
2096
+ throw new SetupGithubError(
2097
+ "github_git_root_mismatch",
2098
+ "The Git repository root must match the daemon workspace root.",
2099
+ 400
2100
+ );
2143
2101
  }
2144
- ];
2145
- }
2146
- __name(buildToolResultContentPrefix, "buildToolResultContentPrefix");
2147
-
2148
- // packages/cli/src/acp-integration/session/history-replayer.ts
2149
- init_esbuild_shims();
2150
- var HistoryReplayer = class {
2151
- constructor(ctx) {
2152
- this.ctx = ctx;
2153
- this.toolCallEmitter = new ToolCallEmitter(ctx);
2154
- this.machine = this.createMachine();
2155
2102
  }
2156
- static {
2157
- __name(this, "HistoryReplayer");
2103
+ fileOps.assertCanWrite?.();
2104
+ let releaseTag;
2105
+ try {
2106
+ releaseTag = await getLatestGitHubRelease(options.proxy);
2107
+ } catch (error) {
2108
+ writeStderrLine(
2109
+ `qwen setup-github: failed to determine latest qwen-code-action release: ${error instanceof Error ? error.message : String(error)}`
2110
+ );
2111
+ debugLogger2.debug(
2112
+ "Failed to determine latest qwen-code-action release:",
2113
+ error
2114
+ );
2115
+ throw new SetupGithubError(
2116
+ "github_release_lookup_failed",
2117
+ "Unable to determine the latest qwen-code-action release on GitHub.",
2118
+ 502
2119
+ );
2158
2120
  }
2159
- toolCallEmitter;
2160
- machine;
2161
- async replay(records, gaps) {
2162
- try {
2163
- await this.replayPage(records, {
2164
- finalizeDangling: true,
2165
- gaps
2166
- });
2167
- } finally {
2168
- this.setActiveRecordId(null);
2121
+ const readmeUrl = `https://github.com/QwenLM/qwen-code-action/blob/${releaseTag}/README.md#quick-start`;
2122
+ const secretsUrl = await resolveSecretsUrl(cwd);
2123
+ const downloads = await downloadWorkflows({
2124
+ releaseTag,
2125
+ proxy: options.proxy,
2126
+ abortSignal: options.abortSignal,
2127
+ fetchImpl: options.fetchImpl ?? fetch
2128
+ });
2129
+ const result = {
2130
+ kind: "github_setup",
2131
+ workspaceCwd: options.workspaceRoot ?? gitRepoRoot,
2132
+ gitRepoRoot,
2133
+ releaseTag,
2134
+ readmeUrl,
2135
+ ...secretsUrl ? { secretsUrl } : {},
2136
+ workflows: [],
2137
+ gitignore: { path: ".gitignore", status: "skipped" },
2138
+ warnings: []
2139
+ };
2140
+ result.gitignore = await updateGitignore(gitRepoRoot, fileOps);
2141
+ if (result.gitignore.status === "failed") {
2142
+ result.warnings.push("Failed to update .gitignore.");
2143
+ }
2144
+ try {
2145
+ await fileOps.ensureWorkflowDirectory(gitRepoRoot);
2146
+ for (const workflow of downloads) {
2147
+ const relativePath = path.posix.join(
2148
+ ".github",
2149
+ "workflows",
2150
+ path.posix.basename(workflow.sourcePath)
2151
+ );
2152
+ try {
2153
+ const write = await fileOps.writeTextFile(
2154
+ gitRepoRoot,
2155
+ relativePath,
2156
+ workflow.content
2157
+ );
2158
+ result.workflows.push({
2159
+ sourcePath: workflow.sourcePath,
2160
+ path: relativePath,
2161
+ status: "written",
2162
+ sizeBytes: write.sizeBytes
2163
+ });
2164
+ } catch (error) {
2165
+ if (isWorkspaceGenerationClosed(error)) throw error;
2166
+ result.partial = true;
2167
+ result.workflows.push({
2168
+ sourcePath: workflow.sourcePath,
2169
+ path: relativePath,
2170
+ status: "failed",
2171
+ error: error instanceof Error ? error.message : String(error)
2172
+ });
2173
+ throw new SetupGithubError(
2174
+ "github_workflow_write_failed",
2175
+ `Unable to write ${relativePath}.`,
2176
+ 500,
2177
+ result
2178
+ );
2179
+ }
2169
2180
  }
2181
+ } catch (error) {
2182
+ if (isWorkspaceGenerationClosed(error)) throw error;
2183
+ if (error instanceof SetupGithubError) throw error;
2184
+ throw new SetupGithubError(
2185
+ "github_workflow_write_failed",
2186
+ "Unable to create .github/workflows.",
2187
+ 500,
2188
+ result
2189
+ );
2170
2190
  }
2171
- async replayPage(records, options = {}) {
2172
- this.machine = this.createMachine(options);
2173
- let replayError;
2174
- try {
2175
- for (const record of records) {
2176
- for (const emission of this.machine.project(record)) {
2177
- this.setActiveRecordId(
2178
- emission.sourceRecordId,
2179
- emission.sourceTimestamp
2180
- );
2181
- await this.sendUpdate(emission.update);
2182
- }
2183
- }
2184
- } catch (error) {
2185
- replayError = error;
2191
+ return result;
2192
+ }
2193
+ __name(setupGithub, "setupGithub");
2194
+ async function updateGitignore(gitRepoRoot, fileOps = nodeFileOps) {
2195
+ try {
2196
+ const existingContent = await fileOps.readTextFile(
2197
+ gitRepoRoot,
2198
+ ".gitignore"
2199
+ );
2200
+ if (existingContent === void 0) {
2201
+ const content = GITIGNORE_ENTRIES.join("\n") + "\n";
2202
+ await fileOps.writeTextFile(gitRepoRoot, ".gitignore", content);
2203
+ return {
2204
+ path: ".gitignore",
2205
+ status: "created",
2206
+ added: [...GITIGNORE_ENTRIES]
2207
+ };
2186
2208
  }
2187
- let danglingError;
2188
- if (options.finalizeDangling === true) {
2189
- for (const emission of this.machine.finalize()) {
2190
- this.setActiveRecordId(
2191
- emission.sourceRecordId,
2192
- emission.sourceTimestamp
2193
- );
2194
- try {
2195
- await this.sendUpdate(emission.update);
2196
- } catch (error) {
2197
- danglingError ??= error;
2198
- }
2199
- }
2209
+ const missingEntries = GITIGNORE_ENTRIES.filter(
2210
+ (entry) => !existingContent.split(/\r?\n/).some((line) => line.split("#")[0].trim() === entry)
2211
+ );
2212
+ if (missingEntries.length === 0) {
2213
+ return { path: ".gitignore", status: "unchanged" };
2200
2214
  }
2201
- const replay = this.machine.snapshot();
2202
- this.copyCumulativeUsage(replay);
2203
- const state = {
2204
- pendingToolCalls: options.finalizeDangling === true ? [] : replay.pendingToolCalls.map(toLegacyPendingToolCall),
2205
- replay
2215
+ const nextContent = existingContent + "\n" + missingEntries.join("\n") + "\n";
2216
+ await fileOps.writeTextFile(gitRepoRoot, ".gitignore", nextContent);
2217
+ return {
2218
+ path: ".gitignore",
2219
+ status: "updated",
2220
+ added: missingEntries
2206
2221
  };
2207
- this.setActiveRecordId(null);
2208
- if (replayError && danglingError) {
2209
- throw new AggregateError(
2210
- [replayError, danglingError],
2211
- "Replay and dangling-cleanup both failed"
2212
- );
2213
- }
2214
- if (replayError) throw replayError;
2215
- if (danglingError) throw danglingError;
2216
- return state;
2217
- }
2218
- getPendingToolCalls() {
2219
- return this.machine.snapshot().pendingToolCalls.map(toLegacyPendingToolCall);
2220
- }
2221
- getReplayState() {
2222
- return this.machine.snapshot();
2223
- }
2224
- createMachine(options = {}) {
2225
- const cumulative = this.ctx.cumulativeUsage;
2226
- const initialState = {
2227
- v: 1,
2228
- pendingToolCalls: (options.pendingToolCalls ?? []).map(
2229
- toPendingTranscriptToolCall
2230
- ),
2231
- cumulativeUsage: cumulative ? { ...cumulative } : {
2232
- promptTokens: 0,
2233
- cachedTokens: 0,
2234
- candidateTokens: 0,
2235
- apiTimeMs: 0
2236
- },
2237
- ...options.goalState ? { goalState: options.goalState } : {},
2238
- ...options.goalCause ? { goalCause: options.goalCause } : {}
2222
+ } catch (error) {
2223
+ if (isWorkspaceGenerationClosed(error)) throw error;
2224
+ debugLogger2.debug("Failed to update .gitignore:", error);
2225
+ return {
2226
+ path: ".gitignore",
2227
+ status: "failed",
2228
+ error: error instanceof Error ? error.message : String(error)
2239
2229
  };
2240
- return createTranscriptReplayMachine({
2241
- initialState,
2242
- gaps: options.gaps,
2243
- presentation: this.presentationAdapter(),
2244
- onDiagnostic: /* @__PURE__ */ __name((diagnostic) => {
2245
- if (diagnostic.code === "malformed_part" && diagnostic.path === "systemPayload.outputHistoryItems.goalStatus.condition") {
2246
- writeStderrLineSafe(`qwen: ${diagnostic.message}`);
2230
+ }
2231
+ }
2232
+ __name(updateGitignore, "updateGitignore");
2233
+ async function downloadWorkflows(options) {
2234
+ const internalAbort = new AbortController();
2235
+ try {
2236
+ const dispatcher = options.proxy ? new (await loadUndici()).ProxyAgent(options.proxy) : void 0;
2237
+ return await Promise.all(
2238
+ GITHUB_WORKFLOW_PATHS.map(async (workflow) => {
2239
+ const endpoint = `https://raw.githubusercontent.com/QwenLM/qwen-code-action/refs/tags/${options.releaseTag}/examples/workflows/${workflow}`;
2240
+ const response = await options.fetchImpl(endpoint, {
2241
+ method: "GET",
2242
+ dispatcher,
2243
+ signal: AbortSignal.any([
2244
+ AbortSignal.timeout(3e4),
2245
+ internalAbort.signal,
2246
+ ...options.abortSignal ? [options.abortSignal] : []
2247
+ ])
2248
+ });
2249
+ if (!response.ok) {
2250
+ throw new Error(
2251
+ `Invalid response code downloading ${endpoint}: ${response.status} - ${response.statusText}`
2252
+ );
2247
2253
  }
2248
- }, "onDiagnostic")
2249
- });
2254
+ return {
2255
+ sourcePath: workflow,
2256
+ content: await readResponseTextWithLimit(response, workflow)
2257
+ };
2258
+ })
2259
+ );
2260
+ } catch (error) {
2261
+ internalAbort.abort();
2262
+ const message = error instanceof Error ? error.message : String(error);
2263
+ debugLogger2.debug("Failed to download qwen-code-action workflows:", error);
2264
+ throw new SetupGithubError(
2265
+ "github_workflow_download_failed",
2266
+ `Unable to download qwen-code-action workflows from GitHub. ${message}`,
2267
+ 502
2268
+ );
2250
2269
  }
2251
- presentationAdapter() {
2252
- return {
2253
- resolveToolMetadata: /* @__PURE__ */ __name((toolName, args) => this.toolCallEmitter.resolveToolMetadata(toolName, { ...args }), "resolveToolMetadata"),
2254
- formatHistoryGap: /* @__PURE__ */ __name((gap) => formatHistoryGapNotice(gap), "formatHistoryGap"),
2255
- buildToolResultContentPrefix
2256
- };
2270
+ }
2271
+ __name(downloadWorkflows, "downloadWorkflows");
2272
+ async function readResponseTextWithLimit(response, sourcePath) {
2273
+ const contentLength = response.headers.get("content-length");
2274
+ if (contentLength !== null) {
2275
+ const parsedLength = Number(contentLength);
2276
+ if (Number.isFinite(parsedLength) && parsedLength > MAX_WORKFLOW_DOWNLOAD_BYTES) {
2277
+ throw new Error(
2278
+ `${sourcePath} exceeds download limit of ${MAX_WORKFLOW_DOWNLOAD_BYTES} bytes`
2279
+ );
2280
+ }
2257
2281
  }
2258
- async sendUpdate(update) {
2259
- if (this.ctx.messageRewriter) {
2260
- await this.ctx.messageRewriter.interceptUpdate(update);
2261
- return;
2282
+ if (!response.body) return "";
2283
+ const reader = response.body.getReader();
2284
+ const chunks = [];
2285
+ let totalBytes = 0;
2286
+ try {
2287
+ while (true) {
2288
+ const { done, value } = await reader.read();
2289
+ if (done) break;
2290
+ if (!value) continue;
2291
+ totalBytes += value.byteLength;
2292
+ if (totalBytes > MAX_WORKFLOW_DOWNLOAD_BYTES) {
2293
+ await reader.cancel().catch(() => {
2294
+ });
2295
+ throw new Error(
2296
+ `${sourcePath} exceeds download limit of ${MAX_WORKFLOW_DOWNLOAD_BYTES} bytes`
2297
+ );
2298
+ }
2299
+ chunks.push(value);
2262
2300
  }
2263
- await this.ctx.sendUpdate(update);
2301
+ } finally {
2302
+ reader.releaseLock();
2264
2303
  }
2265
- copyCumulativeUsage(state) {
2266
- const cumulative = this.ctx.cumulativeUsage;
2267
- if (!cumulative) return;
2268
- cumulative.promptTokens = state.cumulativeUsage.promptTokens;
2269
- cumulative.cachedTokens = state.cumulativeUsage.cachedTokens;
2270
- cumulative.candidateTokens = state.cumulativeUsage.candidateTokens;
2271
- cumulative.apiTimeMs = state.cumulativeUsage.apiTimeMs;
2304
+ const body = new Uint8Array(totalBytes);
2305
+ let offset = 0;
2306
+ for (const chunk of chunks) {
2307
+ body.set(chunk, offset);
2308
+ offset += chunk.byteLength;
2272
2309
  }
2273
- setActiveRecordId(recordId, timestamp) {
2274
- this.ctx.setActiveRecordId?.(recordId, timestamp);
2310
+ return new TextDecoder().decode(body);
2311
+ }
2312
+ __name(readResponseTextWithLimit, "readResponseTextWithLimit");
2313
+ async function resolveSecretsUrl(cwd) {
2314
+ try {
2315
+ const repoInfo = await getGitHubRepoInfoAsync({ cwd });
2316
+ return `https://github.com/${repoInfo.owner}/${repoInfo.repo}/settings/secrets/actions`;
2317
+ } catch {
2318
+ return void 0;
2275
2319
  }
2276
- };
2277
- function toPendingTranscriptToolCall(pending) {
2278
- return {
2279
- callId: pending.callId,
2280
- toolName: pending.toolName,
2281
- sourceRecordId: pending.recordId,
2282
- ...pending.timestamp ? { sourceTimestamp: pending.timestamp } : {}
2283
- };
2284
2320
  }
2285
- __name(toPendingTranscriptToolCall, "toPendingTranscriptToolCall");
2286
- function toLegacyPendingToolCall(pending) {
2287
- return {
2288
- callId: pending.callId,
2289
- toolName: pending.toolName,
2290
- recordId: pending.sourceRecordId,
2291
- ...pending.sourceTimestamp ? { timestamp: pending.sourceTimestamp } : {}
2292
- };
2321
+ __name(resolveSecretsUrl, "resolveSecretsUrl");
2322
+ async function realpathOrResolve(input) {
2323
+ try {
2324
+ return await fsp.realpath(input);
2325
+ } catch {
2326
+ return path.resolve(input);
2327
+ }
2293
2328
  }
2294
- __name(toLegacyPendingToolCall, "toLegacyPendingToolCall");
2329
+ __name(realpathOrResolve, "realpathOrResolve");
2295
2330
 
2296
2331
  // packages/cli/src/ui/utils/export/collect.ts
2297
2332
  init_esbuild_shims();
@@ -2512,7 +2547,7 @@ async function extractMetadata(conversation, config) {
2512
2547
  const gitBranch = firstRecord?.gitBranch;
2513
2548
  let gitRepo;
2514
2549
  if (cwd) {
2515
- const { getGitRepoName } = await import("./deferred-core-runtime-SFT3KI2C.js");
2550
+ const { getGitRepoName } = await import("./deferred-core-runtime-F4XOQJQL.js");
2516
2551
  gitRepo = getGitRepoName(cwd);
2517
2552
  }
2518
2553
  let model;
@@ -3386,7 +3421,7 @@ export {
3386
3421
  };
3387
3422
  /**
3388
3423
  * @license
3389
- * Copyright 2025 Google LLC
3424
+ * Copyright 2026 Qwen Team
3390
3425
  * SPDX-License-Identifier: Apache-2.0
3391
3426
  */
3392
3427
  /**
@@ -3396,12 +3431,12 @@ export {
3396
3431
  */
3397
3432
  /**
3398
3433
  * @license
3399
- * Copyright 2026 Qwen Team
3434
+ * Copyright 2025 Qwen
3400
3435
  * SPDX-License-Identifier: Apache-2.0
3401
3436
  */
3402
3437
  /**
3403
3438
  * @license
3404
- * Copyright 2025 Qwen
3439
+ * Copyright 2025 Google LLC
3405
3440
  * SPDX-License-Identifier: Apache-2.0
3406
3441
  */
3407
3442
  /**