nolo-cli 0.149.0-alpha.1 → 0.151.0-alpha.2

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 (258) hide show
  1. package/{_executeModel-OW3H7ICR.js → _executeModel-XHAFJ2MM.js} +134 -91
  2. package/accountResolver-7RYB4D2P.js +300 -0
  3. package/action-SXJD5N5R.js +23 -0
  4. package/{addContentAction-B2DRF7P6.js → addContentAction-ZV774PHH.js} +20 -14
  5. package/{addDialogAgentAction-2P2FLTLD.js → addDialogAgentAction-A6SMKAGH.js} +26 -22
  6. package/{agentDeleteCommand-7IDWF6E3.js → agentDeleteCommand-DPUUS56Z.js} +181 -93
  7. package/{agentEmailCommands-A6XBQZBN.js → agentEmailCommands-V4P5EFLP.js} +132 -112
  8. package/{agentGrantCommands-M3XFO6EN.js → agentGrantCommands-HOJ3JBBQ.js} +3 -3
  9. package/agentListCommands-TWFLUYIZ.js +802 -0
  10. package/{agentMachineCommands-DQPUIMAC.js → agentMachineCommands-MELPAZZI.js} +58 -62
  11. package/{agentProviderCommands-YK2BIIXZ.js → agentProviderCommands-HL6MBLCL.js} +149 -2
  12. package/{agentPullCommand-HF4A42D4.js → agentPullCommand-FA43RBRU.js} +7 -7
  13. package/agentRecordCommands-FSWSSQIO.js +154 -0
  14. package/agentRunCommand-GDBJVOAT.js +183 -0
  15. package/{agentRunControl-2SKCR4SB.js → agentRunControl-IFM7IGMG.js} +10 -2
  16. package/{agentRuntimeLocal-AK2QVJHY.js → agentRuntimeLocal-KKSQJMTE.js} +47 -50
  17. package/{agentSlice-O4RUQUMT.js → agentSlice-YO2ZLJMD.js} +23 -16
  18. package/{appDeleteCommands-N3XEVVYC.js → appDeleteCommands-4PL4KYRN.js} +58 -59
  19. package/{appDeployCommands-AWFIXYVW.js → appDeployCommands-EEEXCEB6.js} +67 -63
  20. package/{appDeployStatusCommands-CZRON2FO.js → appDeployStatusCommands-35ZX7T66.js} +56 -56
  21. package/{appGetCommands-XQIUY4TD.js → appGetCommands-WFCHXJWF.js} +56 -56
  22. package/{appListCommands-NNG4H36Y.js → appListCommands-XY2U6DPF.js} +57 -59
  23. package/{authCommand-UBJ4EWYZ.js → authCommand-QYN47CQD.js} +371 -68
  24. package/{authCommands-H6WKKCRW.js → authCommands-77CHYBGF.js} +12 -9
  25. package/{builtinSkillRegistry-ZMF6YGNO.js → builtinSkillRegistry-TDQ6JB2E.js} +13 -11
  26. package/{chromeCommands-2N6MEWRU.js → chromeCommands-OBBNJCLS.js} +314 -13
  27. package/chromeOpsCommands-3Z34RKSE.js +472 -0
  28. package/{chunk-ALXHV7NK.js → chunk-2GGXHQIW.js} +43 -4
  29. package/{localRuntimeAuthority-5W6IJRAD.js → chunk-2IXDJNZI.js} +154 -75
  30. package/{chunk-IVZJWTDI.js → chunk-36OMEXXR.js} +89 -21
  31. package/{chunk-H6A6X4EK.js → chunk-3MZAGMYY.js} +16 -0
  32. package/chunk-3PVYUPXK.js +40 -0
  33. package/chunk-3SZA4U64.js +1192 -0
  34. package/{chunk-GNMAFAIS.js → chunk-44WXLHFI.js} +1 -1
  35. package/{chunk-AGGIDPCZ.js → chunk-4JH2UMJR.js} +6 -0
  36. package/chunk-4LCOCOR5.js +50 -0
  37. package/chunk-4YRTZIVN.js +871 -0
  38. package/chunk-556RW72X.js +14110 -0
  39. package/{chunk-N7J63Q6C.js → chunk-56GBUMO5.js} +10 -1
  40. package/{chunk-W7XHHYWM.js → chunk-5BHQICF2.js} +5 -1
  41. package/{chunk-XUWRURDF.js → chunk-5EBLANFT.js} +1 -1
  42. package/{chunk-3AH7LNUB.js → chunk-5EMSBTQ6.js} +33 -14
  43. package/{chunk-YRRASA5Q.js → chunk-5MM7NNO6.js} +113 -52
  44. package/chunk-5MMAK75Q.js +15 -0
  45. package/{chunk-M5PVFLD4.js → chunk-64K7WX26.js} +90 -21
  46. package/{chunk-AKG5W4LG.js → chunk-6CCFTVBP.js} +76 -221
  47. package/chunk-6MJNEXUU.js +614 -0
  48. package/{chunk-62IL3KQV.js → chunk-6MXDOUMH.js} +15 -3
  49. package/{chunk-QOKAKDPE.js → chunk-6Q7UTJKR.js} +6 -94
  50. package/chunk-6QDYSCPW.js +223 -0
  51. package/{chunk-HYZIYH2H.js → chunk-74RAWNQN.js} +56 -63
  52. package/chunk-7DPNBQSV.js +9 -0
  53. package/chunk-7MOXKPHC.js +119 -0
  54. package/{chunk-ZUEK6A6C.js → chunk-7XKL25PW.js} +1973 -754
  55. package/{chunk-IAESIMK7.js → chunk-A4MW3YZL.js} +10 -14
  56. package/chunk-AGIM7IMJ.js +147 -0
  57. package/{chunk-7CHC4W22.js → chunk-AIZE5TDM.js} +3 -3
  58. package/{chunk-YAQJJDC2.js → chunk-AOCM7HPT.js} +214 -51
  59. package/{chunk-5GVBDNTO.js → chunk-AU7AXHUL.js} +1 -1
  60. package/{chunk-4H22P2JV.js → chunk-AUIJZACN.js} +2073 -1275
  61. package/{chunk-CIF4X6ZM.js → chunk-AWVFQMOV.js} +25 -3
  62. package/{chunk-RYZINGPM.js → chunk-BPMPOFWP.js} +347 -235
  63. package/{chunk-YUNJN43V.js → chunk-BU2YQBV4.js} +215 -28
  64. package/{chunk-XPRWFQQK.js → chunk-CBHGZRCE.js} +38 -12
  65. package/{chunk-Y3PMXGLH.js → chunk-CHCS6XPJ.js} +365 -144
  66. package/chunk-CHOZJMJS.js +78 -0
  67. package/{chunk-GBRG75BQ.js → chunk-D2MDMY2M.js} +1 -0
  68. package/{chunk-3SV7RM24.js → chunk-D2QN6CTI.js} +117 -72
  69. package/{chunk-5TEEECZM.js → chunk-E2AKSW7L.js} +10 -7
  70. package/{chunk-RSEEDUMS.js → chunk-EDX5XSJM.js} +2 -2
  71. package/{chunk-ATLTFRYJ.js → chunk-ES633ZS5.js} +280 -98
  72. package/{chunk-QDSINZM3.js → chunk-EUGTFFO6.js} +2 -23
  73. package/{chunk-UNYJU5L6.js → chunk-EYLGAEB4.js} +5 -1
  74. package/{chunk-CU3QB4HW.js → chunk-EYWJT7A2.js} +12 -12
  75. package/{chunk-BNGW5ASC.js → chunk-EZVK3N5L.js} +66 -18
  76. package/{chunk-6FGTMQCL.js → chunk-F32Z66T4.js} +6 -10
  77. package/chunk-FJMRBOPO.js +11507 -0
  78. package/{chunk-ZOVKKMF6.js → chunk-FY4SDK2E.js} +1 -1
  79. package/chunk-G6OOUQWJ.js +417 -0
  80. package/{chunk-PQWU42UQ.js → chunk-GCKHQECX.js} +6 -6
  81. package/chunk-GKXCHNTE.js +15 -0
  82. package/{chunk-TXH4IWJL.js → chunk-GQN2WLAI.js} +20 -11
  83. package/{chunk-P6GMCCAT.js → chunk-GQV5KHJU.js} +78 -12
  84. package/{chunk-B2XUQXQX.js → chunk-HIQ4GF53.js} +191 -68
  85. package/{chunk-MST6R3E4.js → chunk-HKX3ULQB.js} +34 -22
  86. package/{chunk-GMZLP5DV.js → chunk-HNUWUO75.js} +30 -19
  87. package/{chunk-5UTFL4QJ.js → chunk-I2ZMGXXF.js} +10 -5
  88. package/chunk-I42VC5KR.js +15 -0
  89. package/{chunk-3BXNTXYI.js → chunk-I4SN4NUQ.js} +1199 -56
  90. package/chunk-IA7TRNNR.js +11 -0
  91. package/{chunk-WIWM4FE3.js → chunk-IJERIUXS.js} +55 -748
  92. package/{chunk-CPUFH46E.js → chunk-ILU2NPWY.js} +10 -10
  93. package/{chunk-SLLGJZDT.js → chunk-ISQL4V7C.js} +4 -4
  94. package/chunk-IT3ZZRJE.js +12 -0
  95. package/{chunk-TZZ2WRBL.js → chunk-IZ7OJB6K.js} +20 -16
  96. package/{chunk-DY7ANLKG.js → chunk-JKMLSTZK.js} +43 -12
  97. package/{chunk-6TPOEJMQ.js → chunk-JZX2XLKC.js} +64 -23
  98. package/{chunk-27ONFIEY.js → chunk-K2AER7RX.js} +19 -12
  99. package/{chunk-O2OWEFII.js → chunk-KFHQQ3NO.js} +1 -1
  100. package/{chunk-QXGPFY6J.js → chunk-LGN377P3.js} +27 -17
  101. package/{chunk-L36OWPP3.js → chunk-LIQJTQRN.js} +118 -139
  102. package/{chunk-UASIEDKM.js → chunk-LTRUTOHX.js} +36 -31
  103. package/{chunk-BFU6C242.js → chunk-NMFV26UG.js} +1 -1
  104. package/{chunk-5J3PYNUP.js → chunk-NYYFIKHI.js} +17 -3
  105. package/{chunk-6O4IK4V2.js → chunk-OFFL4DCR.js} +1 -1
  106. package/{chunk-B6SAMB33.js → chunk-OWYYDMGJ.js} +209 -9
  107. package/{chunk-KQHGZWSV.js → chunk-OXME3PEE.js} +1 -1
  108. package/{chunk-CTUQJVQM.js → chunk-P5QACQDK.js} +1 -1
  109. package/{chunk-DXHL7G2L.js → chunk-PCKVQXYV.js} +274 -93
  110. package/{chunk-4JMDLJAD.js → chunk-PJNFNEJE.js} +114 -37
  111. package/{chunk-Z4CSIXYP.js → chunk-PLSVXHSA.js} +3 -3
  112. package/{chunk-BIDGLJQ3.js → chunk-PLXDDGBK.js} +45 -8
  113. package/chunk-PWTNI4N7.js +47 -0
  114. package/chunk-QFEW2ULV.js +42 -0
  115. package/{chunk-RGNEEJ3Y.js → chunk-QLQ573SU.js} +35 -9
  116. package/chunk-QQ56R7KS.js +88 -0
  117. package/chunk-QYPE3TS3.js +43 -0
  118. package/{chunk-4DPP773Q.js → chunk-RSHPU4PD.js} +59 -11
  119. package/chunk-RVWMAFIT.js +134 -0
  120. package/{chunk-ESHYE7WU.js → chunk-S73EPYNC.js} +10 -7
  121. package/{chunk-UQNS32WZ.js → chunk-SCMHQUMK.js} +1 -1
  122. package/{chunk-HTVYCXBP.js → chunk-SMENBO3M.js} +354 -120
  123. package/{chunk-OMRJYNCI.js → chunk-SSFDFOVT.js} +26 -31
  124. package/chunk-SW4S4XYB.js +1794 -0
  125. package/{chunk-TB3MIBRC.js → chunk-T6X3D7NB.js} +572 -430
  126. package/chunk-TY3TIUJK.js +89 -0
  127. package/{chunk-X2QRZXZH.js → chunk-TYJ5XFEA.js} +4 -4
  128. package/{chunk-ALFH24P3.js → chunk-TYYRSFBG.js} +197 -155
  129. package/{chunk-7KVZ5LDQ.js → chunk-UBUH2TCC.js} +18 -4
  130. package/chunk-UEILX4EV.js +15 -0
  131. package/chunk-UHTDNB5Y.js +140 -0
  132. package/{chunk-YYLHWIW6.js → chunk-UKZX3NHN.js} +1 -1
  133. package/{chunk-OHOVNO7I.js → chunk-UOKFKFPO.js} +6 -3
  134. package/{chunk-XISEYOGH.js → chunk-USHQX6VT.js} +5 -5
  135. package/chunk-UUPR3TD7.js +53 -0
  136. package/{chunk-HDLLCBRF.js → chunk-VEA7H5FG.js} +2 -2
  137. package/chunk-VHGD6FHV.js +116 -0
  138. package/chunk-VIWDGTDA.js +8 -0
  139. package/{chunk-GOH6RW6F.js → chunk-VJXHL6MH.js} +34 -11
  140. package/{chunk-4XEYAFLY.js → chunk-VL5KOY2C.js} +623 -94
  141. package/{chunk-EADNWBAZ.js → chunk-VP3BINY7.js} +13 -0
  142. package/{chunk-EOARMOVD.js → chunk-W4S6OTSC.js} +6 -3
  143. package/chunk-WD4XYDYC.js +567 -0
  144. package/chunk-WJZOQR2J.js +151 -0
  145. package/{chunk-AUDNYVRC.js → chunk-XETG4RIX.js} +5 -5
  146. package/{chunk-MX574M24.js → chunk-XI7DGLUK.js} +4 -4
  147. package/{chunk-3L2WKC3W.js → chunk-XPWGOTBQ.js} +8 -1
  148. package/chunk-XRUSXPCQ.js +514 -0
  149. package/{chunk-I4OPU5TK.js → chunk-XS47QOFV.js} +273 -11
  150. package/{chunk-S5XGT6GB.js → chunk-XZNCX52W.js} +30 -9
  151. package/{chunk-ID7LNBWR.js → chunk-Y2DXOPSO.js} +1920 -644
  152. package/{chunk-5OA5HMTL.js → chunk-YLMMECCH.js} +1 -1
  153. package/{chunk-CFT5HBGW.js → chunk-YVLQXTUB.js} +448 -12
  154. package/chunk-YVPQATSC.js +709 -0
  155. package/{chunk-3DAVPNFT.js → chunk-Z7OJUX6S.js} +122 -107
  156. package/chunk-ZEZC7IIM.js +126 -0
  157. package/{chunk-ALGORS6Y.js → chunk-ZF6526IQ.js} +43 -8
  158. package/chunk-ZIWPQEFU.js +165 -0
  159. package/chunk-ZKZ5X2HS.js +7012 -0
  160. package/chunk-ZRAU6T47.js +56 -0
  161. package/{cliExecutor-AWYR3T33.js → cliExecutor-BWBF2MTI.js} +4 -3
  162. package/{clipboardy-BX4NMYHE.js → clipboardy-GCO3GT3I.js} +3 -8
  163. package/{commandRegistry-2KBOXZQC.js → commandRegistry-XN7C5GHO.js} +183 -107
  164. package/contentThunks-5L7YQI3S.js +84 -0
  165. package/{cooldownCommands-ZLEPIB4A.js → cooldownCommands-JFKTYS2D.js} +2 -2
  166. package/{createAgentAutomationAction-5UGTB26P.js → createAgentAutomationAction-QOPOLCRK.js} +53 -44
  167. package/createDialogAction-MZ66VY5Q.js +76 -0
  168. package/{createPageAction-CDLDKPRM.js → createPageAction-VQDJIXMY.js} +65 -54
  169. package/cursorProvider-YGGNMVWX.js +6123 -0
  170. package/{db-VQSAOWAO.js → db-2QOTXYGH.js} +11 -5
  171. package/{dbSlice-DQ32LYTJ.js → dbSlice-J37OGIXH.js} +19 -13
  172. package/{deleteFile-NX6QHCWZ.js → deleteFile-6JWDDRVP.js} +10 -6
  173. package/dialogCommands-YZLSJB6X.js +113 -0
  174. package/{dialogSlice-N3YB65G5.js → dialogSlice-6RODVYCK.js} +53 -39
  175. package/{docCreateCommands-ZSLGVBZT.js → docCreateCommands-JB2RRMRJ.js} +54 -57
  176. package/{docDeleteCommands-5N4GVZBG.js → docDeleteCommands-AQENULNM.js} +56 -58
  177. package/{docReadCommands-YJSAA7AV.js → docReadCommands-DYD25YLQ.js} +53 -56
  178. package/{docStore-E3CEOV5Q.js → docStore-ZZA3OPM5.js} +25 -16
  179. package/{docUpdateCommands-WEMLSW6W.js → docUpdateCommands-3GVS23QL.js} +54 -57
  180. package/{fetchMessages-67MEFPZR.js → fetchMessages-IIJWQ3HR.js} +5 -4
  181. package/{getPricing-NMMFT3YI.js → getPricing-FKK3F5EJ.js} +11 -9
  182. package/{handleSendMessageAction-DQAD5ERJ.js → handleSendMessageAction-DVG5U26T.js} +422 -118
  183. package/index.js +11 -7
  184. package/{lib-FRRS27KN.js → lib-4YTWAGY7.js} +581 -248
  185. package/{localDialogRead-EBRS242U.js → localDialogRead-FSOMOPDZ.js} +2 -2
  186. package/localRuntimeAdapter-HXRHFKRC.js +244 -0
  187. package/localRuntimeAuthority-JDAD7CB6.js +16 -0
  188. package/{localRuntimeDb-3LRMNLCM.js → localRuntimeDb-CVC62PM5.js} +1 -1
  189. package/{machineCommands-HAP75VSG.js → machineCommands-5KBF4RCC.js} +503 -161
  190. package/{machineInfo-66ZFUMLE.js → machineInfo-UKPTZO5Y.js} +2 -2
  191. package/machineWsRunDispatch-4OQDEDOR.js +169 -0
  192. package/{memberThunks-5ZXPR63F.js → memberThunks-66DH6ABQ.js} +25 -18
  193. package/{models-ZPU5EDF4.js → models-LAS4B2B5.js} +2 -2
  194. package/package.json +1 -1
  195. package/{providerPresetApply-DD6NGWW6.js → providerPresetApply-MY66I6NT.js} +10 -10
  196. package/{providerRegistry-XDRLMYGJ.js → providerRegistry-QOE2FT57.js} +13 -9
  197. package/{read-EPTJRAEF.js → read-DC4NUGN6.js} +12 -8
  198. package/{readDocTool-W4NDXNEX.js → readDocTool-NCJ5NT25.js} +1 -1
  199. package/{readlineWorkspace-7BC66QSX.js → readlineWorkspace-RIE62QVZ.js} +5022 -921
  200. package/{removeDialogAgentAction-OSYNZRX7.js → removeDialogAgentAction-E2H3OZU6.js} +29 -28
  201. package/{runAgentClientLoop-6E6UC3CE.js → runAgentClientLoop-KLUUXBZS.js} +154 -97
  202. package/{runtimeDoctorCommands-ID23PNNZ.js → runtimeDoctorCommands-GIOGC5SC.js} +17 -17
  203. package/secretCommands-ZXZRLR3R.js +700 -0
  204. package/setDialogExtraReferencesAction-SITRPMYU.js +37 -0
  205. package/{setPrimaryDialogAgentAction-WZ7KI3YA.js → setPrimaryDialogAgentAction-U7N45TGC.js} +30 -29
  206. package/{chunk-SONWNI3L.js → settingThunks-Y7SVJOMZ.js} +223 -928
  207. package/{skillDiscovery-ZBU76COE.js → skillDiscovery-QC35EQY4.js} +2 -2
  208. package/{slateUtils-RIZES3PV.js → slateUtils-NGV2NMKM.js} +1 -1
  209. package/{spaceCommands-UJOVU4XI.js → spaceCommands-ZR5BR3GX.js} +59 -59
  210. package/{streamAgentChatTurn-3UXPYFNX.js → streamAgentChatTurn-MN2SSPGA.js} +309 -165
  211. package/{switchDialogAgentAction-GMR7WN3P.js → switchDialogAgentAction-OMGBD3N2.js} +26 -22
  212. package/{tableCommands-G7RV3RU3.js → tableCommands-U3QDY4L6.js} +19 -17
  213. package/{toolApiClient-CVGWM4PN.js → toolApiClient-7WSJJJBV.js} +6 -5
  214. package/tools-W2MOLERY.js +124 -0
  215. package/tuiSummaryLlmCaller-BM3VSTBU.js +130 -0
  216. package/{updateCommands-4EHDLF5J.js → updateCommands-NQXAGFM7.js} +3 -3
  217. package/{updateDialogTitleAction-UPFV7TDT.js → updateDialogTitleAction-Z4JX6REN.js} +102 -57
  218. package/workloadLifecycle-36DXRZKU.js +320 -0
  219. package/action-GI44T4DR.js +0 -31
  220. package/agentListCommands-IW3GQVUP.js +0 -427
  221. package/agentRecordCommands-VCA76W6B.js +0 -134
  222. package/agentRunCommand-YNLDKVR7.js +0 -161
  223. package/browser-image-compression-MFDTD7K6.js +0 -1763
  224. package/chatQueueReduxAdapter-TJRMXMYA.js +0 -186
  225. package/chromeOpsCommands-IXRLN57H.js +0 -289
  226. package/chunk-36KZDDO5.js +0 -2415
  227. package/chunk-ACQD6YI2.js +0 -25363
  228. package/chunk-CQ3WA2NE.js +0 -299
  229. package/chunk-CYSYR67N.js +0 -93
  230. package/chunk-JBTJAPUF.js +0 -35
  231. package/chunk-K2CSUCHJ.js +0 -620
  232. package/chunk-LTRXGFMS.js +0 -83
  233. package/chunk-M76ECQRD.js +0 -13658
  234. package/chunk-MEYIRKDN.js +0 -8967
  235. package/chunk-OCZKATRC.js +0 -129
  236. package/chunk-OTGFTBLI.js +0 -13
  237. package/chunk-PUOC4YRO.js +0 -394
  238. package/chunk-PZZTFEKK.js +0 -34
  239. package/chunk-URMS4XY2.js +0 -10
  240. package/chunk-UV6VISQJ.js +0 -20
  241. package/chunk-VJVNU77E.js +0 -83
  242. package/chunk-XYJSY4KG.js +0 -13807
  243. package/chunk-Y5GCAMGP.js +0 -9
  244. package/chunk-YPREESF4.js +0 -225
  245. package/contentThunks-BDIQRZR6.js +0 -73
  246. package/createDialogAction-B7VGVEVU.js +0 -66
  247. package/dialogCommands-G7YBVAMC.js +0 -102
  248. package/levelLazyShim-GZBKODGI.js +0 -7
  249. package/machineWsRunDispatch-L32G7C4P.js +0 -149
  250. package/serverStoreFactory-YMXDF4NI.js +0 -20
  251. package/setDialogExtraReferencesAction-M32UYNCG.js +0 -30
  252. package/settingSlice-Q6EKL7EQ.js +0 -204
  253. package/syncMapping-N6RGXGBW.js +0 -437
  254. package/tools-MKYDMWA4.js +0 -111
  255. package/tuiSummaryLlmCaller-3YFNHCTW.js +0 -128
  256. package/{chunk-SV5IJK6K.js → chunk-NBTY7YJF.js} +3 -3
  257. package/{chunk-2SYTUTLI.js → chunk-YBNHPX4S.js} +3 -3
  258. package/{offlineMarxistsAgentCommand-HGXZV4XJ.js → offlineMarxistsAgentCommand-2QTHJCHV.js} +4 -4
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  findPotentialSecrets
3
- } from "./chunk-VJVNU77E.js";
3
+ } from "./chunk-6QDYSCPW.js";
4
4
  import {
5
5
  buildLocalRunEnv,
6
6
  isFullstackCodingAgentRef,
@@ -9,14 +9,16 @@ import {
9
9
  resolveRawAgentInput,
10
10
  resolveServerUrl,
11
11
  writeUsage
12
- } from "./chunk-BIDGLJQ3.js";
12
+ } from "./chunk-PLXDDGBK.js";
13
+ import {
14
+ getReadableCliDb
15
+ } from "./chunk-P5QACQDK.js";
13
16
  import {
14
- agentRunCardLabels,
15
17
  createCliLocalRuntimeAdapter,
16
18
  detectCurrentMachineId,
17
- getCliLocale,
18
19
  isBuiltinNoloAgentRef,
19
20
  isCliProviderAgentConfig,
21
+ isDockerRuntimeKey,
20
22
  isLiveAgentRunObservation,
21
23
  isMachineBoundLocalhostCustomProvider,
22
24
  isSubtaskRun,
@@ -24,151 +26,203 @@ import {
24
26
  resolveAuthToken as resolveAuthToken2,
25
27
  resolveBoundMachineId,
26
28
  resolveFileWriteGateEnabled,
27
- resolveLocalUserId,
28
- t,
29
- toolLabel,
30
- toolLabelVariants
31
- } from "./chunk-XYJSY4KG.js";
29
+ resolveLocalUserId
30
+ } from "./chunk-FJMRBOPO.js";
32
31
  import {
33
32
  clearCredentialAvailability,
34
33
  readCredentialEntry,
35
34
  recordCredentialProbe
36
- } from "./chunk-62IL3KQV.js";
35
+ } from "./chunk-6MXDOUMH.js";
37
36
  import {
38
- getReadableCliDb
39
- } from "./chunk-CTUQJVQM.js";
37
+ agentRunCardLabels,
38
+ getCliLocale,
39
+ t,
40
+ toolLabel,
41
+ toolLabelVariants
42
+ } from "./chunk-SW4S4XYB.js";
40
43
  import {
41
- resolveMachineId
42
- } from "./chunk-ESHYE7WU.js";
44
+ _appendEntityBatch,
45
+ _appendEvidenceBatch,
46
+ _appendRelationBatch,
47
+ _appendRetiredStateBatch,
48
+ _appendStateBatch,
49
+ getMemoryEntityVNext,
50
+ getMemoryEvidenceVNext,
51
+ getMemoryEvidenceVNextStrict,
52
+ getMemoryStateVNext,
53
+ listMemoryStatesForEntityVNext,
54
+ loadMemoryVNextCatalog,
55
+ putMemoryEvidenceVNext
56
+ } from "./chunk-TY3TIUJK.js";
43
57
  import {
44
58
  readDbRecord,
45
59
  resolveAgentRecordFromHybridStore
46
- } from "./chunk-ALGORS6Y.js";
60
+ } from "./chunk-ZF6526IQ.js";
47
61
  import {
48
62
  isLocalCliAgentKey
49
- } from "./chunk-SV5IJK6K.js";
50
- import {
51
- extractGoogleValidationLink
52
- } from "./chunk-BMQ2MJUK.js";
53
- import {
54
- createRunActivityTracker,
55
- popSingleQueueMessage,
56
- readRunRecord,
57
- resolveRunQueuePath,
58
- settleRunTerminalAuthoritatively,
59
- spawnLocalBackgroundRun
60
- } from "./chunk-CFT5HBGW.js";
61
- import {
62
- isCliAuthorityBrokerProtocolError,
63
- isCliAuthorityBrokerTimeoutError,
64
- isCliAuthorityBrokerUnavailableError
65
- } from "./chunk-EXAJ6DCR.js";
66
- import {
67
- getDefaultCliLocalRuntimeDb
68
- } from "./chunk-ZOVKKMF6.js";
63
+ } from "./chunk-NBTY7YJF.js";
69
64
  import {
70
65
  CliProviderQuotaError
71
- } from "./chunk-4XEYAFLY.js";
66
+ } from "./chunk-VL5KOY2C.js";
67
+ import {
68
+ resolveMachineId
69
+ } from "./chunk-S73EPYNC.js";
72
70
  import {
73
- applyModelLayerOverride,
74
- buildModelLayerOverride
75
- } from "./chunk-LTRXGFMS.js";
71
+ extractGoogleValidationLink
72
+ } from "./chunk-BMQ2MJUK.js";
76
73
  import {
77
- formatAgentListCard
78
- } from "./chunk-ID7LNBWR.js";
74
+ resolveCliLocalRuntimeKeyCapability
75
+ } from "./chunk-Y2DXOPSO.js";
79
76
  import {
80
77
  isTransientFetchError
81
- } from "./chunk-5UTFL4QJ.js";
78
+ } from "./chunk-I2ZMGXXF.js";
79
+ import {
80
+ parseUiCard,
81
+ uiCardFallback
82
+ } from "./chunk-ES633ZS5.js";
82
83
  import {
83
84
  isGatewayHttpStatus
84
85
  } from "./chunk-NF64D32W.js";
85
86
  import {
86
- formatFinishedRunCard,
87
- formatListRunsCard,
88
- formatNotFoundRunCard,
89
- formatStartRunCard,
90
- formatStatusRunCard,
91
- formatStopRunCard,
92
- isAgentRunTerminalStatus
93
- } from "./chunk-4JMDLJAD.js";
87
+ parsePositiveFiniteNumberOrFallback
88
+ } from "./chunk-XPWGOTBQ.js";
94
89
  import {
95
90
  buildMemorySubjectsForAgent,
96
91
  chooseMemoryOwners,
97
92
  loadMemoryCandidatesFromDb,
98
93
  resolveAgentMemoryPolicy
99
- } from "./chunk-OMRJYNCI.js";
94
+ } from "./chunk-SSFDFOVT.js";
100
95
  import {
101
96
  API_REPORTED_COST_MULTIPLIER,
102
97
  parseUiAskChoiceContent
103
- } from "./chunk-ACQD6YI2.js";
98
+ } from "./chunk-556RW72X.js";
104
99
  import {
105
100
  isOAuthApiKeyRef
106
- } from "./chunk-YYLHWIW6.js";
107
- import {
108
- buildSkillDiscoveryContextLayer
109
- } from "./chunk-5GVBDNTO.js";
101
+ } from "./chunk-UKZX3NHN.js";
110
102
  import {
111
103
  parseExternalSkillMarkdown,
112
104
  parseSkillDocProtocol
113
- } from "./chunk-AUDNYVRC.js";
105
+ } from "./chunk-XETG4RIX.js";
114
106
  import {
115
107
  LOCAL_AGENT_CONFIG_MISSING_CODE,
116
108
  LOCAL_TURN_ABORTED_CODE,
117
109
  readActionGate
118
- } from "./chunk-4H22P2JV.js";
110
+ } from "./chunk-AUIJZACN.js";
119
111
  import {
112
+ devinChannelContextWindow,
120
113
  resolveAgentRuntimeConfigFromRecord
121
- } from "./chunk-OHOVNO7I.js";
114
+ } from "./chunk-UOKFKFPO.js";
115
+ import {
116
+ isDevinOAuthAgent
117
+ } from "./chunk-5ZUL4CUO.js";
122
118
  import {
123
119
  createThinkParserState,
124
120
  flushThinkParser,
125
121
  processThinkChunk
126
- } from "./chunk-N7J63Q6C.js";
122
+ } from "./chunk-56GBUMO5.js";
123
+ import {
124
+ ATTACHMENT_PART_TYPE,
125
+ ATTACHMENT_PART_VERSION,
126
+ describeAttachmentForModel,
127
+ normalizeAttachmentPart
128
+ } from "./chunk-WJZOQR2J.js";
127
129
  import {
130
+ PROBE_INTERVAL_MS,
128
131
  QUOTA_ERROR_PATTERNS,
129
132
  isQuotaExhaustedError,
130
133
  isQuotaLimited403Body,
131
134
  mergeAvailabilityDeadline,
132
135
  resolveCooldownGate,
133
136
  resolveCredentialKeyWithFallback
134
- } from "./chunk-H6A6X4EK.js";
137
+ } from "./chunk-3MZAGMYY.js";
135
138
  import {
136
- isAntigravityOAuthAgent
137
- } from "./chunk-S5XGT6GB.js";
138
- import {
139
- resolveClientVersion
140
- } from "./chunk-27ONFIEY.js";
141
- import {
142
- DEFAULT_CONTEXT_WINDOW,
143
- getModelContextWindow,
144
139
  normalizeUsage
145
- } from "./chunk-AKG5W4LG.js";
140
+ } from "./chunk-6CCFTVBP.js";
141
+ import {
142
+ findModelContextWindow
143
+ } from "./chunk-BPMPOFWP.js";
146
144
  import {
147
145
  clipCompactText
148
- } from "./chunk-RYZINGPM.js";
146
+ } from "./chunk-5MMAK75Q.js";
149
147
  import {
150
148
  compactWhitespace
151
149
  } from "./chunk-DWLEOOGR.js";
152
150
  import {
153
- toErrorMessage
154
- } from "./chunk-HNMXYYJR.js";
151
+ normalizeRuntimeToolPolicyOverride,
152
+ resolveEffectiveRuntimeToolPolicy
153
+ } from "./chunk-LIQJTQRN.js";
154
+ import {
155
+ BUILTIN_NOLO_AGENT_KEY,
156
+ BUILTIN_NOLO_AGENT_NAME,
157
+ builtinAgentCatalogEntryById,
158
+ parseBuiltinPlatformAgentId
159
+ } from "./chunk-EZVK3N5L.js";
160
+ import {
161
+ parsePublicAgentId
162
+ } from "./chunk-M2EJHDJP.js";
163
+ import {
164
+ createMemoryKey,
165
+ ulid
166
+ } from "./chunk-5EMSBTQ6.js";
167
+ import {
168
+ isAntigravityOAuthAgent
169
+ } from "./chunk-XZNCX52W.js";
170
+ import {
171
+ createRunActivityTracker,
172
+ createShellApprovalChild,
173
+ getRunResultHeaderMeta,
174
+ popSingleQueueMessage,
175
+ readRunRecord,
176
+ recordRunResultHeaderMeta,
177
+ resolveResultServerMeta,
178
+ resolveRunQueuePath,
179
+ serverOriginForDialog,
180
+ settleRunTerminalAuthoritatively,
181
+ spawnLocalBackgroundRun
182
+ } from "./chunk-YVLQXTUB.js";
183
+ import {
184
+ formatAgentListCard,
185
+ formatFinishedRunCard,
186
+ formatListRunsCard,
187
+ formatNotFoundRunCard,
188
+ formatStartRunCard,
189
+ formatStatusRunCard,
190
+ formatStopRunCard,
191
+ isAgentRunTerminalStatus
192
+ } from "./chunk-PJNFNEJE.js";
193
+ import {
194
+ estimateTokenCount
195
+ } from "./chunk-PSCNXBYA.js";
196
+ import {
197
+ resolveClientVersion
198
+ } from "./chunk-K2AER7RX.js";
155
199
  import {
156
200
  findModelConfig
157
- } from "./chunk-3BXNTXYI.js";
201
+ } from "./chunk-I4SN4NUQ.js";
158
202
  import {
159
- buildAgentsMdLayer,
160
- buildMemoryOverlayLayer,
161
- buildMemoryUseGuidanceLayer,
162
- partitionScopedBlocks,
163
- renderTurnContextBlocksWithScope
164
- } from "./chunk-HDLLCBRF.js";
203
+ asTrimmedString
204
+ } from "./chunk-3EUW3WEO.js";
205
+ import {
206
+ isCliAuthorityBrokerProtocolError,
207
+ isCliAuthorityBrokerTimeoutError,
208
+ isCliAuthorityBrokerUnavailableError
209
+ } from "./chunk-EXAJ6DCR.js";
210
+ import {
211
+ toErrorMessage
212
+ } from "./chunk-HNMXYYJR.js";
213
+ import {
214
+ getDefaultCliLocalRuntimeDb
215
+ } from "./chunk-FY4SDK2E.js";
165
216
  import {
166
217
  getLogger,
167
218
  normalizeError
168
- } from "./chunk-UNYJU5L6.js";
219
+ } from "./chunk-EYLGAEB4.js";
169
220
  import {
170
221
  resolveAuthToken
171
222
  } from "./chunk-A7GB5UGH.js";
223
+ import {
224
+ asOptionalTrimmedString
225
+ } from "./chunk-G3SUCT4W.js";
172
226
  import {
173
227
  readPipeText,
174
228
  spawnProcess
@@ -177,34 +231,242 @@ import {
177
231
  CLIENT_VERSION_TOO_OLD_CODE,
178
232
  NOLO_CLIENT_VERSION_HEADER,
179
233
  buildClientVersionUpgradeMessage
180
- } from "./chunk-Y3PMXGLH.js";
181
- import {
182
- parsePositiveFiniteNumberOrFallback
183
- } from "./chunk-Y5GCAMGP.js";
184
- import {
185
- createMemoryKey,
186
- ulid
187
- } from "./chunk-3AH7LNUB.js";
234
+ } from "./chunk-CHCS6XPJ.js";
188
235
  import {
189
236
  asTrimmedLowercaseString
190
237
  } from "./chunk-QSJ3HFEF.js";
191
238
  import {
192
- isLevelNotFoundError
193
- } from "./chunk-OW765XBU.js";
194
- import {
195
- BUILTIN_NOLO_AGENT_KEY,
196
- BUILTIN_NOLO_AGENT_NAME,
197
- builtinAgentCatalogEntryById
198
- } from "./chunk-BNGW5ASC.js";
199
- import {
200
- parsePublicAgentId
201
- } from "./chunk-M2EJHDJP.js";
202
- import {
203
- asTrimmedString
204
- } from "./chunk-3EUW3WEO.js";
239
+ buildSkillDiscoveryContextLayer
240
+ } from "./chunk-AU7AXHUL.js";
205
241
  import {
206
- asOptionalTrimmedString
207
- } from "./chunk-G3SUCT4W.js";
242
+ buildAgentsMdLayer,
243
+ buildMemoryOverlayLayer,
244
+ buildMemoryUseGuidanceLayer,
245
+ partitionScopedBlocks,
246
+ renderTurnContextBlocksWithScope
247
+ } from "./chunk-VEA7H5FG.js";
248
+
249
+ // packages/agent-runtime/modelLayerOverride.ts
250
+ var MODEL_LAYER_KEYS = [
251
+ "provider",
252
+ "model",
253
+ "apiSource",
254
+ "cliProvider",
255
+ "useServerProxy",
256
+ "apiKey",
257
+ "apiKeyRef",
258
+ "apiKeyHeader",
259
+ "customProviderUrl",
260
+ "credentialRef",
261
+ "credentialSynced",
262
+ "temperature",
263
+ "top_p",
264
+ "frequency_penalty",
265
+ "presence_penalty",
266
+ "max_tokens",
267
+ "reasoning_effort",
268
+ "enableThinking",
269
+ "thinkingBudget"
270
+ ];
271
+ function mergeReferences(base, extra) {
272
+ const safeBase = Array.isArray(base) ? base : [];
273
+ const safeExtra = Array.isArray(extra) ? extra : [];
274
+ const seen = /* @__PURE__ */ new Set();
275
+ const merged = [];
276
+ for (const item of [...safeBase, ...safeExtra]) {
277
+ const key = item?.dbKey;
278
+ if (key && seen.has(key)) continue;
279
+ if (key) seen.add(key);
280
+ if (item) merged.push(item);
281
+ }
282
+ return merged;
283
+ }
284
+ var asNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
285
+ function buildModelLayerOverride(agent) {
286
+ if (!agent || !asNonEmptyString(agent.provider) || !asNonEmptyString(agent.model)) {
287
+ return null;
288
+ }
289
+ const override = {
290
+ provider: agent.provider,
291
+ model: agent.model
292
+ };
293
+ for (const key of MODEL_LAYER_KEYS) {
294
+ if (key === "provider" || key === "model") continue;
295
+ const value = agent[key];
296
+ if (value !== void 0) {
297
+ override[key] = value;
298
+ }
299
+ }
300
+ if (Array.isArray(agent.references) && agent.references.length > 0) {
301
+ override.references = agent.references;
302
+ }
303
+ return override;
304
+ }
305
+ function applyModelLayerOverride(base, override) {
306
+ const next = { ...base };
307
+ for (const key of MODEL_LAYER_KEYS) {
308
+ delete next[key];
309
+ }
310
+ for (const key of MODEL_LAYER_KEYS) {
311
+ const value = override[key];
312
+ if (value !== void 0) {
313
+ next[key] = value;
314
+ }
315
+ }
316
+ const merged = mergeReferences(
317
+ base.references,
318
+ override.references
319
+ );
320
+ if (merged.length > 0) {
321
+ next.references = merged;
322
+ } else {
323
+ delete next.references;
324
+ }
325
+ return next;
326
+ }
327
+
328
+ // packages/cli/tui/localAttachmentParts.ts
329
+ import { statSync } from "node:fs";
330
+ import path from "node:path";
331
+ var EXT_MIME = {
332
+ jpg: "image/jpeg",
333
+ jpeg: "image/jpeg",
334
+ png: "image/png",
335
+ gif: "image/gif",
336
+ webp: "image/webp",
337
+ bmp: "image/bmp",
338
+ tif: "image/tiff",
339
+ tiff: "image/tiff",
340
+ heic: "image/heic",
341
+ heif: "image/heif",
342
+ svg: "image/svg+xml",
343
+ mp3: "audio/mpeg",
344
+ m4a: "audio/mp4",
345
+ wav: "audio/wav",
346
+ ogg: "audio/ogg",
347
+ oga: "audio/ogg",
348
+ opus: "audio/opus",
349
+ flac: "audio/flac",
350
+ aac: "audio/aac",
351
+ amr: "audio/amr",
352
+ wma: "audio/x-ms-wma",
353
+ mp4: "video/mp4",
354
+ m4v: "video/x-m4v",
355
+ mov: "video/quicktime",
356
+ mkv: "video/x-matroska",
357
+ webm: "video/webm",
358
+ avi: "video/x-msvideo",
359
+ wmv: "video/x-ms-wmv",
360
+ mpg: "video/mpeg",
361
+ mpeg: "video/mpeg",
362
+ "3gp": "video/3gpp",
363
+ flv: "video/x-flv",
364
+ pdf: "application/pdf",
365
+ txt: "text/plain",
366
+ md: "text/markdown",
367
+ json: "application/json",
368
+ csv: "text/csv",
369
+ zip: "application/zip",
370
+ apk: "application/vnd.android.package-archive"
371
+ };
372
+ var mimeTypeForLocalPath = (filePath) => {
373
+ const ext = path.extname(filePath).slice(1).toLowerCase();
374
+ return EXT_MIME[ext] ?? "application/octet-stream";
375
+ };
376
+ var defaultStatSize = (filePath) => {
377
+ try {
378
+ const stat = statSync(filePath);
379
+ return stat.isFile() ? stat.size : null;
380
+ } catch {
381
+ return null;
382
+ }
383
+ };
384
+ var buildLocalAttachments = (input) => {
385
+ const machineId = typeof input.machineId === "string" ? input.machineId.trim() : "";
386
+ const workspaceRoot = typeof input.workspaceRoot === "string" ? input.workspaceRoot.trim() : "";
387
+ const statSize = input.statSize ?? defaultStatSize;
388
+ const mimeTypeOf = input.mimeTypeOf ?? mimeTypeForLocalPath;
389
+ const parts = [];
390
+ const skipped = [];
391
+ const seen = /* @__PURE__ */ new Set();
392
+ for (const raw of input.paths) {
393
+ const filePath = typeof raw === "string" ? raw.trim() : "";
394
+ if (!filePath || seen.has(filePath)) continue;
395
+ seen.add(filePath);
396
+ if (!machineId) {
397
+ skipped.push({ path: filePath, reason: "machine-unbound" });
398
+ continue;
399
+ }
400
+ const size = statSize(filePath);
401
+ if (size === null || !Number.isFinite(size) || size < 0) {
402
+ skipped.push({ path: filePath, reason: "unreadable" });
403
+ continue;
404
+ }
405
+ const normalized = normalizeAttachmentPart({
406
+ type: ATTACHMENT_PART_TYPE,
407
+ v: ATTACHMENT_PART_VERSION,
408
+ source: {
409
+ kind: "local-file",
410
+ path: filePath,
411
+ machineId,
412
+ ...workspaceRoot ? { workspaceRoot } : {}
413
+ },
414
+ name: path.basename(filePath),
415
+ mimeType: mimeTypeOf(filePath),
416
+ size
417
+ });
418
+ if (normalized.status !== "valid") {
419
+ skipped.push({ path: filePath, reason: "invalid-part" });
420
+ continue;
421
+ }
422
+ parts.push(normalized.attachment);
423
+ }
424
+ const cardText = parts.map((part) => describeAttachmentForModel(part)).join("\n");
425
+ return { parts, skipped, cardText };
426
+ };
427
+ var appendAttachmentCard = (message, cardText) => {
428
+ if (!cardText) return message;
429
+ return message.trim() ? `${message}
430
+
431
+ ${cardText}` : cardText;
432
+ };
433
+
434
+ // packages/chat/messages/attachmentWriteRollout.ts
435
+ var ENABLE_REMOTE_ATTACHMENT_PART_WRITES = false;
436
+
437
+ // packages/ai/context/contextOccupancy.ts
438
+ function estimateMessagesTokens(messages) {
439
+ return messages.reduce((total, message) => {
440
+ const content = typeof message.content === "string" ? message.content : message.content == null ? "" : JSON.stringify(message.content);
441
+ return total + estimateTokenCount(content) + 4;
442
+ }, 0);
443
+ }
444
+ function historyTokensBeforeLatestAssistant(messages) {
445
+ const total = estimateMessagesTokens(messages);
446
+ const latest = messages[messages.length - 1];
447
+ if (latest?.role !== "assistant") return total;
448
+ return Math.max(0, total - estimateMessagesTokens([latest]));
449
+ }
450
+ function resolveOccupancy(input) {
451
+ if (input.authoritativeInput !== void 0 && input.authoritativeInput > 0) {
452
+ const generated = Math.max(0, input.generatedSinceAuthority ?? 0);
453
+ return {
454
+ tokens: input.authoritativeInput + generated,
455
+ estimated: generated > 0
456
+ };
457
+ }
458
+ return {
459
+ tokens: Math.max(0, input.baselineEstimate ?? 0),
460
+ estimated: true
461
+ };
462
+ }
463
+ function resolveOccupancyWindow(ref) {
464
+ if (!ref.model) return void 0;
465
+ if (isDevinOAuthAgent(ref)) {
466
+ return devinChannelContextWindow(ref.model) ?? findModelContextWindow(ref.model, ref.provider);
467
+ }
468
+ return findModelContextWindow(ref.model, ref.provider);
469
+ }
208
470
 
209
471
  // packages/cli/client/tokenUsage.ts
210
472
  var PLATFORM_CREDIT_UNIT = "credits";
@@ -216,7 +478,9 @@ function resolveEffectiveModel(opts) {
216
478
  if (isUsableModelId(opts.model)) return opts.model;
217
479
  const agentKey = opts.agentKey?.trim();
218
480
  if (!agentKey) return void 0;
219
- return builtinAgentCatalogEntryById(parsePublicAgentId(agentKey))?.model;
481
+ return builtinAgentCatalogEntryById(
482
+ parseBuiltinPlatformAgentId(agentKey) ?? parsePublicAgentId(agentKey)
483
+ )?.model;
220
484
  }
221
485
  function resolveAgentModelIdentity(opts) {
222
486
  const model = resolveEffectiveModel(opts);
@@ -229,11 +493,32 @@ function resolveAgentModelIdentity(opts) {
229
493
  }
230
494
  function resolveAgentContextWindow(opts) {
231
495
  const model = resolveEffectiveModel(opts);
232
- if (model) return getModelContextWindow(model);
233
- if (opts.agentName?.trim()) {
234
- return getModelContextWindow(opts.agentName);
496
+ if (model) return resolveContextWindow(model);
497
+ const byName = opts.agentName?.trim() ? resolveOccupancyWindow({ model: opts.agentName }) : void 0;
498
+ if (byName !== void 0) return byName;
499
+ const candidates = [
500
+ ...modelSlugCandidates(opts.agentKey, 2),
501
+ ...modelSlugCandidates(opts.agentName, 1)
502
+ ];
503
+ for (const candidate of candidates) {
504
+ const window = resolveOccupancyWindow({ model: candidate });
505
+ if (window !== void 0) return window;
506
+ }
507
+ return void 0;
508
+ }
509
+ var AGENT_KEY_PREFIX = /^agent-[a-z0-9]+-/i;
510
+ function modelSlugCandidates(source, maxDrop) {
511
+ const raw = source?.trim();
512
+ if (!raw) return [];
513
+ const base = raw.replace(/\s+/g, "-").toLowerCase();
514
+ const seed = base.replace(AGENT_KEY_PREFIX, "");
515
+ const out = [seed];
516
+ if (seed !== base) out.push(base);
517
+ const segments = seed.split("-");
518
+ for (let drop = 1; drop <= maxDrop && drop < segments.length; drop++) {
519
+ out.push(segments.slice(drop).join("-"));
235
520
  }
236
- return DEFAULT_CONTEXT_WINDOW;
521
+ return [...new Set(out.filter(Boolean))];
237
522
  }
238
523
  var PROVIDER_LOOKUP_ORDER = [
239
524
  "openrouter",
@@ -271,7 +556,7 @@ function resolveContextWindow(model) {
271
556
  const config = findModelConfig(provider, raw);
272
557
  if (config?.contextWindow) return config.contextWindow;
273
558
  }
274
- return getModelContextWindow(raw);
559
+ return resolveOccupancyWindow({ model: raw });
275
560
  }
276
561
  function buildTurnTokenUsage(usage, model) {
277
562
  const parsed = parseUsageRecord(usage);
@@ -324,11 +609,66 @@ function formatTokenCount(value) {
324
609
  const compact = value / 1e6;
325
610
  return compact >= 100 ? `${Math.round(compact)}M` : `${compact.toFixed(1).replace(/\.0$/, "")}M`;
326
611
  }
327
- function renderTokenStatus(tokens) {
328
- if (!tokens) return "in \u2014 out \u2014 left \u2014";
329
- const left = tokens.remaining != null ? formatTokenCount(tokens.remaining) : tokens.contextWindow ? "\u2014" : "\u2014";
330
- const cache = tokens.cacheRead != null && tokens.cacheRead > 0 ? ` (cache ${formatTokenCount(tokens.cacheRead)})` : "";
331
- return `in ${formatTokenCount(tokens.input)}${cache} out ${formatTokenCount(tokens.output)} left ${left}`;
612
+ function resolveAuthorityTurnCount(turns) {
613
+ if (turns.length === 0) return 0;
614
+ const latest = turns[turns.length - 1];
615
+ if (latest?.role === "assistant") {
616
+ return Math.max(0, turns.length - 1);
617
+ }
618
+ return turns.length;
619
+ }
620
+ function computeBaselineContextTokens(options) {
621
+ const { authoritativeInput, lastAuthorityTurnCount, turns, fallbackEstimate } = options;
622
+ if (authoritativeInput !== void 0 && authoritativeInput > 0 && lastAuthorityTurnCount !== void 0 && lastAuthorityTurnCount >= 0) {
623
+ const turnsSinceAuthority = turns.slice(lastAuthorityTurnCount);
624
+ const addedTokens = estimateMessagesTokens(turnsSinceAuthority);
625
+ return authoritativeInput + addedTokens;
626
+ }
627
+ return typeof fallbackEstimate === "function" ? fallbackEstimate() : fallbackEstimate;
628
+ }
629
+ function resolveContextUsage(opts = {}) {
630
+ const tokens = opts.tokens;
631
+ const contextWindow = tokens?.contextWindow ?? opts.fallbackContextWindow;
632
+ const authoritativeInput = tokens && tokens.input > 0 ? tokens.input : void 0;
633
+ const baselineEstimate = opts.estimatedContextTokens != null && opts.estimatedContextTokens > 0 ? opts.estimatedContextTokens : void 0;
634
+ const generatedSinceAuthority = opts.turnEstimatedTokens != null && opts.turnEstimatedTokens > 0 ? opts.turnEstimatedTokens : void 0;
635
+ const occupancy = resolveOccupancy({
636
+ authoritativeInput,
637
+ baselineEstimate: authoritativeInput === void 0 && baselineEstimate !== void 0 ? baselineEstimate + (generatedSinceAuthority ?? 0) : baselineEstimate,
638
+ generatedSinceAuthority
639
+ });
640
+ const hasInputSignal = authoritativeInput !== void 0 || baselineEstimate !== void 0 || generatedSinceAuthority !== void 0;
641
+ const used = hasInputSignal ? occupancy.tokens : void 0;
642
+ const usage = { estimated: occupancy.estimated };
643
+ if (used !== void 0) usage.used = used;
644
+ if (contextWindow != null) usage.contextWindow = contextWindow;
645
+ if (used !== void 0 && contextWindow != null && contextWindow > 0) {
646
+ usage.left = Math.max(0, contextWindow - used);
647
+ usage.pct = used / contextWindow * 100;
648
+ }
649
+ return usage;
650
+ }
651
+ function renderTokenStatus(tokens, fallback) {
652
+ const usage = resolveContextUsage({
653
+ tokens,
654
+ fallbackContextWindow: fallback?.contextWindow,
655
+ estimatedContextTokens: fallback?.estimatedContextTokens,
656
+ turnEstimatedTokens: fallback?.turnEstimatedTokens
657
+ });
658
+ const cache = tokens?.cacheRead != null && tokens.cacheRead > 0 ? ` (cache ${formatTokenCount(tokens.cacheRead)})` : "";
659
+ if (usage.contextWindow === void 0) {
660
+ const inStr = usage.used !== void 0 ? `${usage.estimated ? "~" : ""}${formatTokenCount(usage.used)}` : "\u2014";
661
+ const outStr = tokens ? formatTokenCount(tokens.output) : "\u2014";
662
+ return `in ${inStr}${cache} out ${outStr} left \u2014`;
663
+ }
664
+ if (!tokens) {
665
+ if (usage.used === void 0) return "in \u2014 out \u2014 left \u2014";
666
+ const left2 = usage.left !== void 0 ? `~${formatTokenCount(usage.left)}` : "\u2014";
667
+ return `in ~${formatTokenCount(usage.used)} out \u2014 left ${left2}`;
668
+ }
669
+ const inputText = tokens.input > 0 || usage.used === void 0 ? formatTokenCount(tokens.input) : `~${formatTokenCount(usage.used)}`;
670
+ const left = tokens.remaining != null ? formatTokenCount(tokens.remaining) : usage.left !== void 0 ? `${usage.estimated ? "~" : ""}${formatTokenCount(usage.left)}` : "\u2014";
671
+ return `in ${inputText}${cache} out ${formatTokenCount(tokens.output)} left ${left}`;
332
672
  }
333
673
  function shouldShowUsage(env) {
334
674
  return env.NOLO_DEBUG === "1" || env.NOLO_SHOW_USAGE === "1";
@@ -1013,11 +1353,17 @@ function wrapTranscriptLineWithLayout(line, columns, hangingIndent = "", lineSou
1013
1353
  activeStyles.push(value);
1014
1354
  }
1015
1355
  };
1356
+ let lastContentTokenIndex = -1;
1357
+ for (let i = tokens.length - 1; i >= 0; i -= 1) {
1358
+ if (tokens[i].kind !== "sgr") {
1359
+ lastContentTokenIndex = i;
1360
+ break;
1361
+ }
1362
+ }
1363
+ let plainCharIndexAtStart = 0;
1016
1364
  let start = 0;
1017
1365
  while (start < tokens.length) {
1018
- if (tokens.slice(start).every((token) => token.kind === "sgr")) {
1019
- if (rows.length > 0) break;
1020
- }
1366
+ if (start > lastContentTokenIndex && rows.length > 0) break;
1021
1367
  const openingStyles = [...activeStyles];
1022
1368
  const isContinuation = rows.length > 0;
1023
1369
  const currentPrefixWidth = isContinuation ? visibleWidth(hangingIndent) : prefixWidth;
@@ -1065,13 +1411,7 @@ function wrapTranscriptLineWithLayout(line, columns, hangingIndent = "", lineSou
1065
1411
  let segSourceEnd = lineSourceStart;
1066
1412
  let foundFirst = false;
1067
1413
  const rowMapping = [];
1068
- let plainCharIndex = 0;
1069
- for (let i = 0; i < start; i++) {
1070
- const tok = tokens[i];
1071
- if (tok.kind === "char" && tok.charIndex >= prefixCharCount) {
1072
- plainCharIndex += tok.value.length;
1073
- }
1074
- }
1414
+ let plainCharIndex = plainCharIndexAtStart;
1075
1415
  for (let i = start; i < segmentEnd; i++) {
1076
1416
  const tok = tokens[i];
1077
1417
  if (tok.kind === "char" && tok.charIndex >= prefixCharCount) {
@@ -1108,6 +1448,7 @@ function wrapTranscriptLineWithLayout(line, columns, hangingIndent = "", lineSou
1108
1448
  if (start >= tokens.length && rawLineLength !== void 0) {
1109
1449
  segSourceEnd = lineSourceStart + rawLineLength;
1110
1450
  }
1451
+ plainCharIndexAtStart = plainCharIndex;
1111
1452
  rows.push({
1112
1453
  rendered: rowRendered,
1113
1454
  sourceStart: segSourceStart,
@@ -1527,6 +1868,19 @@ function surfaceBackgroundSequence(env = process.env, brightness = resolveTuiBri
1527
1868
  if (!supportsTruecolor(env)) return "";
1528
1869
  return hexToBgSgr((SURFACE_HEX[activeThemeName] ?? SURFACE_HEX.trail)[brightness]);
1529
1870
  }
1871
+ function composerSurfaceBackgroundSequence(env = process.env, brightness = resolveTuiBrightness(env)) {
1872
+ if (!supportsTruecolor(env)) return "";
1873
+ if (resolveTuiThemeMode(env) === "terminal" && activeTerminalBaseHex === null && detectColorFgBgBrightness(env) === null) {
1874
+ return "";
1875
+ }
1876
+ const base = resolveTerminalBaseHex(brightness);
1877
+ const channels = readHexChannels(base.replace(/^#/, "").toUpperCase());
1878
+ const baseLuma = channels ? (0.299 * channels[0] + 0.587 * channels[1] + 0.114 * channels[2]) / 255 : null;
1879
+ const darkCanvas = baseLuma === null ? brightness === "dark" : baseLuma < 0.5;
1880
+ const tint = darkCanvas ? "FFFFFF" : "000000";
1881
+ const weight = darkCanvas ? 0.1 : 0.07;
1882
+ return hexToBgSgr(blendHex(tint, base, weight));
1883
+ }
1530
1884
  function userSurfaceBackgroundSequence(env = process.env, brightness = resolveTuiBrightness(env)) {
1531
1885
  if (!supportsTruecolor(env)) return "";
1532
1886
  if (resolveTuiThemeMode(env) === "terminal" && activeTerminalBaseHex === null && detectColorFgBgBrightness(env) === null) {
@@ -8462,6 +8816,68 @@ function styleRichMarkdownLine(line, brightness) {
8462
8816
  }
8463
8817
  return styleInlineMarkdown(line, brightness);
8464
8818
  }
8819
+ var FenceTracker = class {
8820
+ inFence = false;
8821
+ inMermaid = false;
8822
+ fenceLang = "unknown";
8823
+ mermaidBody = [];
8824
+ isInFence() {
8825
+ return this.inFence;
8826
+ }
8827
+ isInMermaid() {
8828
+ return this.inMermaid;
8829
+ }
8830
+ processLine(line) {
8831
+ if (isCodeFenceLine(line)) {
8832
+ if (this.inMermaid) {
8833
+ const body = this.mermaidBody;
8834
+ this.mermaidBody = [];
8835
+ this.inMermaid = false;
8836
+ this.inFence = false;
8837
+ this.fenceLang = "unknown";
8838
+ return { kind: "close-mermaid", body };
8839
+ }
8840
+ if (this.inFence) {
8841
+ this.inFence = false;
8842
+ this.fenceLang = "unknown";
8843
+ return { kind: "close-code" };
8844
+ }
8845
+ const lang = readFenceLanguage(line);
8846
+ this.fenceLang = normalizeCodeLang(lang);
8847
+ this.inFence = true;
8848
+ if (/^mermaid$/i.test(lang)) {
8849
+ this.inMermaid = true;
8850
+ this.mermaidBody = [];
8851
+ return { kind: "open" };
8852
+ }
8853
+ return { kind: "open" };
8854
+ }
8855
+ if (this.inMermaid) {
8856
+ this.mermaidBody.push(line);
8857
+ return { kind: "mermaid-body" };
8858
+ }
8859
+ if (this.inFence) {
8860
+ return { kind: "code-line", lang: this.fenceLang };
8861
+ }
8862
+ return { kind: "outside" };
8863
+ }
8864
+ /**
8865
+ * Take unclosed mermaid body lines if currently inside a mermaid block.
8866
+ * Resets mermaid and fence state. Returns null if not in a mermaid block.
8867
+ */
8868
+ flushMermaid(extraLines) {
8869
+ if (!this.inMermaid) return null;
8870
+ if (extraLines && extraLines.length > 0) {
8871
+ this.mermaidBody.push(...extraLines);
8872
+ }
8873
+ const body = this.mermaidBody;
8874
+ this.mermaidBody = [];
8875
+ this.inMermaid = false;
8876
+ this.inFence = false;
8877
+ this.fenceLang = "unknown";
8878
+ return body;
8879
+ }
8880
+ };
8465
8881
  function renderMermaidBody(bodyLines, brightness) {
8466
8882
  const body = bodyLines.join("\n");
8467
8883
  const rendered = renderMermaidBlock(body, brightness, true);
@@ -8476,52 +8892,27 @@ function formatAssistantDisplay(text, options = {}) {
8476
8892
  const lines = polished.split("\n");
8477
8893
  const out = [];
8478
8894
  let i = 0;
8479
- let inFence = false;
8480
- let fenceLang = "unknown";
8481
- let inMermaid = false;
8482
- let mermaidBody = null;
8483
- const flushMermaid = () => {
8484
- if (mermaidBody !== null) {
8485
- out.push(renderMermaidBody(mermaidBody, brightness));
8486
- mermaidBody = null;
8487
- }
8488
- };
8895
+ const tracker = new FenceTracker();
8489
8896
  while (i < lines.length) {
8490
8897
  const line = lines[i];
8491
- if (isCodeFenceLine(line)) {
8492
- const lang = readFenceLanguage(line);
8493
- if (inMermaid) {
8494
- flushMermaid();
8495
- inMermaid = false;
8496
- inFence = false;
8497
- out.push(`${STYLE.dim}${line}${STYLE.reset}`);
8498
- i++;
8499
- continue;
8500
- }
8501
- if (inFence) {
8502
- fenceLang = "unknown";
8503
- inFence = false;
8504
- out.push(`${STYLE.dim}${line}${STYLE.reset}`);
8505
- i++;
8506
- continue;
8507
- }
8508
- inFence = true;
8509
- fenceLang = normalizeCodeLang(lang);
8510
- if (/^mermaid$/i.test(lang)) {
8511
- inMermaid = true;
8512
- mermaidBody = [];
8513
- }
8898
+ const event = tracker.processLine(line);
8899
+ if (event.kind === "close-mermaid") {
8900
+ out.push(renderMermaidBody(event.body, brightness));
8514
8901
  out.push(`${STYLE.dim}${line}${STYLE.reset}`);
8515
8902
  i++;
8516
8903
  continue;
8517
8904
  }
8518
- if (inMermaid && mermaidBody !== null) {
8519
- mermaidBody.push(line);
8905
+ if (event.kind === "open" || event.kind === "close-code") {
8906
+ out.push(`${STYLE.dim}${line}${STYLE.reset}`);
8520
8907
  i++;
8521
8908
  continue;
8522
8909
  }
8523
- if (inFence) {
8524
- out.push(highlightCodeLine(line, fenceLang, brightness));
8910
+ if (event.kind === "mermaid-body") {
8911
+ i++;
8912
+ continue;
8913
+ }
8914
+ if (event.kind === "code-line") {
8915
+ out.push(highlightCodeLine(line, event.lang, brightness));
8525
8916
  i++;
8526
8917
  continue;
8527
8918
  }
@@ -8562,7 +8953,10 @@ function formatAssistantDisplay(text, options = {}) {
8562
8953
  out.push(styleRichMarkdownLine(line, brightness));
8563
8954
  i++;
8564
8955
  }
8565
- flushMermaid();
8956
+ const unclosed = tracker.flushMermaid();
8957
+ if (unclosed !== null) {
8958
+ out.push(renderMermaidBody(unclosed, brightness));
8959
+ }
8566
8960
  return out.join("\n");
8567
8961
  }
8568
8962
  function emitFormattedAssistantBlock(write, text, trailingNewline = false) {
@@ -8598,10 +8992,7 @@ function needsListProseBreath(prev, next, prevLine = "") {
8598
8992
  function createRenderAwareStreamWriter(args) {
8599
8993
  const brightness = resolveTuiBrightness();
8600
8994
  let buffer = "";
8601
- let inFence = false;
8602
- let fenceLang = "unknown";
8603
- let inMermaid = false;
8604
- let mermaidBody = [];
8995
+ const tracker = new FenceTracker();
8605
8996
  let lastKind = null;
8606
8997
  let lastLine = "";
8607
8998
  let pendingBlankRow = false;
@@ -8615,7 +9006,7 @@ function createRenderAwareStreamWriter(args) {
8615
9006
  if (needsListProseBreath(lastKind, nextKind, lastLine)) args.write("\n");
8616
9007
  };
8617
9008
  const flushPartialProse = () => {
8618
- if (inFence || buffer.length < PARTIAL_FLUSH_THRESHOLD) return;
9009
+ if (tracker.isInFence() || buffer.length < PARTIAL_FLUSH_THRESHOLD) return;
8619
9010
  const firstLine = buffer.split("\n", 1)[0] ?? "";
8620
9011
  if (isTableRow(firstLine) || classifyStreamLine(firstLine) !== "prose") return;
8621
9012
  const Segmenter = Intl.Segmenter;
@@ -8638,34 +9029,19 @@ function createRenderAwareStreamWriter(args) {
8638
9029
  const lines = buffer.split("\n");
8639
9030
  if (lines.length < 2) break;
8640
9031
  const firstLine = lines[0] ?? "";
8641
- if (isCodeFenceLine(firstLine)) {
8642
- if (inMermaid) {
8643
- const diagram = renderMermaidBody(mermaidBody, brightness);
8644
- args.write(diagram + "\n");
8645
- mermaidBody = [];
8646
- inMermaid = false;
8647
- inFence = false;
8648
- fenceLang = "unknown";
8649
- emitBreathIfNeeded("fence");
8650
- args.write(`${STYLE.dim}${firstLine}${STYLE.reset}
9032
+ const event = tracker.processLine(firstLine);
9033
+ if (event.kind === "close-mermaid") {
9034
+ const diagram = renderMermaidBody(event.body, brightness);
9035
+ args.write(diagram + "\n");
9036
+ emitBreathIfNeeded("fence");
9037
+ args.write(`${STYLE.dim}${firstLine}${STYLE.reset}
8651
9038
  `);
8652
- lastKind = "fence";
8653
- lastLine = firstLine;
8654
- buffer = lines.slice(1).join("\n");
8655
- continue;
8656
- }
8657
- if (inFence) {
8658
- fenceLang = "unknown";
8659
- inFence = false;
8660
- } else {
8661
- const lang = readFenceLanguage(firstLine);
8662
- fenceLang = normalizeCodeLang(lang);
8663
- if (/^mermaid$/i.test(lang)) {
8664
- inMermaid = true;
8665
- mermaidBody = [];
8666
- }
8667
- inFence = true;
8668
- }
9039
+ lastKind = "fence";
9040
+ lastLine = firstLine;
9041
+ buffer = lines.slice(1).join("\n");
9042
+ continue;
9043
+ }
9044
+ if (event.kind === "open" || event.kind === "close-code") {
8669
9045
  emitBreathIfNeeded("fence");
8670
9046
  args.write(`${STYLE.dim}${firstLine}${STYLE.reset}
8671
9047
  `);
@@ -8674,13 +9050,12 @@ function createRenderAwareStreamWriter(args) {
8674
9050
  buffer = lines.slice(1).join("\n");
8675
9051
  continue;
8676
9052
  }
8677
- if (inMermaid) {
8678
- mermaidBody.push(firstLine);
9053
+ if (event.kind === "mermaid-body") {
8679
9054
  buffer = lines.slice(1).join("\n");
8680
9055
  continue;
8681
9056
  }
8682
- if (inFence) {
8683
- args.write(`${highlightCodeLine(firstLine, fenceLang, brightness)}
9057
+ if (event.kind === "code-line") {
9058
+ args.write(`${highlightCodeLine(firstLine, event.lang, brightness)}
8684
9059
  `);
8685
9060
  lastKind = "fence";
8686
9061
  lastLine = firstLine;
@@ -8688,7 +9063,7 @@ function createRenderAwareStreamWriter(args) {
8688
9063
  continue;
8689
9064
  }
8690
9065
  const trimmedFirst = firstLine.trim();
8691
- if ((trimmedFirst.startsWith("$$") || trimmedFirst.startsWith("\\[")) && !inFence) {
9066
+ if ((trimmedFirst.startsWith("$$") || trimmedFirst.startsWith("\\[")) && !tracker.isInFence()) {
8692
9067
  const isBracket = trimmedFirst.startsWith("\\[");
8693
9068
  const closeMarker = isBracket ? "\\]" : "$$";
8694
9069
  if (trimmedFirst.length > 2 && trimmedFirst.endsWith(closeMarker)) {
@@ -8772,16 +9147,17 @@ function createRenderAwareStreamWriter(args) {
8772
9147
  flushPartialProse();
8773
9148
  },
8774
9149
  flush() {
8775
- if (inMermaid) {
8776
- if (buffer) mermaidBody.push(...buffer.split("\n"));
8777
- args.write(renderMermaidBody(mermaidBody, brightness) + "\n");
8778
- mermaidBody = [];
8779
- inMermaid = false;
9150
+ if (tracker.isInMermaid()) {
9151
+ const extra = buffer ? buffer.split("\n") : void 0;
9152
+ const unclosed = tracker.flushMermaid(extra);
9153
+ if (unclosed !== null) {
9154
+ args.write(renderMermaidBody(unclosed, brightness) + "\n");
9155
+ }
8780
9156
  buffer = "";
8781
9157
  return;
8782
9158
  }
8783
9159
  if (!buffer) return;
8784
- if (inFence) {
9160
+ if (tracker.isInFence()) {
8785
9161
  args.write(buffer);
8786
9162
  } else {
8787
9163
  emitFormattedAssistantBlock(args.write, buffer);
@@ -8806,17 +9182,45 @@ function redactSecrets(text) {
8806
9182
  );
8807
9183
  }
8808
9184
 
8809
- // node_modules/diff/libesm/diff/base.js
8810
- var Diff = class {
8811
- diff(oldStr, newStr, options = {}) {
8812
- let callback;
8813
- if (typeof options === "function") {
8814
- callback = options;
8815
- options = {};
8816
- } else if ("callback" in options) {
8817
- callback = options.callback;
8818
- }
8819
- const oldString = this.castInput(oldStr, options);
9185
+ // packages/cli/tui/askTextSanitize.ts
9186
+ var ASK_SECRET_PLACEHOLDER = "\u27E8redacted\u27E9";
9187
+ var C0_C1_CONTROL_REGEX = /[\x00-\x1f\x7f-\x9f]/g;
9188
+ var NORMAL_GIST_SECRET_PATTERNS = [
9189
+ /\bbearer\s+[A-Za-z0-9._~+/=-]{8,}/i,
9190
+ /\bsk-(?:ant-)?(?:api)?[0-9a-zA-Z-]{10,}/,
9191
+ /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{10,}/,
9192
+ /\bxox[baprs]-[A-Za-z0-9-]{10,}/
9193
+ ];
9194
+ function withholdIfSecretLike(gist) {
9195
+ if (!gist) return "";
9196
+ if (findPotentialSecrets(gist).length > 0) return "";
9197
+ if (NORMAL_GIST_SECRET_PATTERNS.some((pattern) => pattern.test(gist))) return "";
9198
+ return gist;
9199
+ }
9200
+ function toText(value) {
9201
+ return typeof value === "string" ? value : String(value ?? "");
9202
+ }
9203
+ function cleanAskText(value) {
9204
+ return stripAnsi2(toText(value)).replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").replace(C0_C1_CONTROL_REGEX, "").replace(/\s+/g, " ").trim();
9205
+ }
9206
+ function safeAskText(value, max) {
9207
+ const cleaned = redactSecrets(cleanAskText(value));
9208
+ if (!cleaned) return "";
9209
+ const guarded = withholdIfSecretLike(cleaned) || ASK_SECRET_PLACEHOLDER;
9210
+ return max === void 0 ? guarded : clipCompactText(guarded, max, "\u2026");
9211
+ }
9212
+
9213
+ // node_modules/diff/libesm/diff/base.js
9214
+ var Diff = class {
9215
+ diff(oldStr, newStr, options = {}) {
9216
+ let callback;
9217
+ if (typeof options === "function") {
9218
+ callback = options;
9219
+ options = {};
9220
+ } else if ("callback" in options) {
9221
+ callback = options.callback;
9222
+ }
9223
+ const oldString = this.castInput(oldStr, options);
8820
9224
  const newString = this.castInput(newStr, options);
8821
9225
  const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
8822
9226
  const newTokens = this.removeEmpty(this.tokenize(newString, options));
@@ -8906,16 +9310,16 @@ var Diff = class {
8906
9310
  }
8907
9311
  }
8908
9312
  }
8909
- addToPath(path, added, removed, oldPosInc, options) {
8910
- const last = path.lastComponent;
9313
+ addToPath(path2, added, removed, oldPosInc, options) {
9314
+ const last = path2.lastComponent;
8911
9315
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
8912
9316
  return {
8913
- oldPos: path.oldPos + oldPosInc,
9317
+ oldPos: path2.oldPos + oldPosInc,
8914
9318
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
8915
9319
  };
8916
9320
  } else {
8917
9321
  return {
8918
- oldPos: path.oldPos + oldPosInc,
9322
+ oldPos: path2.oldPos + oldPosInc,
8919
9323
  lastComponent: { count: 1, added, removed, previousComponent: last }
8920
9324
  };
8921
9325
  }
@@ -9060,14 +9464,14 @@ function tokenize(value, options) {
9060
9464
  import { homedir as osHomedir } from "node:os";
9061
9465
 
9062
9466
  // packages/core/foldHomePath.ts
9063
- function foldHomePath(path, home) {
9064
- if (!path) return path;
9467
+ function foldHomePath(path2, home) {
9468
+ if (!path2) return path2;
9065
9469
  if (home) {
9066
9470
  const cleanHome = home.endsWith("/") ? home.slice(0, -1) : home;
9067
- if (path === cleanHome) return "~";
9068
- if (path.startsWith(cleanHome + "/")) return `~${path.slice(cleanHome.length)}`;
9471
+ if (path2 === cleanHome) return "~";
9472
+ if (path2.startsWith(cleanHome + "/")) return `~${path2.slice(cleanHome.length)}`;
9069
9473
  }
9070
- return path.replace(/^(\/Users\/[^/]+|\/home\/[^/]+)(\/|$)/, "~$2");
9474
+ return path2.replace(/^(\/Users\/[^/]+|\/home\/[^/]+)(\/|$)/, "~$2");
9071
9475
  }
9072
9476
 
9073
9477
  // packages/cli/client/formatReadPathTree.ts
@@ -9094,10 +9498,10 @@ function clipPathAware(value, max = 72) {
9094
9498
  if (filenameOnly.length <= max) return filenameOnly;
9095
9499
  return clipCompactText(value, max, "\u2026");
9096
9500
  }
9097
- function formatHomePath(path, customHomedir) {
9098
- if (!path) return "";
9501
+ function formatHomePath(path2, customHomedir) {
9502
+ if (!path2) return "";
9099
9503
  const home = customHomedir || (typeof process !== "undefined" ? process.env?.HOME : void 0) || (typeof osHomedir === "function" ? osHomedir() : "");
9100
- return foldHomePath(path, home);
9504
+ return foldHomePath(path2, home);
9101
9505
  }
9102
9506
  function formatReadItemPath(rawPath, metadata, customHomedir) {
9103
9507
  const inputPath = rawPath || (typeof metadata?.path === "string" ? metadata.path : void 0) || (typeof metadata?.filePath === "string" ? metadata.filePath : void 0) || "file";
@@ -9117,10 +9521,10 @@ function formatReadItemPath(rawPath, metadata, customHomedir) {
9117
9521
  const clippedPath = clipPathAware(formattedPath, 72);
9118
9522
  return `${clippedPath}${rangePart}`;
9119
9523
  }
9120
- function formatSearchItemQuery(query, path, customHomedir) {
9524
+ function formatSearchItemQuery(query, path2, customHomedir) {
9121
9525
  let text = (query || "").trim();
9122
- if (path) {
9123
- const formattedPath = formatHomePath(path, customHomedir);
9526
+ if (path2) {
9527
+ const formattedPath = formatHomePath(path2, customHomedir);
9124
9528
  if (formattedPath) {
9125
9529
  text = text ? `${text} in ${formattedPath}` : formattedPath;
9126
9530
  }
@@ -9176,7 +9580,7 @@ function parseUiAskChoiceForCli(event) {
9176
9580
  label: String(parsed.selected.label ?? "").trim(),
9177
9581
  userMessage: String(parsed.selected.userMessage ?? "").trim()
9178
9582
  } : void 0;
9179
- const answers = Array.isArray(parsed.answers) ? parsed.answers : void 0;
9583
+ const answers = Array.isArray(parsed.answers) ? parsed.answers.filter((a) => Boolean(a && typeof a === "object")) : void 0;
9180
9584
  const cancelled = Boolean(parsed.cancelled);
9181
9585
  const resolved = Boolean(
9182
9586
  event.metadata?.resolved || selected || cancelled || answers && answers.length > 0
@@ -9197,7 +9601,7 @@ function formatUiAskChoiceBlock(event, colorEnabled) {
9197
9601
  if (!parsed) return null;
9198
9602
  const lines = [];
9199
9603
  lines.push("");
9200
- const questionText = parsed.question || "";
9604
+ const questionText = safeAskText(parsed.question, 200);
9201
9605
  if (colorEnabled) {
9202
9606
  lines.push(`${themeText("\u2753 ", "info", true)}${styleCliText(questionText, "cyan", true)}`);
9203
9607
  } else {
@@ -9212,7 +9616,8 @@ function formatUiAskChoiceBlock(event, colorEnabled) {
9212
9616
  return `${lines.join("\n")}
9213
9617
  `;
9214
9618
  }
9215
- const selectedLabel = parsed.selected?.label || parsed.selected?.userMessage || (parsed.answers ? parsed.answers.map((a) => a.userMessage).filter(Boolean).join(", ") : "");
9619
+ const rawSelected = parsed.selected?.label || parsed.selected?.userMessage;
9620
+ const selectedLabel = rawSelected ? safeAskText(rawSelected, 160) : parsed.answers ? parsed.answers.map((a) => safeAskText(a.userMessage, 160)).filter(Boolean).join(", ") : "";
9216
9621
  const marker = t("askChoiceHistorySelected");
9217
9622
  const displayLabel = selectedLabel || "\u2014";
9218
9623
  if (colorEnabled) {
@@ -9225,8 +9630,9 @@ function formatUiAskChoiceBlock(event, colorEnabled) {
9225
9630
  if (parsed.answers && parsed.answers.length > 1) {
9226
9631
  for (const answer of parsed.answers) {
9227
9632
  if (!answer.userMessage) continue;
9633
+ const answerText = safeAskText(answer.userMessage, 160);
9228
9634
  lines.push(
9229
- colorEnabled ? ` ${themeText("\xB7", "chrome", true)} ${answer.userMessage}` : ` \xB7 ${answer.userMessage}`
9635
+ colorEnabled ? ` ${themeText("\xB7", "chrome", true)} ${answerText}` : ` \xB7 ${answerText}`
9230
9636
  );
9231
9637
  }
9232
9638
  }
@@ -9235,7 +9641,7 @@ function formatUiAskChoiceBlock(event, colorEnabled) {
9235
9641
  }
9236
9642
  parsed.choices.forEach((choice, i) => {
9237
9643
  const num = String(i + 1);
9238
- const label = choice.label;
9644
+ const label = safeAskText(choice.label, 160);
9239
9645
  if (colorEnabled) {
9240
9646
  lines.push(
9241
9647
  ` ${themeText(num + ".", "chrome", true)} ${label}`
@@ -9251,6 +9657,87 @@ function formatUiAskChoiceBlock(event, colorEnabled) {
9251
9657
  lines.push(` ${hint}`);
9252
9658
  }
9253
9659
  return `${lines.join("\n")}
9660
+ `;
9661
+ }
9662
+ function formatShowInteractionBlock(event, colorEnabled) {
9663
+ const label = toolLabel(event.toolName || "show_interaction");
9664
+ let parsedPayload;
9665
+ if (typeof event.content === "string") {
9666
+ try {
9667
+ parsedPayload = JSON.parse(event.content);
9668
+ } catch {
9669
+ const metadata = event.metadata ?? {};
9670
+ const rawMetaError = metadata.error ?? metadata.errorMessage;
9671
+ const rawMessage = event.message?.trim();
9672
+ const rawContent = event.content.trim();
9673
+ let reason = "";
9674
+ if (typeof rawMetaError === "string" && rawMetaError.trim()) {
9675
+ reason = rawMetaError.trim();
9676
+ } else if (rawMessage) {
9677
+ reason = rawMessage;
9678
+ } else if (/^\[工具\s*"[^"]+"\s*执行失败:\s*[^\]]+\]$/.test(rawContent)) {
9679
+ reason = rawContent;
9680
+ }
9681
+ const detail = reason ? clip(redactSecrets(cleanUserText(reason)), 96) : "invalid card payload";
9682
+ return formatToolTraceLine(`\u25B8 ${label} \u2717 ${detail}`, colorEnabled, "error");
9683
+ }
9684
+ } else if (event.content && typeof event.content === "object") {
9685
+ parsedPayload = event.content;
9686
+ } else {
9687
+ const metadata = event.metadata ?? {};
9688
+ const rawMetaError = metadata.error ?? metadata.errorMessage;
9689
+ const reason = typeof rawMetaError === "string" && rawMetaError.trim() || event.message?.trim() || "";
9690
+ const detail = reason ? clip(redactSecrets(cleanUserText(reason)), 96) : "invalid card payload";
9691
+ return formatToolTraceLine(`\u25B8 ${label} \u2717 ${detail}`, colorEnabled, "error");
9692
+ }
9693
+ if (parsedPayload && typeof parsedPayload === "object" && parsedPayload.error) {
9694
+ const detail = typeof parsedPayload.detail === "string" && parsedPayload.detail.trim() ? clip(redactSecrets(cleanUserText(parsedPayload.detail)), 96) : "card error";
9695
+ return formatToolTraceLine(`\u25B8 ${label} \u2717 ${detail}`, colorEnabled, "error");
9696
+ }
9697
+ const rawCard = parsedPayload && typeof parsedPayload === "object" && (parsedPayload.type === "show_interaction" || parsedPayload.card !== void 0) ? parsedPayload.card : parsedPayload;
9698
+ const parsedCard = parseUiCard(rawCard);
9699
+ if (!parsedCard.ok) {
9700
+ const errorText = clip(redactSecrets(cleanUserText(parsedCard.error)), 96);
9701
+ return formatToolTraceLine(`\u25B8 ${label} \u2717 ${errorText}`, colorEnabled, "error");
9702
+ }
9703
+ const fallback = uiCardFallback(parsedCard.value);
9704
+ const maxLines = 12;
9705
+ const maxDisplayWidth = 400;
9706
+ const rawLines = fallback.split("\n");
9707
+ const clippedLines = [];
9708
+ let currentWidth = 0;
9709
+ let wasClipped = false;
9710
+ for (let i = 0; i < rawLines.length; i++) {
9711
+ if (clippedLines.length >= maxLines) {
9712
+ wasClipped = true;
9713
+ break;
9714
+ }
9715
+ const cleanLine = redactSecrets(cleanUserText(rawLines[i]));
9716
+ const lineWidth = displayWidth(cleanLine);
9717
+ const separatorWidth = clippedLines.length > 0 ? 1 : 0;
9718
+ if (currentWidth + lineWidth + separatorWidth > maxDisplayWidth) {
9719
+ const remainingWidth = maxDisplayWidth - currentWidth - separatorWidth;
9720
+ if (remainingWidth > 0) {
9721
+ clippedLines.push(truncateByDisplayWidth(cleanLine, remainingWidth));
9722
+ }
9723
+ wasClipped = true;
9724
+ break;
9725
+ }
9726
+ clippedLines.push(cleanLine);
9727
+ currentWidth += lineWidth + separatorWidth;
9728
+ }
9729
+ if (clippedLines.length === 0 && rawLines.length > 0 && maxDisplayWidth > 0) {
9730
+ const cleanLine = redactSecrets(cleanUserText(rawLines[0]));
9731
+ clippedLines.push(truncateByDisplayWidth(cleanLine, maxDisplayWidth));
9732
+ wasClipped = true;
9733
+ }
9734
+ if (wasClipped) {
9735
+ clippedLines.push("\u2026");
9736
+ }
9737
+ const cleanLines = clippedLines.map((l) => colorEnabled ? themeText(l, "muted", true) : l);
9738
+ return `
9739
+ ${cleanLines.join("\n")}
9740
+
9254
9741
  `;
9255
9742
  }
9256
9743
  function formatToolTraceLine(text, colorEnabled, accent = "none") {
@@ -9273,6 +9760,7 @@ function renderRunCard(snapshot, opts) {
9273
9760
  ...snapshot,
9274
9761
  agentName: snapshot.agentName ? cleanUserText(snapshot.agentName) : snapshot.agentName,
9275
9762
  taskPreview: snapshot.taskPreview ? cleanUserText(snapshot.taskPreview) : snapshot.taskPreview,
9763
+ title: snapshot.title ? cleanUserText(snapshot.title) : snapshot.title,
9276
9764
  lastAssistantText: snapshot.lastAssistantText ? cleanUserText(snapshot.lastAssistantText) : snapshot.lastAssistantText,
9277
9765
  lastToolNames: snapshot.lastToolNames?.map(cleanUserText)
9278
9766
  } : snapshot;
@@ -9283,6 +9771,7 @@ function renderRunCard(snapshot, opts) {
9283
9771
  } : { errorMessage: source.errorMessage, logLines: source.logLines };
9284
9772
  const body = isAgentRunTerminalStatus(snapshot.status) ? formatFinishedRunCard(name, snapshot.status, {
9285
9773
  runId: snapshot.runId,
9774
+ ...snapshot.title ? { title: snapshot.title } : {},
9286
9775
  toolCallCount: source.toolCallCount,
9287
9776
  lastToolNames: source.lastToolNames,
9288
9777
  lastAssistantText: source.lastAssistantText,
@@ -9292,6 +9781,7 @@ function renderRunCard(snapshot, opts) {
9292
9781
  labels
9293
9782
  }) : formatStatusRunCard(name, snapshot.status, {
9294
9783
  runId: snapshot.runId,
9784
+ ...snapshot.title ? { title: snapshot.title } : {},
9295
9785
  toolCallCount: source.toolCallCount,
9296
9786
  lastToolNames: source.lastToolNames,
9297
9787
  lastAssistantText: source.lastAssistantText,
@@ -9312,7 +9802,10 @@ function recoverOrchestrationCard(event, toolName, opts) {
9312
9802
  try {
9313
9803
  const parsed = JSON.parse(trimmed);
9314
9804
  const agents = Array.isArray(parsed.agents) ? parsed.agents : [];
9315
- return formatAgentListCard(agents);
9805
+ const card = formatAgentListCard(agents);
9806
+ const lines = card.split("\n");
9807
+ lines[0] = t("agentsListLabel", String(agents.length));
9808
+ return lines.join("\n");
9316
9809
  } catch {
9317
9810
  return null;
9318
9811
  }
@@ -9336,9 +9829,11 @@ function recoverOrchestrationCard(event, toolName, opts) {
9336
9829
  if (kind === "start") {
9337
9830
  const name = safe ? cleanUserText(snapshot.agentName ?? "agent") : snapshot.agentName ?? "agent";
9338
9831
  const task = snapshot.taskPreview ? safe ? cleanUserText(snapshot.taskPreview) : snapshot.taskPreview : snapshot.taskPreview;
9832
+ const title = snapshot.title ? safe ? cleanUserText(snapshot.title) : snapshot.title : snapshot.title;
9339
9833
  return formatStartRunCard(name, snapshot.status, {
9340
9834
  task,
9341
9835
  runId: snapshot.runId,
9836
+ ...title ? { title } : {},
9342
9837
  labels
9343
9838
  });
9344
9839
  }
@@ -9436,8 +9931,8 @@ function commandFullGist(command, max) {
9436
9931
  if (!oneLine) return "";
9437
9932
  return truncateByDisplayWidth(redactSecrets(oneLine), max);
9438
9933
  }
9439
- function pathBasenameGist(path) {
9440
- const segments = path.split(/[\\/]/).filter((segment) => segment.length > 0);
9934
+ function pathBasenameGist(path2) {
9935
+ const segments = path2.split(/[\\/]/).filter((segment) => segment.length > 0);
9441
9936
  const base = segments.pop();
9442
9937
  return base ? gistClip(base) : "";
9443
9938
  }
@@ -9593,8 +10088,8 @@ function normalToolGistRaw(event) {
9593
10088
  const metadata = event.metadata ?? {};
9594
10089
  const toolName = event.toolName || "";
9595
10090
  if (toolName === "readFile") {
9596
- const path2 = typeof metadata.path === "string" ? metadata.path : typeof metadata.filePath === "string" ? metadata.filePath : "";
9597
- if (path2) return gistClip(formatReadItemPath(path2, metadata), 52);
10091
+ const path3 = typeof metadata.path === "string" ? metadata.path : typeof metadata.filePath === "string" ? metadata.filePath : "";
10092
+ if (path3) return gistClip(formatReadItemPath(path3, metadata), 52);
9598
10093
  }
9599
10094
  if (toolName === "fetchWebpage") {
9600
10095
  const url = typeof metadata.url === "string" ? metadata.url : "";
@@ -9602,8 +10097,8 @@ function normalToolGistRaw(event) {
9602
10097
  }
9603
10098
  if (toolName === "exa_search") {
9604
10099
  const query2 = typeof metadata.query === "string" ? metadata.query : typeof metadata.pattern === "string" ? metadata.pattern : "";
9605
- const path2 = typeof metadata.path === "string" ? metadata.path : void 0;
9606
- if (query2 || path2) return formatSearchItemQuery(query2, path2);
10100
+ const path3 = typeof metadata.path === "string" ? metadata.path : void 0;
10101
+ if (query2 || path3) return formatSearchItemQuery(query2, path3);
9607
10102
  }
9608
10103
  if (isRunToolName(toolName)) {
9609
10104
  const command2 = typeof metadata.command === "string" ? metadata.command : "";
@@ -9613,26 +10108,14 @@ function normalToolGistRaw(event) {
9613
10108
  }
9614
10109
  const memoryGist = memoryToolGist(toolName, metadata);
9615
10110
  if (memoryGist) return memoryGist;
9616
- const path = typeof metadata.path === "string" ? metadata.path : "";
9617
- if (path) return pathBasenameGist(path);
10111
+ const path2 = typeof metadata.path === "string" ? metadata.path : "";
10112
+ if (path2) return pathBasenameGist(path2);
9618
10113
  const command = typeof metadata.command === "string" ? metadata.command : "";
9619
10114
  if (command) return commandFullGist(command, normalRunGistMaxWidth());
9620
10115
  const query = typeof metadata.query === "string" ? metadata.query : "";
9621
10116
  if (query) return clipCompactText(query, 64, "\u2026");
9622
10117
  return "";
9623
10118
  }
9624
- var NORMAL_GIST_SECRET_PATTERNS = [
9625
- /\bbearer\s+[A-Za-z0-9._~+/=-]{8,}/i,
9626
- /\bsk-(?:ant-)?(?:api)?[0-9a-zA-Z-]{10,}/,
9627
- /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{10,}/,
9628
- /\bxox[baprs]-[A-Za-z0-9-]{10,}/
9629
- ];
9630
- function withholdIfSecretLike(gist) {
9631
- if (!gist) return "";
9632
- if (findPotentialSecrets(gist).length > 0) return "";
9633
- if (NORMAL_GIST_SECRET_PATTERNS.some((pattern) => pattern.test(gist))) return "";
9634
- return gist;
9635
- }
9636
10119
  function normalToolGist(event) {
9637
10120
  return withholdIfSecretLike(normalToolGistRaw(event));
9638
10121
  }
@@ -9644,8 +10127,6 @@ function formatNormalToolDuration(elapsedMs) {
9644
10127
  function formatNormalToolLine(event, pending, colorEnabled) {
9645
10128
  if (event.type === "tool-call") return "";
9646
10129
  const toolName = event.toolName || pending?.toolName || "tool";
9647
- const todoBlock = formatTodoListForCli(event, colorEnabled);
9648
- if (todoBlock) return todoBlock;
9649
10130
  if (event.type === "tool-result" && (event.toolName === "ask_user" || event.metadata?.uiAskChoice)) {
9650
10131
  const block = formatUiAskChoiceBlock(event, colorEnabled);
9651
10132
  if (block) return block;
@@ -9656,6 +10137,9 @@ function formatNormalToolLine(event, pending, colorEnabled) {
9656
10137
  if (event.type === "tool-result" && toolName === "loadSkill") {
9657
10138
  return formatLoadSkillBlock(event, colorEnabled, { safe: true }) ?? "";
9658
10139
  }
10140
+ if (event.type === "tool-result" && toolName === "show_interaction") {
10141
+ return formatShowInteractionBlock(event, colorEnabled);
10142
+ }
9659
10143
  const label = toolLabel(toolName);
9660
10144
  if (readActionGate(event.metadata?.actionGate)) {
9661
10145
  return formatToolTraceLine(`\u25B8 ${label} ! ${t("toolNeedsAction")}`, colorEnabled, "error");
@@ -9708,39 +10192,6 @@ function resolveLoadSkillName(event) {
9708
10192
  if (match?.[1]) return match[1];
9709
10193
  return argName || "skill";
9710
10194
  }
9711
- function formatTodoListForCli(event, colorEnabled) {
9712
- if (event.type !== "tool-result" || event.toolName !== "setTodoList") {
9713
- return void 0;
9714
- }
9715
- let raw = event.metadata?.displayData;
9716
- let parsed = typeof raw === "object" && raw !== null;
9717
- if (typeof raw === "string") {
9718
- try {
9719
- raw = JSON.parse(raw);
9720
- parsed = true;
9721
- } catch {
9722
- raw = void 0;
9723
- }
9724
- }
9725
- if (!parsed && typeof event.content === "string") {
9726
- try {
9727
- raw = JSON.parse(event.content);
9728
- parsed = true;
9729
- } catch {
9730
- raw = void 0;
9731
- }
9732
- }
9733
- const todos = Array.isArray(raw?.todos) ? raw.todos : void 0;
9734
- if (!todos) return void 0;
9735
- if (todos.length === 0) return "\u2611 Todo\n (empty)\n";
9736
- const lines = todos.map((todo) => {
9737
- const status = todo?.status === "done" ? "\u2713" : todo?.status === "in_progress" ? "\u25D0" : "\u25CB";
9738
- const title = typeof todo?.title === "string" ? todo.title : "Untitled task";
9739
- return ` ${status} ${title}`;
9740
- });
9741
- const text = [`\u2611 Todo (${todos.length})`, ...lines].join("\n") + "\n";
9742
- return colorEnabled ? themeText(text, "chrome") : text;
9743
- }
9744
10195
  function formatLoadSkillBlock(event, colorEnabled, opts) {
9745
10196
  if (event.type !== "tool-result" || event.toolName !== "loadSkill") return null;
9746
10197
  const skillName = resolveLoadSkillName(event);
@@ -10385,6 +10836,12 @@ var describeClientVersionTooOldFailure = (message, rawError) => {
10385
10836
  };
10386
10837
 
10387
10838
  // packages/cli/client/agentRunStream.ts
10839
+ function isMalformedFunctionCallFailure(message) {
10840
+ return message.includes("MALFORMED_FUNCTION_CALL");
10841
+ }
10842
+ function shouldAppendStreamRawErrorDetail(env) {
10843
+ return env?.NOLO_DEBUG === "1" || env?.NOLO_CLI_DEBUG_DETAIL === "1";
10844
+ }
10388
10845
  async function readStreamingAgentRun(options, res, existingSpinner) {
10389
10846
  const reader = res.body?.getReader();
10390
10847
  if (!reader) {
@@ -10493,15 +10950,18 @@ async function readStreamingAgentRun(options, res, existingSpinner) {
10493
10950
  };
10494
10951
  }
10495
10952
  const message = toErrorMessage(error);
10953
+ const malformedToolCall = isMalformedFunctionCallFailure(message);
10954
+ const rawDetail = shouldAppendStreamRawErrorDetail(options.env) ? t("agentRunStream.rawErrorDetail", message) : null;
10496
10955
  if (dialogId) {
10497
- options.output.write(
10498
- `
10499
- [nolo] Agent stream transport interrupted after dialog ${dialogId} was created: ${message}
10500
- `
10501
- );
10502
- options.output.write(
10503
- "[nolo] The agent run may still finish on the server; read the dialog before retrying.\n"
10504
- );
10956
+ if (malformedToolCall) {
10957
+ options.output.write(`
10958
+ ${t("agentRunStream.malformedToolCallRejected", dialogId)}
10959
+ `);
10960
+ if (rawDetail) options.output.write(rawDetail);
10961
+ return { exitCode: 0, dialogId, streamInterrupted: true };
10962
+ }
10963
+ options.output.write(t("agentRunStream.interruptedAfterDialog", dialogId, message));
10964
+ options.output.write(t("agentRunStream.mayStillFinishOnServer"));
10505
10965
  return { exitCode: 0, dialogId, streamInterrupted: true };
10506
10966
  }
10507
10967
  if (isClientVersionTooOldFailure(message, error)) {
@@ -10509,9 +10969,14 @@ async function readStreamingAgentRun(options, res, existingSpinner) {
10509
10969
  ${describeClientVersionTooOldFailure(message, error)}`);
10510
10970
  return { exitCode: 1 };
10511
10971
  }
10512
- options.output.write(`
10513
- [nolo] Agent stream failed: ${message}
10972
+ if (malformedToolCall) {
10973
+ options.output.write(`
10974
+ ${t("agentRunStream.malformedToolCallRejectedNoDialog")}
10514
10975
  `);
10976
+ if (rawDetail) options.output.write(rawDetail);
10977
+ return { exitCode: 1 };
10978
+ }
10979
+ options.output.write(t("agentRunStream.failed", message));
10515
10980
  return { exitCode: 1 };
10516
10981
  }
10517
10982
  if (options.abortSignal?.aborted && !sawDone) {
@@ -10532,6 +10997,9 @@ ${describeClientVersionTooOldFailure(message, error)}`);
10532
10997
  return {
10533
10998
  exitCode: 0,
10534
10999
  ...dialogId ? { dialogId } : {},
11000
+ // 结论载体与 local / 非流式 HTTP 路径同契约:流式分支已经把 assistant
11001
+ // 正文累加在 content 里,不随行则 server 流式 run 的结算也拿不到结论。
11002
+ ...content ? { finalText: content } : {},
10535
11003
  turnTokens: buildTurnTokenUsage(usage, options.agentKey),
10536
11004
  ...turnCredits !== void 0 ? { turnCredits } : {}
10537
11005
  };
@@ -10738,8 +11206,46 @@ function findCollapsedPasteSpanAt(buffer, pos, opts = {}) {
10738
11206
 
10739
11207
  // packages/cli/client/agentRun.ts
10740
11208
  import { ulid as ulid2 } from "ulid";
11209
+
11210
+ // packages/cli/client/balanceErrorPatterns.ts
11211
+ var ZERO_WIDTH_RE = /[\u200b-\u200d\u2060\ufeff]/g;
11212
+ function stripZeroWidthChars(text) {
11213
+ return text.replace(ZERO_WIDTH_RE, "");
11214
+ }
11215
+ var CONTROL_CHAR_RE = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g;
11216
+ function stripControlChars(text) {
11217
+ return text.replace(CONTROL_CHAR_RE, "");
11218
+ }
11219
+ var BALANCE_ERROR_PATTERNS = [
11220
+ /UPSTREAM_402/i,
11221
+ // 裸 HTTP 402 本身就是「Payment Required」:报文里没有任何余额关键词(如只有
11222
+ // `{"error":{}}` 空壳)时也必须走余额块,而不是落进通用 4xx 长文案。
11223
+ // `\b` 保证 `HTTP 4020` 不误命中。
11224
+ /\bHTTP\s*402\b/i,
11225
+ // `insufficient balance` / `insufficient_balance` / `insufficient-balance` /
11226
+ // `Insufficient Balance`(分隔符重复也要认:alpha 里的旧 `/insufficient\s+balance/`
11227
+ // 能覆盖双空格,收窄成 `?` 会回退)。
11228
+ /insufficient[_\s-]+balance/i,
11229
+ /余额不足/,
11230
+ /wallet\s+balance\s+is\s+insufficient/i,
11231
+ /top\s+up\s+your\s+wallet/i,
11232
+ /payment[_ ]required/i
11233
+ ];
11234
+ var CODING_PLAN_EXHAUSTED_RE = /coding[_\s-]?plan[_\s-]?exhausted/i;
11235
+ function matchesBalanceError(message) {
11236
+ if (!message) return false;
11237
+ const normalized = stripZeroWidthChars(message);
11238
+ return BALANCE_ERROR_PATTERNS.some((pattern) => pattern.test(normalized));
11239
+ }
11240
+ function isBalanceExhaustedError(error) {
11241
+ if (!error) return false;
11242
+ const message = error instanceof Error ? error.message : typeof error === "string" ? error : String(error?.message ?? "");
11243
+ return matchesBalanceError(message);
11244
+ }
11245
+
11246
+ // packages/cli/client/agentRun.ts
10741
11247
  async function loadRunLocalAgentTurn() {
10742
- const { runLocalAgentTurn } = await import("./agentRuntimeLocal-AK2QVJHY.js");
11248
+ const { runLocalAgentTurn } = await import("./agentRuntimeLocal-KKSQJMTE.js");
10743
11249
  return runLocalAgentTurn;
10744
11250
  }
10745
11251
  var stripDebugNoise = (s) => s.replace(/\s*raw="[\s\S]*"/g, "").replace(/\s*raw=\S+/g, "").replace(/\s*headers=\[[^\]]*\]/g, "").replace(/\s*headers=\S+/g, "").trim();
@@ -10763,25 +11269,7 @@ function parseEmbeddedBalanceDetails(message) {
10763
11269
  const jsonStart = message.indexOf('{"error"');
10764
11270
  if (jsonStart < 0) return void 0;
10765
11271
  try {
10766
- let depth = 0;
10767
- let inString = false;
10768
- let escaped = false;
10769
- let jsonEnd = -1;
10770
- for (let i = jsonStart; i < message.length; i += 1) {
10771
- const char = message[i];
10772
- if (inString) {
10773
- if (escaped) escaped = false;
10774
- else if (char === "\\") escaped = true;
10775
- else if (char === '"') inString = false;
10776
- } else if (char === '"') {
10777
- inString = true;
10778
- } else if (char === "{") {
10779
- depth += 1;
10780
- } else if (char === "}" && --depth === 0) {
10781
- jsonEnd = i + 1;
10782
- break;
10783
- }
10784
- }
11272
+ const jsonEnd = findJsonObjectEnd(message, jsonStart);
10785
11273
  if (jsonEnd < 0) return void 0;
10786
11274
  const parsed = JSON.parse(message.slice(jsonStart, jsonEnd));
10787
11275
  if (!parsed || typeof parsed !== "object") return void 0;
@@ -10825,6 +11313,7 @@ function resolveRequestedRuntimeMode(options) {
10825
11313
  return envMode;
10826
11314
  return "auto";
10827
11315
  }
11316
+ var MACHINE_SHELL_LOCAL_REFUSAL_MESSAGE = "[nolo] --machine-shell can only run on the machine bound in the agent record (runtimeBinding.machineId): a local run cannot honor it, and it never executes on this computer.\n[nolo] Retry without --local / NOLO_RUNTIME_MODE=local, or drop --machine-shell to run on this computer.\n";
10828
11317
  function canResolveCollapsedPasteReference(store, content) {
10829
11318
  const expand = (text) => expandCollapsedPastes(text, store) !== text;
10830
11319
  if (typeof content === "string") return expand(content);
@@ -10837,15 +11326,31 @@ function buildDefaultLocalRuntimeAdapter(options) {
10837
11326
  fetchImpl: options.fetchImpl,
10838
11327
  cwd: options.localRuntimeCwd,
10839
11328
  output: options.output,
11329
+ // TUI 显式注入的真实会话身份;缺省时 adapter 内仍回退 parentDialogId。
11330
+ ...options.originSession ? { originSession: options.originSession } : {},
11331
+ // 分享 OAuth agent 的 shell 会话授权(块 D):仅 owner-required 场景生效。
11332
+ ...options.shellGrant ? { shellGrant: options.shellGrant } : {},
11333
+ ...options.shellApprovalSession ? { shellApprovalSession: options.shellApprovalSession } : {},
11334
+ ...options.execShellApproval ? { execShellApproval: options.execShellApproval } : {},
11335
+ // 运行位置展示(块 D):TUI 消费 projectToolExecutionLocation 渲染工具实际
11336
+ // 执行设备/工作区;非 owner-required 场景 adapter 不回调。
11337
+ ...options.onToolExecutionLocation ? { onToolExecutionLocation: options.onToolExecutionLocation } : {},
10840
11338
  ...options.confirmDestructiveAction ? { confirmDestructiveAction: options.confirmDestructiveAction } : {},
10841
11339
  ...options.requestUserChoice ? { requestUserChoice: options.requestUserChoice } : {},
10842
11340
  ...options.pastedTextStore?.items.size ? { pastedTextStore: options.pastedTextStore } : {},
10843
- ...options.activityReporter ? { activityReporter: options.activityReporter } : {}
11341
+ ...options.activityReporter ? { activityReporter: options.activityReporter } : {},
11342
+ // runtimeKey 接线:不传下去则本地 run 的 runtimeKey 在 agentRun 层就断了
11343
+ // ——adapter 收不到 → docker workload 永不创建,非 docker 云后端也不会
11344
+ // fail-closed(死代码)。
11345
+ ...options.runtimeKey ? { runtimeKey: options.runtimeKey } : {}
10844
11346
  });
10845
11347
  }
10846
11348
  function resolveLocalRuntimeAdapter(options) {
10847
11349
  return options.localRuntimeAdapter || options.localRuntimeAdapterFactory?.(options.env, {
10848
- cwd: options.localRuntimeCwd
11350
+ cwd: options.localRuntimeCwd,
11351
+ // 与 buildDefaultLocalRuntimeAdapter 同口径:注入式 factory 也必须拿到
11352
+ // runtimeKey,否则注入了 adapter 的本地 run 会静默丢掉 docker 语义。
11353
+ ...options.runtimeKey ? { runtimeKey: options.runtimeKey } : {}
10849
11354
  }) || buildDefaultLocalRuntimeAdapter(options);
10850
11355
  }
10851
11356
  function wrapAdapterEphemeral(adapter) {
@@ -10874,7 +11379,7 @@ function wrapLoadAgentConfigWithModelOverride(adapter, targetAgentKey, override)
10874
11379
  }
10875
11380
  };
10876
11381
  }
10877
- var oauthChannelSkipReportedOutputs = /* @__PURE__ */ new WeakSet();
11382
+ var oauthChannelSkipReportedAgentKeys = /* @__PURE__ */ new Set();
10878
11383
  function resolveOAuthChannelOwnerSkip(agentConfig, options) {
10879
11384
  if (!agentConfig) return null;
10880
11385
  const apiKeyRef = typeof agentConfig.apiKeyRef === "string" ? agentConfig.apiKeyRef : void 0;
@@ -10886,8 +11391,8 @@ function resolveOAuthChannelOwnerSkip(agentConfig, options) {
10886
11391
  if (!ownerUserId) return null;
10887
11392
  const localUserId = resolveLocalUserId(options.env);
10888
11393
  if (ownerUserId === localUserId) return null;
10889
- return `[nolo] auto runtime: skipping local runtime because ${options.agentKey} runs on its owner's OAuth subscription channel (owner ${ownerUserId}, this machine runs as ${localUserId}). Use --local explicitly to force this machine's own subscription.
10890
- `;
11394
+ const agentName = asOptionalTrimmedString(agentConfig.name) ?? asOptionalTrimmedString(options.agentName) ?? t("agentRun.sharedAgentFallbackName");
11395
+ return t("agentRun.oauthChannelOwnerSkip", agentName) + "\n";
10891
11396
  }
10892
11397
  async function shouldSkipAutoLocalForServerPlatformTools(options) {
10893
11398
  if (isBuiltinNoloAgentRef(options.agentKey)) return false;
@@ -10903,13 +11408,13 @@ async function shouldSkipAutoLocalForServerPlatformTools(options) {
10903
11408
  }
10904
11409
  const oauthChannelOwnerSkip = resolveOAuthChannelOwnerSkip(agentConfig, options);
10905
11410
  if (oauthChannelOwnerSkip) {
10906
- if (!options.output || typeof options.output !== "object" || !oauthChannelSkipReportedOutputs.has(options.output)) {
11411
+ if (!options.output || typeof options.output !== "object" || !oauthChannelSkipReportedAgentKeys.has(options.agentKey)) {
10907
11412
  if (options.output && typeof options.output === "object") {
10908
- oauthChannelSkipReportedOutputs.add(options.output);
11413
+ oauthChannelSkipReportedAgentKeys.add(options.agentKey);
10909
11414
  }
10910
11415
  options.output.write(oauthChannelOwnerSkip);
10911
11416
  }
10912
- return true;
11417
+ return false;
10913
11418
  }
10914
11419
  if (options.localRuntimeCwd) {
10915
11420
  return false;
@@ -10948,14 +11453,15 @@ async function shouldSkipAutoLocalForServerPlatformTools(options) {
10948
11453
  );
10949
11454
  return true;
10950
11455
  }
10951
- function buildUserInputContent(message, imageUrls = []) {
10952
- if (imageUrls.length === 0) return message;
11456
+ function buildUserInputContent(message, imageUrls = [], attachmentParts = []) {
11457
+ if (imageUrls.length === 0 && attachmentParts.length === 0) return message;
10953
11458
  return [
10954
11459
  ...message.trim() ? [{ type: "text", text: message }] : [],
10955
11460
  ...imageUrls.map((url) => ({
10956
11461
  type: "image_url",
10957
11462
  image_url: { url }
10958
- }))
11463
+ })),
11464
+ ...attachmentParts
10959
11465
  ];
10960
11466
  }
10961
11467
  function buildSubjectRefs(options) {
@@ -11000,8 +11506,8 @@ function isMissingLocalAgentConfigError(error, agentRef) {
11000
11506
  error && typeof error === "object" && "code" in error && error.code === LOCAL_AGENT_CONFIG_MISSING_CODE && error.agentRef === agentRef
11001
11507
  );
11002
11508
  }
11003
- var PROVIDER_HTTP_FAILED_RE = /(.+?) provider failed:\s*HTTP\s+(\d+)\b/i;
11004
- var PLATFORM_TRANSPORT_RE = /\bplatform provider failed\b/i;
11509
+ var PROVIDER_HTTP_FAILED_RE = /(.+?)(?:\s+provider|\s+proxy) failed:\s*HTTP\s+(\d+)\b/i;
11510
+ var PLATFORM_TRANSPORT_RE = /\b(?:platform provider failed|owner-required proxy failed)\b/i;
11005
11511
  var EXTRA_RATE_LIMIT_TEXT_RE = /\brate[\s_-]?limit(?:ed|ing|s)?\b|\bresource[_\s-]?exhausted\b|\bmax_concurrent_reached\b/i;
11006
11512
  function looksLikeRateLimitedText(message) {
11007
11513
  return EXTRA_RATE_LIMIT_TEXT_RE.test(message) || QUOTA_ERROR_PATTERNS.some((pattern) => pattern.test(message));
@@ -11048,7 +11554,6 @@ function classifyLocalRunError(message) {
11048
11554
  kind: "rate-limit",
11049
11555
  transport,
11050
11556
  status: 429,
11051
- statusInferred: true,
11052
11557
  ...quotaExhausted ? { quotaExhausted: true } : {}
11053
11558
  };
11054
11559
  }
@@ -11059,7 +11564,8 @@ function classifyLocalRunError(message) {
11059
11564
  }
11060
11565
  return { kind: "generic" };
11061
11566
  }
11062
- var HISTORY_REPLAY_REJECTION_RE = /invalid_request_error|invalid\s+tool\s+call\s+arguments?/i;
11567
+ var HISTORY_REPLAY_REJECTION_RE = /invalid\s+tool\s+call\s+arguments?/i;
11568
+ var REASONING_REPLAY_CONTRACT_RE = /reasoning_content[^.]*must be passed back/i;
11063
11569
  var RUN_UNAVAILABLE_PREFIX = "[nolo] auto runtime: local run unavailable";
11064
11570
  var NO_FALLBACK = "Not falling back to server.";
11065
11571
  var SERVER_FALLBACK_HINT = "or use --server to run on the server explicitly.";
@@ -11094,39 +11600,268 @@ function buildAuthFailure(ctx) {
11094
11600
  Detail: ${ctx.message} ${NO_FALLBACK} Use --server to run on the server explicitly.
11095
11601
  `;
11096
11602
  }
11097
- return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}, auth rejected). Detail: ${ctx.message} ${NO_FALLBACK} ${fix}, ${SERVER_FALLBACK_HINT}.
11603
+ if (ctx.status === 403 && ctx.message.includes("owner-required proxy failed") && /"code"\s*:\s*"owner_origin_mismatch"/i.test(ctx.message)) {
11604
+ return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}, this run's origin device could not be verified \u2014 no live connector connection for this machine on this server/account; owner_origin_mismatch).
11605
+ \xB7 Start the connector on this machine: \`nolo connect --daemon\` (\`nolo machine status\` shows whether it is online and connected to the same server)
11606
+ \xB7 Force a fully local run with --local (needs a local credential for this agent), or run on the server: --server
11607
+ Detail: ${ctx.message} ${NO_FALLBACK} ${SERVER_FALLBACK_HINT}
11608
+ `;
11609
+ }
11610
+ return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}, auth rejected). Detail: ${ctx.message} ${NO_FALLBACK} ${fix}, ${SERVER_FALLBACK_HINT}
11098
11611
  `;
11099
11612
  }
11100
11613
  function isAuthNoTokenBody(message) {
11101
11614
  return /"authCode"\s*:\s*"AUTH_NO_TOKEN"/i.test(message) || /no authentication token provided/i.test(message);
11102
11615
  }
11103
11616
  function buildRejectedPayloadFailure(ctx) {
11104
- const looksLikeHistoryReplay = HISTORY_REPLAY_REJECTION_RE.test(ctx.message);
11105
- const cause = looksLikeHistoryReplay ? ` This usually happens when the dialog history contains tool_calls or reasoning produced by a different model/provider (e.g. after /switch); the new provider rejects that history. Start a fresh dialog, or clean the offending history.` : "";
11617
+ const looksLikeReasoningReplay = REASONING_REPLAY_CONTRACT_RE.test(ctx.message);
11618
+ const looksLikeHistoryReplay = !looksLikeReasoningReplay && HISTORY_REPLAY_REJECTION_RE.test(ctx.message);
11619
+ const cause = looksLikeReasoningReplay ? ` This is a thinking-mode replay contract violation: the history contains an assistant tool-call turn without reasoning_content, but this model requires every such turn to pass reasoning back to the API. The upstream may not have returned reasoning for that turn, or the history came from a different model.` : looksLikeHistoryReplay ? ` This usually happens when the dialog history contains tool_calls or reasoning produced by a different model/provider (e.g. after /switch); the new provider rejects that history. Start a fresh dialog, or clean the offending history.` : "";
11106
11620
  return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}, the provider rejected the request body \u2014 this is NOT a local credential/config issue). Detail: ${ctx.message}${cause} ${NO_FALLBACK} Use --server to run on the server explicitly, or start a fresh dialog.
11107
11621
  `;
11108
11622
  }
11109
- var RATE_LIMIT_RESET_HINT_RE = /retry[-_\s]?after\s*[:=]?\s*\d[\w:-]*|resets?\s+(?:in|at)\s+\d[\w:-]*(?:[ T]\d[\w:-]*)?/i;
11623
+ var RESET_HINT_UNIT = String.raw`(?:d(?:ays?)?|h(?:ours?|rs?)?|m(?:in(?:ute)?s?)?|s(?:ec(?:ond)?s?)?)`;
11624
+ var RESET_HINT_DURATION = String.raw`\d+(?:\.\d+)?(?:\s*${RESET_HINT_UNIT})?(?:\s*\d+(?:\.\d+)?\s*${RESET_HINT_UNIT})*`;
11625
+ var RATE_LIMIT_RESET_HINT_RE = new RegExp(
11626
+ String.raw`retry[-_\s]?after\s*[:=]?\s*\d[\w:.-]*` + String.raw`|resets?\s+at\s+\d[\w:.-]*` + String.raw`|resets?\s+in\s+${RESET_HINT_DURATION}`,
11627
+ "i"
11628
+ );
11629
+ function findRateLimitResetHint(message) {
11630
+ const match = RATE_LIMIT_RESET_HINT_RE.exec(message);
11631
+ if (!match) return void 0;
11632
+ const end = match.index + match[0].length;
11633
+ if (/^[a-z:-]/i.test(message[end] ?? "")) return void 0;
11634
+ return { raw: match[0], text: match[0].trim(), index: match.index };
11635
+ }
11110
11636
  function extractRateLimitResetHint(message) {
11111
- const match = message.match(RATE_LIMIT_RESET_HINT_RE);
11112
- return match ? match[0].trim() : void 0;
11637
+ return findRateLimitResetHint(message)?.text;
11638
+ }
11639
+ function isStandaloneResetSentence(text, index) {
11640
+ const before = text.slice(0, index).replace(/\s+$/, "");
11641
+ return before === "" || /[.。!!??;;]$/.test(before);
11642
+ }
11643
+ var RATE_LIMIT_DETAIL_MAX_CHARS = 140;
11644
+ var UPSTREAM_TAG_MAX_CHARS = 64;
11645
+ function findJsonObjectEnd(text, from) {
11646
+ const open = text[from];
11647
+ if (open !== "{" && open !== "[") return -1;
11648
+ const close = open === "{" ? "}" : "]";
11649
+ let depth = 0;
11650
+ let inString = false;
11651
+ let escaped = false;
11652
+ for (let i = from; i < text.length; i += 1) {
11653
+ const ch = text[i];
11654
+ if (inString) {
11655
+ if (escaped) escaped = false;
11656
+ else if (ch === "\\") escaped = true;
11657
+ else if (ch === '"') inString = false;
11658
+ continue;
11659
+ }
11660
+ if (ch === '"') inString = true;
11661
+ else if (ch === open) depth += 1;
11662
+ else if (ch === close) {
11663
+ depth -= 1;
11664
+ if (depth === 0) return i + 1;
11665
+ }
11666
+ }
11667
+ return -1;
11668
+ }
11669
+ function stripRateLimitDetailsArray(message) {
11670
+ const KEY = "details=";
11671
+ let out = message;
11672
+ let searchFrom = 0;
11673
+ for (; ; ) {
11674
+ const keyIndex = out.indexOf(KEY, searchFrom);
11675
+ if (keyIndex === -1) return out;
11676
+ let openIndex = keyIndex + KEY.length;
11677
+ while (openIndex < out.length && /\s/.test(out[openIndex])) openIndex += 1;
11678
+ if (out[openIndex] !== "[") {
11679
+ searchFrom = keyIndex + KEY.length;
11680
+ continue;
11681
+ }
11682
+ const endIndex = findJsonObjectEnd(out, openIndex);
11683
+ if (endIndex === -1) return out;
11684
+ out = `${out.slice(0, keyIndex)} ${out.slice(endIndex)}`;
11685
+ searchFrom = keyIndex;
11686
+ }
11687
+ }
11688
+ function stripRateLimitTransportPrefix(message) {
11689
+ let out = message.trim();
11690
+ const localPrefix = /^local(?:\s+\S+)?\s+provider failed:\s*/i.exec(out);
11691
+ if (localPrefix) {
11692
+ out = out.slice(localPrefix[0].length);
11693
+ } else {
11694
+ const proxyPrefix = /^server chat proxy[^:]*:\s*/i.exec(out);
11695
+ if (proxyPrefix) out = out.slice(proxyPrefix[0].length);
11696
+ }
11697
+ return out.replace(/^HTTP\s+\d{3}\b[\s:,-]*/i, "").trim();
11698
+ }
11699
+ function describeUpstreamTag(ctx) {
11700
+ const source = stripZeroWidthChars(ctx.message);
11701
+ const clean2 = (value) => {
11702
+ if (value === void 0) return void 0;
11703
+ const normalized = stripControlChars(value).replace(/\s+/g, " ").trim();
11704
+ if (!normalized) return void 0;
11705
+ return normalized.length > UPSTREAM_TAG_MAX_CHARS ? `${normalized.slice(0, UPSTREAM_TAG_MAX_CHARS - 1).trimEnd()}\u2026` : normalized;
11706
+ };
11707
+ const provider = clean2(/^local\s+(\S+)\s+provider failed/i.exec(source)?.[1]);
11708
+ const model = clean2(/"model"\s*:\s*"([^"]+)"/.exec(source)?.[1]);
11709
+ const parts = [provider, model].filter((part) => Boolean(part));
11710
+ return parts.length > 0 ? parts.join(" \xB7 ") : ctx.where;
11711
+ }
11712
+ function sanitizeRateLimitDetail(message, stripResetSentence) {
11713
+ const withoutNoise = stripRateLimitTransportPrefix(
11714
+ // 控制字符(ESC 清屏 / 光标移动)是 provider 可控文本,先剥再进用户文案。
11715
+ stripControlChars(stripRateLimitDetailsArray(stripDebugNoise(message)))
11716
+ );
11717
+ const collapse = (text) => text.replace(/\s+/g, " ").replace(/([.。!!??])\s+(?=[.。!!??])/g, "").replace(/([.。!!??])\1+/g, "$1").replace(/[\s,;:,;:]+$/, "").trim();
11718
+ const hint = stripResetSentence ? findRateLimitResetHint(withoutNoise) : void 0;
11719
+ const stripped = hint && isStandaloneResetSentence(withoutNoise, hint.index) ? `${withoutNoise.slice(0, hint.index)} ${withoutNoise.slice(hint.index + hint.raw.length)}` : withoutNoise;
11720
+ const detail = collapse(stripped) || collapse(withoutNoise);
11721
+ return detail.length > RATE_LIMIT_DETAIL_MAX_CHARS ? `${detail.slice(0, RATE_LIMIT_DETAIL_MAX_CHARS - 1).trimEnd()}\u2026` : detail;
11722
+ }
11723
+ function formatCooldownUntilLocal(iso, now = /* @__PURE__ */ new Date()) {
11724
+ const at = new Date(iso);
11725
+ if (Number.isNaN(at.getTime())) return iso;
11726
+ const pad = (value) => String(value).padStart(2, "0");
11727
+ const time = `${pad(at.getHours())}:${pad(at.getMinutes())}`;
11728
+ const sameDay = at.getFullYear() === now.getFullYear() && at.getMonth() === now.getMonth() && at.getDate() === now.getDate();
11729
+ return sameDay ? time : `${pad(at.getMonth() + 1)}-${pad(at.getDate())} ${time}`;
11730
+ }
11731
+ var RESET_HINT_VALUE_RE = /^(?:resets?\s+(?:in|at)\s*|retry[-_\s]?after\s*[:=]?\s*(?:in\s+)?)(.*)$/i;
11732
+ var RESET_HINT_DURATION_RE = /^(?:(\d+)\s*d(?:ays?)?)?\s*(?:(\d+)\s*h(?:ours?|rs?)?)?\s*(?:(\d+)\s*m(?:in(?:ute)?s?)?)?\s*(?:(\d+)\s*s(?:ec(?:ond)?s?)?)?$/i;
11733
+ var RESET_HINT_ABSOLUTE_RE = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}/;
11734
+ var RESET_HINT_IN_BRANCH_RE = /^resets?\s+in\b/i;
11735
+ var RESET_HINT_UNIT_IN_VALUE_RE = new RegExp(String.raw`\d\s*${RESET_HINT_UNIT}`, "i");
11736
+ function parseResetHintSeconds(value) {
11737
+ if (/^\d+$/.test(value)) return Number(value);
11738
+ const match = RESET_HINT_DURATION_RE.exec(value);
11739
+ if (!match || !match.slice(1).some(Boolean)) return void 0;
11740
+ const [days, hours, minutes, seconds] = match.slice(1).map((part) => Number(part ?? 0));
11741
+ return days * 86400 + hours * 3600 + minutes * 60 + seconds;
11742
+ }
11743
+ function formatRateLimitResetHint(hint, locale) {
11744
+ const value = (RESET_HINT_VALUE_RE.exec(hint.trim())?.[1] ?? hint).trim();
11745
+ if (!value) return void 0;
11746
+ if (RESET_HINT_IN_BRANCH_RE.test(hint.trim()) && !RESET_HINT_UNIT_IN_VALUE_RE.test(value)) {
11747
+ return void 0;
11748
+ }
11749
+ if (RESET_HINT_ABSOLUTE_RE.test(value)) return formatCooldownUntilLocal(value);
11750
+ const seconds = parseResetHintSeconds(value);
11751
+ if (seconds === void 0) return value;
11752
+ const minutes = Math.round(seconds / 60);
11753
+ const zh = locale === "zh";
11754
+ if (minutes < 1) return zh ? "<1 \u5206\u949F" : "<1m";
11755
+ const days = Math.floor(minutes / 1440);
11756
+ const hours = Math.floor(minutes % 1440 / 60);
11757
+ const rest = minutes % 60;
11758
+ const parts = [];
11759
+ if (days > 0) parts.push(zh ? `${days} \u5929` : `${days}d`);
11760
+ if (hours > 0) parts.push(zh ? `${hours} \u5C0F\u65F6` : `${hours}h`);
11761
+ if (rest > 0) parts.push(zh ? `${rest} \u5206` : `${rest}m`);
11762
+ return parts.join(" ");
11113
11763
  }
11114
11764
  function buildRateLimitFailure(ctx) {
11115
- const cooldownNote = ctx.cooldownUntil ? ` \u5DF2\u6807\u8BB0\u51B7\u5374\u81F3 ${ctx.cooldownUntil}\uFF0C\u5230\u671F\u524D\u6D3E\u53D1\u4F1A\u88AB\u51B7\u5374\u95E8\u63A7\u62E6\u622A\uFF08\u5230\u671F\u81EA\u52A8 probe \u6062\u590D\uFF09\u3002` : "";
11116
- const headline = ctx.statusInferred ? `${ctx.where} hit an upstream rate-limit/quota error` : `${ctx.where} returned HTTP ${ctx.status}, rate limited`;
11117
- const cause = ctx.quotaExhausted ? "The upstream quota/balance for this agent is exhausted \u2014 NOT a local credential/config issue" : "This agent is being throttled by the upstream provider \u2014 NOT a local credential/config issue";
11118
- const reset = extractRateLimitResetHint(ctx.message);
11119
- const advice = ctx.quotaExhausted ? `Retry after the upstream quota resets${reset ? ` (${reset})` : ""}` : `Retry shortly${reset ? ` (${reset})` : ""}`;
11120
- return `${RUN_UNAVAILABLE_PREFIX} (${headline}). Detail: ${ctx.message} ${NO_FALLBACK} ${cause}. ${advice}, switch to another agent (\`nolo agent list\`), ${SERVER_FALLBACK_HINT}${cooldownNote}
11765
+ const headlineKey = ctx.quotaExhausted ? "localRunRateLimitQuota" : "localRunRateLimitThrottled";
11766
+ const lines = [
11767
+ t(
11768
+ headlineKey,
11769
+ describeUpstreamTag(ctx),
11770
+ sanitizeRateLimitDetail(ctx.message, Boolean(ctx.cooldownUntil))
11771
+ )
11772
+ ];
11773
+ const cooldownUntil = ctx.cooldownUntil;
11774
+ if (cooldownUntil) {
11775
+ const resetValue = formatRateLimitResetHint(
11776
+ extractRateLimitResetHint(ctx.message) ?? "",
11777
+ getCliLocale()
11778
+ );
11779
+ lines.push(
11780
+ t(
11781
+ "localRunRateLimitCooldown",
11782
+ formatCooldownUntilLocal(cooldownUntil),
11783
+ resetValue ? t("localRunRateLimitResetNote", resetValue) : "",
11784
+ String(Math.round(PROBE_INTERVAL_MS / 6e4))
11785
+ )
11786
+ );
11787
+ }
11788
+ lines.push(t("localRunRateLimitExits"));
11789
+ return `${lines.join("\n")}
11790
+ `;
11791
+ }
11792
+ var BALANCE_DETAIL_MAX_CHARS = RATE_LIMIT_DETAIL_MAX_CHARS;
11793
+ function stripEmbeddedErrorJson(message) {
11794
+ const KEY = '{"error"';
11795
+ let out = message;
11796
+ let searchFrom = 0;
11797
+ for (; ; ) {
11798
+ const keyIndex = out.indexOf(KEY, searchFrom);
11799
+ if (keyIndex === -1) return out;
11800
+ const endIndex = findJsonObjectEnd(out, keyIndex);
11801
+ if (endIndex === -1) return out;
11802
+ out = `${out.slice(0, keyIndex)} ${out.slice(endIndex)}`;
11803
+ searchFrom = keyIndex;
11804
+ }
11805
+ }
11806
+ function sanitizeBalanceDetail(message) {
11807
+ const withoutNoise = stripEmbeddedErrorJson(stripDebugNoise(message));
11808
+ const detail = stripControlChars(
11809
+ stripZeroWidthChars(stripRateLimitTransportPrefix(withoutNoise))
11810
+ ).replace(/(\d{3})\[/g, "$1 [").replace(/\s+/g, " ").replace(/([.。!!??])\s+(?=[.。!!??])/g, "").replace(/([.。!!??])\1+/g, "$1").replace(/[\s,;:,;:]+$/, "").trim();
11811
+ return detail.length > BALANCE_DETAIL_MAX_CHARS ? `${detail.slice(0, BALANCE_DETAIL_MAX_CHARS - 1).trimEnd()}\u2026` : detail;
11812
+ }
11813
+ function extractBalanceErrorMarker(message) {
11814
+ const bodyStart = message.indexOf('{"error"');
11815
+ const body = bodyStart === -1 ? message : message.slice(bodyStart);
11816
+ const match = /"(?:code|type|status)"\s*:\s*"([^"\\]{1,60})"/.exec(body);
11817
+ const marker = match?.[1].trim();
11818
+ return marker ? marker : void 0;
11819
+ }
11820
+ function extractBalanceResetAt(message) {
11821
+ const text = stripZeroWidthChars(message);
11822
+ const iso = /"reset_at"\s*:\s*"([^"]+)"/.exec(text)?.[1];
11823
+ if (iso) {
11824
+ const at2 = new Date(iso.trim());
11825
+ return Number.isNaN(at2.getTime()) ? void 0 : at2.getTime();
11826
+ }
11827
+ const epoch = /"reset_at"\s*:\s*(\d{9,16})/.exec(text)?.[1];
11828
+ if (!epoch) return void 0;
11829
+ const value = Number(epoch);
11830
+ if (!Number.isFinite(value)) return void 0;
11831
+ const at = new Date(value >= 1e12 ? value : value * 1e3);
11832
+ return Number.isNaN(at.getTime()) ? void 0 : at.getTime();
11833
+ }
11834
+ function buildBalanceFailure(ctx) {
11835
+ const normalized = stripZeroWidthChars(ctx.message);
11836
+ const balanceDetails = parseEmbeddedBalanceDetails(normalized);
11837
+ const reason = balanceDetails ? t("balanceInsufficientReason", balanceDetails.required, balanceDetails.current) : sanitizeBalanceDetail(extractEmbeddedErrorMessage(normalized) ?? ctx.message) || extractBalanceErrorMarker(normalized) || t("localRunBalanceUnknownReason");
11838
+ const lines = [
11839
+ t(
11840
+ CODING_PLAN_EXHAUSTED_RE.test(normalized) ? "localRunBalanceCodingPlan" : "localRunBalanceExhausted",
11841
+ describeUpstreamTag(ctx),
11842
+ reason
11843
+ )
11844
+ ];
11845
+ const resetAt = extractBalanceResetAt(normalized);
11846
+ if (resetAt !== void 0 && resetAt > Date.now()) {
11847
+ lines.push(
11848
+ t(
11849
+ "localRunBalanceReset",
11850
+ formatCooldownUntilLocal(new Date(resetAt).toISOString())
11851
+ )
11852
+ );
11853
+ }
11854
+ lines.push(t("localRunBalanceExits"));
11855
+ return `${lines.join("\n")}
11121
11856
  `;
11122
11857
  }
11123
11858
  function buildTransientFailure(ctx) {
11124
- return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}; this is an upstream/gateway issue, not your local credential or config). Detail: ${ctx.message} ${NO_FALLBACK} Retry shortly, ${SERVER_FALLBACK_HINT}.
11859
+ return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}; this is an upstream/gateway issue, not your local credential or config). Detail: ${ctx.message} ${NO_FALLBACK} Retry shortly, ${SERVER_FALLBACK_HINT}
11125
11860
  `;
11126
11861
  }
11127
11862
  function buildUpstreamFailure(ctx) {
11128
11863
  const fix = ctx.where === "server chat proxy" ? `Check the agent's provider/api-key settings on nolo.chat` : `Check the agent's endpoint/model settings`;
11129
- return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}). Detail: ${ctx.message} ${NO_FALLBACK} ${fix}, ${SERVER_FALLBACK_HINT}.
11864
+ return `${RUN_UNAVAILABLE_PREFIX} (${ctx.where} returned HTTP ${ctx.status}). Detail: ${ctx.message} ${NO_FALLBACK} ${fix}, ${SERVER_FALLBACK_HINT}
11130
11865
  `;
11131
11866
  }
11132
11867
  function formatLocalTurnFailureLine(error) {
@@ -11137,6 +11872,17 @@ function formatLocalTurnFailureLine(error) {
11137
11872
  return `[nolo] ${t("llmRequestTimedOut", deadline)}
11138
11873
  `;
11139
11874
  }
11875
+ const cls = classifyLocalRunError(message);
11876
+ if (cls.kind === "rate-limit") {
11877
+ const rawCooldownUntil = error && typeof error === "object" ? error.cooldownUntil : void 0;
11878
+ return buildRateLimitFailure({
11879
+ message,
11880
+ where: "local provider",
11881
+ status: cls.status,
11882
+ ...cls.quotaExhausted ? { quotaExhausted: true } : {},
11883
+ ...typeof rawCooldownUntil === "string" && rawCooldownUntil ? { cooldownUntil: rawCooldownUntil } : {}
11884
+ });
11885
+ }
11140
11886
  return `[nolo] Local agent run failed: ${message}
11141
11887
  `;
11142
11888
  }
@@ -11167,22 +11913,11 @@ function describeLocalRunFailure(message, rawError) {
11167
11913
  return `${RUN_UNAVAILABLE_PREFIX} \u670D\u52A1\u5668\u7D27\u5F20${shown !== "\u670D\u52A1\u5668\u7D27\u5F20" ? ` (${shown})` : ""} (PLATFORM_LLM_BUSY)${cleanedBusyDetail ? `: ${cleanedBusyDetail}` : ""}. ${NO_FALLBACK} \u5E73\u53F0\u6A21\u578B\u4E0A\u6E38\u7E41\u5FD9\uFF0C\u7A0D\u540E\u91CD\u8BD5\u6216\u6362\u4E2A\u6A21\u578B\u3002Retry shortly, ${SERVER_FALLBACK_HINT}
11168
11914
  `;
11169
11915
  }
11170
- if (/UPSTREAM_402|Insufficient Balance|余额不足|insufficient\s+balance/i.test(
11171
- message
11172
- )) {
11173
- const cleanedMessage = stripDebugNoise(message);
11174
- const fallback = cleanedMessage.replace(
11175
- /^[^:]*provider failed: HTTP \d{3}\s*/,
11176
- ""
11177
- );
11178
- const balanceDetails = parseEmbeddedBalanceDetails(cleanedMessage);
11179
- const shownMessage = balanceDetails ? t(
11180
- "balanceInsufficientReason",
11181
- balanceDetails.required,
11182
- balanceDetails.current
11183
- ) : extractEmbeddedErrorMessage(cleanedMessage) ?? fallback;
11184
- return `[nolo] ${shownMessage}
11185
- `;
11916
+ if (matchesBalanceError(message)) {
11917
+ return buildBalanceFailure({
11918
+ message,
11919
+ where: PLATFORM_TRANSPORT_RE.test(message) ? "server chat proxy" : "local provider"
11920
+ });
11186
11921
  }
11187
11922
  if (/maximum context length/i.test(message)) {
11188
11923
  const details = parseContextLengthDetails(message);
@@ -11192,31 +11927,39 @@ function describeLocalRunFailure(message, rawError) {
11192
11927
  }
11193
11928
  if (isCliAuthorityBrokerTimeoutError(rawError) || /CLI authority broker .* timed out/i.test(message)) {
11194
11929
  const cleaned = stripDebugNoise(message);
11195
- return `${RUN_UNAVAILABLE_PREFIX} (${cleaned}). ${NO_FALLBACK} The local authority broker timed out and did not respond in time (an existing broker process may be unresponsive). Check the local broker process or retry, ${SERVER_FALLBACK_HINT}.
11930
+ return `${RUN_UNAVAILABLE_PREFIX} (${cleaned}). ${NO_FALLBACK} The local authority broker timed out and did not respond in time (an existing broker process may be unresponsive). Check the local broker process or retry, ${SERVER_FALLBACK_HINT}
11196
11931
  `;
11197
11932
  }
11198
11933
  if (/CLI authority broker could not attach or take ownership/i.test(message)) {
11199
11934
  const cleaned = stripDebugNoise(message);
11200
- return `${RUN_UNAVAILABLE_PREFIX} (${cleaned}). ${NO_FALLBACK} The local runtime could not attach to an existing broker or take database ownership. Check running broker processes holding the local authority store or retry, ${SERVER_FALLBACK_HINT}.
11935
+ if (/EADDRINUSE/i.test(message)) {
11936
+ return `${RUN_UNAVAILABLE_PREFIX} (${cleaned}). ${NO_FALLBACK} Use --server to run on the server explicitly.
11937
+ `;
11938
+ }
11939
+ return `${RUN_UNAVAILABLE_PREFIX} (${cleaned}). ${NO_FALLBACK} The local runtime could not attach to an existing broker or take database ownership. Check running broker processes holding the local authority store or retry, ${SERVER_FALLBACK_HINT}
11201
11940
  `;
11202
11941
  }
11203
11942
  if (isCliAuthorityBrokerUnavailableError(rawError) || /CLI authority broker unavailable at/i.test(message)) {
11204
11943
  const cleaned = stripDebugNoise(message);
11205
- return `${RUN_UNAVAILABLE_PREFIX} (${cleaned}). ${NO_FALLBACK} The local authority broker is unavailable. Start or restart the local authority broker and retry, ${SERVER_FALLBACK_HINT}.
11944
+ return `${RUN_UNAVAILABLE_PREFIX} (${cleaned}). ${NO_FALLBACK} The local authority broker is unavailable. Start or restart the local authority broker and retry, ${SERVER_FALLBACK_HINT}
11206
11945
  `;
11207
11946
  }
11208
11947
  if (isCliAuthorityBrokerProtocolError(rawError) || /CLI authority broker protocol|CLI authority broker .* returned malformed response/i.test(message)) {
11209
11948
  const cleaned = stripDebugNoise(message);
11210
- return `${RUN_UNAVAILABLE_PREFIX} (${cleaned}). ${NO_FALLBACK} The local authority broker returned a protocol or malformed response error. Check the running broker process and retry, ${SERVER_FALLBACK_HINT}.
11949
+ return `${RUN_UNAVAILABLE_PREFIX} (${cleaned}). ${NO_FALLBACK} The local authority broker returned a protocol or malformed response error. Check the running broker process and retry, ${SERVER_FALLBACK_HINT}
11211
11950
  `;
11212
11951
  }
11213
11952
  const cls = classifyLocalRunError(message);
11214
11953
  if (cls.kind === "generic") {
11954
+ if (/owner-required route not acknowledged/i.test(message)) {
11955
+ return `${RUN_UNAVAILABLE_PREFIX} (${message}). ${NO_FALLBACK} The server returned a successful response but did not acknowledge the owner route. Check server version or proxy configuration, ${SERVER_FALLBACK_HINT}
11956
+ `;
11957
+ }
11215
11958
  if (isTransientFetchError(message)) {
11216
11959
  return `${RUN_UNAVAILABLE_PREFIX} (${message}). ${NO_FALLBACK} The upstream connection dropped mid-request (transient network/gateway issue \u2014 not a local credential or config problem). Send again (or say "continue") to retry in the same conversation.
11217
11960
  `;
11218
11961
  }
11219
- return `${RUN_UNAVAILABLE_PREFIX} (${message}). ${NO_FALLBACK} Fix the local credential/config and retry, ${SERVER_FALLBACK_HINT}.
11962
+ return `${RUN_UNAVAILABLE_PREFIX} (${message}). ${NO_FALLBACK} Fix the local credential/config and retry, ${SERVER_FALLBACK_HINT}
11220
11963
  `;
11221
11964
  }
11222
11965
  const cooldownUntil = rawError && typeof rawError === "object" ? rawError.cooldownUntil : void 0;
@@ -11224,7 +11967,6 @@ function describeLocalRunFailure(message, rawError) {
11224
11967
  message,
11225
11968
  where: cls.transport === "platform" ? "server chat proxy" : "local provider",
11226
11969
  status: cls.status,
11227
- ...cls.statusInferred ? { statusInferred: true } : {},
11228
11970
  ...cls.quotaExhausted ? { quotaExhausted: true } : {},
11229
11971
  ...cooldownUntil ? { cooldownUntil } : {},
11230
11972
  ...credentialAccountId ? { credentialAccountId } : {}
@@ -11321,8 +12063,10 @@ async function runHttpAgentTurn(options, authToken) {
11321
12063
  ...options.dialogAgentMode ? { dialogAgentMode: options.dialogAgentMode } : {},
11322
12064
  ...subjectRefs ? { subjectRefs } : {},
11323
12065
  ...blockedToolNames !== void 0 ? { blockedToolNames } : {},
11324
- ...allowedToolNames !== void 0 ? { allowedToolNames } : {}
12066
+ ...allowedToolNames !== void 0 ? { allowedToolNames } : {},
12067
+ ...options.runtimeToolPolicyOverride ? { runtimeToolPolicyOverride: options.runtimeToolPolicyOverride } : {}
11325
12068
  },
12069
+ ...options.strictContinueHistory ? { strictContinueHistory: true } : {},
11326
12070
  ...options.continueDialogId ? { continueDialogId: options.continueDialogId } : {},
11327
12071
  ...options.spaceId ? { spaceId: options.spaceId } : {},
11328
12072
  ...options.category ? { category: options.category } : {},
@@ -11330,6 +12074,7 @@ async function runHttpAgentTurn(options, authToken) {
11330
12074
  ...options.parentDialogId ? { parentDialogId: options.parentDialogId } : {},
11331
12075
  ...options.background ? { background: true } : {},
11332
12076
  ...options.ephemeral ? { ephemeral: true } : {},
12077
+ ...options.runtimeKey ? { runtimeKey: options.runtimeKey } : {},
11333
12078
  ...typeof options.timeoutMs === "number" ? { timeoutMs: options.timeoutMs } : {},
11334
12079
  ...options.modelOverride ? { runtimeOptions: { quickChatModelOverride: options.modelOverride } } : {},
11335
12080
  ...serverContextBlockScopes ? { contextBlockScopes: serverContextBlockScopes } : {},
@@ -11440,15 +12185,24 @@ ${options.agentName} > (no text response)
11440
12185
  const turnCredits = platformCreditsFromUsage(
11441
12186
  data?.usage
11442
12187
  );
11443
- return {
12188
+ const serverResult = {
11444
12189
  exitCode: 0,
11445
12190
  ...typeof data?.dialogId === "string" && data.dialogId ? { dialogId: data.dialogId } : {},
12191
+ // 结论载体与 local 路径同契约(server 模式 / 本地配置缺失时的兜底通道):
12192
+ // 结算点只认 result.finalText,HTTP 派发不给就等于这批 run 没有结论载体,
12193
+ // status 里既无 lastAssistantText 也无 resultFile。content 已在上面算好。
12194
+ ...content ? { finalText: content } : {},
11446
12195
  turnTokens: buildTurnTokenUsage(
11447
12196
  data?.usage,
11448
12197
  typeof data?.model === "string" ? data.model : options.agentKey
11449
12198
  ),
11450
12199
  ...turnCredits !== void 0 ? { turnCredits } : {}
11451
12200
  };
12201
+ recordRunResultHeaderMeta(serverResult, {
12202
+ model: typeof data?.model === "string" ? data.model : void 0,
12203
+ dialogServer: serverOriginForDialog(options.serverUrl)
12204
+ });
12205
+ return serverResult;
11452
12206
  }
11453
12207
  async function runInjectedLocalAgentTurn(options) {
11454
12208
  return runLocalAgentTurnForCli(options, { reportFailure: true });
@@ -11459,8 +12213,40 @@ async function refreshMissingLocalAgentConfig(options) {
11459
12213
  const agentConfig = await adapter.loadAgentConfig(options.agentKey);
11460
12214
  return Boolean(agentConfig);
11461
12215
  }
12216
+ async function releaseAdapterSandboxWorkload(adapter) {
12217
+ const release = adapter?.releaseLocalSandboxWorkload;
12218
+ if (typeof release !== "function") return;
12219
+ try {
12220
+ await release.call(adapter);
12221
+ } catch {
12222
+ }
12223
+ }
11462
12224
  async function runLocalAgentTurnForCli(options, settings) {
11463
12225
  const resolvedBaseAdapter = resolveLocalRuntimeAdapter(options);
12226
+ try {
12227
+ if (options.runtimeKey) {
12228
+ const prepare = resolvedBaseAdapter?.prepareLocalRuntimeWorkload;
12229
+ if (typeof prepare === "function") {
12230
+ try {
12231
+ await prepare.call(resolvedBaseAdapter);
12232
+ } catch (error) {
12233
+ const message = error instanceof Error ? error.message : String(error);
12234
+ options.output.write(`[nolo] ${message}
12235
+ `);
12236
+ return { exitCode: 1, localError: error };
12237
+ }
12238
+ }
12239
+ }
12240
+ return await runLocalAgentTurnForCliWithAdapter(
12241
+ options,
12242
+ settings,
12243
+ resolvedBaseAdapter
12244
+ );
12245
+ } finally {
12246
+ await releaseAdapterSandboxWorkload(resolvedBaseAdapter);
12247
+ }
12248
+ }
12249
+ async function runLocalAgentTurnForCliWithAdapter(options, settings, resolvedBaseAdapter) {
11464
12250
  const baseAdapter = (() => {
11465
12251
  let adapter2 = resolvedBaseAdapter && options.modelOverride ? wrapLoadAgentConfigWithModelOverride(
11466
12252
  resolvedBaseAdapter,
@@ -11483,15 +12269,17 @@ async function runLocalAgentTurnForCli(options, settings) {
11483
12269
  const blockedToolNames = options.blockedToolNames?.filter(
11484
12270
  (name) => name.trim()
11485
12271
  );
11486
- const runtimeContext = subjectRefs || allowedToolNames !== void 0 || blockedToolNames !== void 0 || options.parentWakeOnTerminal || options.dialogAgentMode ? {
12272
+ const runtimeContext = subjectRefs || allowedToolNames !== void 0 || blockedToolNames !== void 0 || options.runtimeToolPolicyOverride || options.parentWakeOnTerminal || options.dialogAgentMode ? {
11487
12273
  ...subjectRefs ? { subjectRefs } : {},
11488
12274
  ...options.dialogAgentMode ? { dialogAgentMode: options.dialogAgentMode } : {},
11489
12275
  ...allowedToolNames !== void 0 ? { allowedToolNames } : {},
11490
12276
  ...blockedToolNames !== void 0 ? { blockedToolNames } : {},
12277
+ ...options.runtimeToolPolicyOverride ? { runtimeToolPolicyOverride: options.runtimeToolPolicyOverride } : {},
11491
12278
  ...options.parentWakeOnTerminal ? { parentWakeOnTerminal: true } : {},
11492
12279
  ...options.parentDialogId ? { parentThreadId: options.parentDialogId } : {}
11493
12280
  } : void 0;
11494
12281
  const currentDialogId = options.continueDialogId ?? ulid2();
12282
+ const freshDialog = options.freshDialog ?? !options.continueDialogId;
11495
12283
  const turnId = `turn-${ulid2()}`;
11496
12284
  const runtimeContextWithOwnership = {
11497
12285
  ...runtimeContext ?? {},
@@ -11507,26 +12295,44 @@ async function runLocalAgentTurnForCli(options, settings) {
11507
12295
  });
11508
12296
  turnOutput.spinner.start();
11509
12297
  try {
12298
+ const localAttachmentPaths = (options.localAttachmentPaths ?? []).filter(
12299
+ (p) => typeof p === "string" && p.trim().length > 0
12300
+ );
12301
+ const { cardText: localAttachmentCard, parts: localAttachmentParts } = buildLocalAttachments({
12302
+ paths: localAttachmentPaths,
12303
+ machineId: localAttachmentPaths.length > 0 ? await resolveCurrentMachineId(options) : void 0,
12304
+ ...options.localRuntimeCwd ? { workspaceRoot: options.localRuntimeCwd } : {}
12305
+ });
12306
+ const messageForLocal = appendAttachmentCard(options.message, localAttachmentCard);
12307
+ const durableAttachmentParts = ENABLE_REMOTE_ATTACHMENT_PART_WRITES ? localAttachmentParts : [];
12308
+ const hasDurableAttachments = durableAttachmentParts.length > 0;
11510
12309
  const runLocalAgentTurn = await loadRunLocalAgentTurn();
11511
12310
  const result = await runLocalAgentTurn({
11512
12311
  adapter,
11513
12312
  agentRef: options.agentKey,
11514
12313
  userLanguage: options.userLanguage ?? options.env.NOLO_LANG ?? null,
11515
- input: buildUserInputContent(options.message, options.imageUrls),
11516
- ...expandedMessage !== options.message ? {
11517
- persistedInput: buildUserInputContent(
12314
+ input: buildUserInputContent(messageForLocal, options.imageUrls),
12315
+ ...expandedMessage !== options.message || localAttachmentCard !== "" ? {
12316
+ persistedInput: hasDurableAttachments ? buildUserInputContent(
11518
12317
  expandedMessage,
12318
+ options.imageUrls,
12319
+ durableAttachmentParts
12320
+ ) : buildUserInputContent(
12321
+ appendAttachmentCard(expandedMessage, localAttachmentCard),
11519
12322
  options.imageUrls
11520
12323
  ),
11521
- persistedInputReference: buildUserInputContent(
12324
+ persistedInputReference: hasDurableAttachments ? buildUserInputContent(
11522
12325
  options.message,
11523
- options.imageUrls
11524
- )
12326
+ options.imageUrls,
12327
+ durableAttachmentParts
12328
+ ) : buildUserInputContent(messageForLocal, options.imageUrls)
11525
12329
  } : {},
11526
12330
  ...options.pastedTextStore ? {
11527
12331
  contextReferenceResolver: (reference) => canResolveCollapsedPasteReference(options.pastedTextStore, reference)
11528
12332
  } : {},
11529
12333
  continueDialogId: currentDialogId,
12334
+ ...options.strictContinueHistory ? { strictContinueHistory: true } : {},
12335
+ ...freshDialog ? { freshDialog: true } : {},
11530
12336
  fileWriteSessionId: currentDialogId,
11531
12337
  fileWriteGateEnabled: resolveFileWriteGateEnabled(options.env),
11532
12338
  spaceId: options.spaceId,
@@ -11585,9 +12391,10 @@ async function runLocalAgentTurnForCli(options, settings) {
11585
12391
  });
11586
12392
  turnOutput.finish(result.content);
11587
12393
  const turnCredits = sumPlatformCredits(result.usageRecords);
11588
- return {
12394
+ const turnResult = {
11589
12395
  exitCode: 0,
11590
12396
  dialogId: result.dialogId,
12397
+ ...typeof result.content === "string" && result.content.trim() ? { finalText: result.content } : {},
11591
12398
  title: result.title,
11592
12399
  ...result.titlePatchPromise ? { titlePatchPromise: result.titlePatchPromise } : {},
11593
12400
  ...pickEmptyAssistantFlags(result),
@@ -11599,6 +12406,17 @@ async function runLocalAgentTurnForCli(options, settings) {
11599
12406
  ...turnCredits !== void 0 ? { turnCredits } : {},
11600
12407
  ...result.usageRecords?.length ? { usageRecords: result.usageRecords } : {}
11601
12408
  };
12409
+ const serverMeta = resolveResultServerMeta({
12410
+ env: options.env ?? {},
12411
+ userId: resolveLocalUserId(options.env ?? {}),
12412
+ hasSubjectRefs: (buildSubjectRefs(options)?.length ?? 0) > 0
12413
+ });
12414
+ recordRunResultHeaderMeta(turnResult, {
12415
+ model: result.model,
12416
+ dialogServer: serverMeta.server,
12417
+ serverSync: serverMeta.serverSync
12418
+ });
12419
+ return turnResult;
11602
12420
  } catch (error) {
11603
12421
  turnOutput.spinner.stop();
11604
12422
  turnOutput.cancel({
@@ -11633,12 +12451,6 @@ async function runLocalAgentTurnForCli(options, settings) {
11633
12451
  } else {
11634
12452
  options.output.write(failureLine);
11635
12453
  }
11636
- if (cooldownUntil) {
11637
- options.output.write(
11638
- `[nolo] \u5DF2\u6807\u8BB0\u51B7\u5374\u81F3 ${cooldownUntil}\uFF0C\u5230\u671F\u524D\u6D3E\u53D1\u8BE5 agent \u4F1A\u88AB\u51B7\u5374\u95E8\u63A7\u62E6\u622A\u3002
11639
- `
11640
- );
11641
- }
11642
12454
  }
11643
12455
  return {
11644
12456
  exitCode: 1,
@@ -11650,6 +12462,7 @@ async function runLocalAgentTurnForCli(options, settings) {
11650
12462
  }
11651
12463
  }
11652
12464
  async function checkLocalAvailabilityBeforeHttpDispatch(options) {
12465
+ if (options.runtimeKey && !isDockerRuntimeKey(options.runtimeKey)) return null;
11653
12466
  const adapter = resolveLocalRuntimeAdapter(options);
11654
12467
  if (!adapter || typeof adapter.loadAgentConfig !== "function") return null;
11655
12468
  let config;
@@ -11688,14 +12501,19 @@ async function checkLocalAvailabilityBeforeHttpDispatch(options) {
11688
12501
  }
11689
12502
  if (gateDecision !== "blocked") return { credentialKey };
11690
12503
  options.output.write(
11691
- `[nolo] Agent ${options.agentName || options.agentKey} is temporarily unavailable (429 cooldown) until ${new Date(Number(effectiveNextAvailableAt)).toISOString()}.
11692
- Dispatch aborted before reaching the server. Pick another agent via listAgents, or retry after the cooldown.
12504
+ `${t(
12505
+ "agentCooldownBlocked",
12506
+ options.agentName || options.agentKey,
12507
+ formatCooldownUntilLocal(
12508
+ new Date(Number(effectiveNextAvailableAt)).toISOString()
12509
+ )
12510
+ )}
11693
12511
  `
11694
12512
  );
11695
12513
  return { exitCode: 1 };
11696
12514
  }
11697
12515
  function foldLocalResultForTui(localResult) {
11698
- return {
12516
+ const folded = {
11699
12517
  exitCode: localResult.exitCode,
11700
12518
  ...localResult.dialogId ? { dialogId: localResult.dialogId } : {},
11701
12519
  title: localResult.title,
@@ -11712,16 +12530,57 @@ function foldLocalResultForTui(localResult) {
11712
12530
  // 漏过 turnCredits(fix/tui-session-credits),usageRecords 是同坑位新字段。
11713
12531
  ...localResult.usageRecords?.length ? { usageRecords: localResult.usageRecords } : {},
11714
12532
  ...localResult.streamInterrupted ? { streamInterrupted: localResult.streamInterrupted } : {},
11715
- ...localResult.pendingToolName ? { pendingToolName: localResult.pendingToolName } : {}
12533
+ ...localResult.pendingToolName ? { pendingToolName: localResult.pendingToolName } : {},
12534
+ // 结论正文必须随行:auto→local 是本函数的唯一出口(runAgentTurn 的两处
12535
+ // 成功分支都 return foldLocalResultForTui(...)),漏掉它 = 默认派发路径
12536
+ // 上 finalText 永远到不了结算点 → agentRunCommand 的 settleRunTerminal-
12537
+ // Authoritatively 拿不到 lastAssistantText → `.result.md` 不写、status 无
12538
+ // resultFile,编排者只能去啃带 ANSI 的 .log(同坑位历史:turnCredits)。
12539
+ ...localResult.finalText ? { finalText: localResult.finalText } : {}
11716
12540
  };
12541
+ const headerMeta = getRunResultHeaderMeta(localResult);
12542
+ recordRunResultHeaderMeta(folded, headerMeta);
12543
+ return folded;
11717
12544
  }
11718
12545
  async function runAgentTurn(options) {
11719
12546
  const authToken = resolveAuthToken2(options.env);
11720
- const runtimeMode = resolveRequestedRuntimeMode(options);
12547
+ const requestedRuntimeMode = resolveRequestedRuntimeMode(options);
12548
+ if (options.requireRemoteDispatch && requestedRuntimeMode === "local") {
12549
+ options.output.write(MACHINE_SHELL_LOCAL_REFUSAL_MESSAGE);
12550
+ return { exitCode: 1 };
12551
+ }
12552
+ const runtimeMode = options.requireRemoteDispatch ? "server" : requestedRuntimeMode;
11721
12553
  if (runtimeMode === "local") {
12554
+ const runtimeKeyIsLocallyFulfillable = resolveCliLocalRuntimeKeyCapability(options.runtimeKey).fulfillableByCliLocal;
12555
+ if (options.runtimeKey && !runtimeKeyIsLocallyFulfillable) {
12556
+ options.output.write("[nolo] \u672C\u5730 run \u7531\u672C\u673A\u6C99\u76D2\u51B3\u5B9A\uFF0C\u4E0D\u652F\u6301\u6307\u5B9A\u4E91\u540E\u7AEF\n");
12557
+ return { exitCode: 1 };
12558
+ }
11722
12559
  return runInjectedLocalAgentTurn(options);
11723
12560
  }
11724
- if (runtimeMode === "auto" && shouldAttemptAutoLocal(options)) {
12561
+ if (runtimeMode === "auto" && !options.runtimeKey && shouldAttemptAutoLocal(options)) {
12562
+ const rawAdapter = resolveLocalRuntimeAdapter(options);
12563
+ let config;
12564
+ const invalidateConfig = () => {
12565
+ config = void 0;
12566
+ };
12567
+ if (rawAdapter) {
12568
+ options = {
12569
+ ...options,
12570
+ localRuntimeAdapter: {
12571
+ ...rawAdapter,
12572
+ loadAgentConfig: async (agentRef) => {
12573
+ if (agentRef !== options.agentKey) {
12574
+ return rawAdapter.loadAgentConfig(agentRef);
12575
+ }
12576
+ if (config) return config;
12577
+ const loaded = await rawAdapter.loadAgentConfig(agentRef);
12578
+ if (loaded) config = loaded;
12579
+ return loaded;
12580
+ }
12581
+ }
12582
+ };
12583
+ }
11725
12584
  const skipLocal = await shouldSkipAutoLocalForServerPlatformTools(options);
11726
12585
  if (!skipLocal) {
11727
12586
  const localResult = await runLocalAgentTurnForCli(options, {
@@ -11730,6 +12589,7 @@ async function runAgentTurn(options) {
11730
12589
  if (localResult.exitCode === 0) {
11731
12590
  return foldLocalResultForTui(localResult);
11732
12591
  }
12592
+ invalidateConfig();
11733
12593
  if (isMissingLocalAgentConfigError(localResult.localError, options.agentKey)) {
11734
12594
  options.output.write(
11735
12595
  `[nolo] Local agent config was missing; refreshing local config and retrying local once.
@@ -11744,8 +12604,10 @@ async function runAgentTurn(options) {
11744
12604
  if (retriedLocalResult.exitCode === 0) {
11745
12605
  return foldLocalResultForTui(retriedLocalResult);
11746
12606
  }
12607
+ invalidateConfig();
11747
12608
  }
11748
12609
  } catch {
12610
+ invalidateConfig();
11749
12611
  }
11750
12612
  }
11751
12613
  const localErrorMessage = localResult.localError ? toErrorMessage(localResult.localError) : "local runtime failed";
@@ -11783,23 +12645,204 @@ async function runAgentTurn(options) {
11783
12645
  return httpResult;
11784
12646
  }
11785
12647
 
12648
+ // packages/cli/client/terminalProgramStatus.ts
12649
+ var TERMINAL_PROGRAM_STATUS_APP = "nolo";
12650
+ var KNOWN_STATES = /* @__PURE__ */ new Set([
12651
+ "idle",
12652
+ "working",
12653
+ "blocked",
12654
+ "done",
12655
+ "error"
12656
+ ]);
12657
+ var KNOWN_KINDS = /* @__PURE__ */ new Set([
12658
+ "permission",
12659
+ "question",
12660
+ "auth"
12661
+ ]);
12662
+ function encodeTerminalProgramStatus(report) {
12663
+ const state2 = report?.state;
12664
+ if (typeof state2 !== "string" || !KNOWN_STATES.has(state2)) return null;
12665
+ const pairs = [`state=${state2}`, `app=${TERMINAL_PROGRAM_STATUS_APP}`];
12666
+ if (state2 === "blocked" && typeof report.kind === "string" && KNOWN_KINDS.has(report.kind)) {
12667
+ pairs.push(`kind=${report.kind}`);
12668
+ }
12669
+ return `\x1B]7501;${pairs.join(":")}\x1B\\`;
12670
+ }
12671
+ function emitTerminalProgramStatus(output, report) {
12672
+ if (!output || typeof output.write !== "function") return false;
12673
+ if (output.isTTY !== true) return false;
12674
+ const sequence2 = encodeTerminalProgramStatus(report);
12675
+ if (sequence2 === null) return false;
12676
+ try {
12677
+ output.write(sequence2);
12678
+ return true;
12679
+ } catch {
12680
+ return false;
12681
+ }
12682
+ }
12683
+
12684
+ // packages/cli/client/terminalRunStatus.ts
12685
+ var FAILED_EMPTY_ASSISTANT_REASONS = /* @__PURE__ */ new Set([
12686
+ "length_truncated",
12687
+ "stream_truncated",
12688
+ "repetition_loop",
12689
+ "stagnant_tool_calls"
12690
+ ]);
12691
+ var isRunResultStalledOrTruncated = (result) => !result.emptyAssistantOutputUsable && FAILED_EMPTY_ASSISTANT_REASONS.has(result.emptyAssistantFallbackReason ?? "");
12692
+ function resolveTerminalProgramStatusState(input) {
12693
+ if (input.interrupted) return "idle";
12694
+ if (input.stalledOrTruncated || input.exitCode !== 0) return "error";
12695
+ return "done";
12696
+ }
12697
+
12698
+ // packages/cli/client/oneShotTerminalStatus.ts
12699
+ function resolveOneShotTerminalState(result) {
12700
+ return resolveTerminalProgramStatusState({
12701
+ exitCode: result.exitCode,
12702
+ interrupted: result.streamInterrupted,
12703
+ stalledOrTruncated: result.stalledOrTruncated
12704
+ });
12705
+ }
12706
+ function createOneShotTerminalStatus(output) {
12707
+ let last;
12708
+ let terminal = false;
12709
+ const report = (state2) => {
12710
+ if (!output || terminal || last === state2) return;
12711
+ last = state2;
12712
+ if (state2 === "done" || state2 === "error") terminal = true;
12713
+ emitTerminalProgramStatus(output, { state: state2 });
12714
+ };
12715
+ return {
12716
+ working: () => report("working"),
12717
+ settle: (result) => report(resolveOneShotTerminalState(result)),
12718
+ fail: () => report("error")
12719
+ };
12720
+ }
12721
+
11786
12722
  // packages/cli/agentRunCommand.ts
11787
12723
  import * as nodeFs from "node:fs";
11788
12724
 
11789
12725
  // packages/cli/client/autoModelRouter.ts
11790
12726
  var CLI_AUTO_ROUTE_AGENT_KEY = BUILTIN_NOLO_AGENT_KEY;
11791
12727
 
11792
- // packages/agent-runtime/agentsMd.ts
12728
+ // packages/agent-runtime/hostEnvironment.ts
11793
12729
  import { existsSync, readFileSync } from "node:fs";
12730
+ import os from "node:os";
12731
+ function parseLinuxOsRelease(content) {
12732
+ let prettyName;
12733
+ let name;
12734
+ let version;
12735
+ for (const line of content.split("\n")) {
12736
+ const trimmed = line.trim();
12737
+ if (!trimmed || trimmed.startsWith("#")) continue;
12738
+ const eqIdx = trimmed.indexOf("=");
12739
+ if (eqIdx === -1) continue;
12740
+ const key = trimmed.slice(0, eqIdx).trim();
12741
+ let val = trimmed.slice(eqIdx + 1).trim();
12742
+ if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
12743
+ val = val.slice(1, -1);
12744
+ }
12745
+ if (key === "PRETTY_NAME") {
12746
+ prettyName = val;
12747
+ } else if (key === "NAME") {
12748
+ name = val;
12749
+ } else if (key === "VERSION") {
12750
+ version = val;
12751
+ }
12752
+ }
12753
+ if (prettyName) return prettyName;
12754
+ if (name && version) return `${name} ${version}`;
12755
+ return name;
12756
+ }
12757
+ function probeHostEnvironment(options) {
12758
+ const platform = options?.platform ?? process.platform;
12759
+ const arch = options?.arch ?? os.arch();
12760
+ const release = options?.release ?? os.release();
12761
+ const env = options?.env ?? process.env;
12762
+ let osName = `${platform} ${release}`;
12763
+ if (platform === "linux") {
12764
+ let osReleaseText = options?.osReleaseContent;
12765
+ if (osReleaseText === void 0) {
12766
+ try {
12767
+ if (existsSync("/etc/os-release")) {
12768
+ osReleaseText = readFileSync("/etc/os-release", "utf8");
12769
+ } else if (existsSync("/usr/lib/os-release")) {
12770
+ osReleaseText = readFileSync("/usr/lib/os-release", "utf8");
12771
+ }
12772
+ } catch {
12773
+ }
12774
+ }
12775
+ if (osReleaseText) {
12776
+ const parsed = parseLinuxOsRelease(osReleaseText);
12777
+ if (parsed) {
12778
+ osName = parsed;
12779
+ } else {
12780
+ osName = `Linux ${release}`;
12781
+ }
12782
+ } else {
12783
+ osName = `Linux ${release}`;
12784
+ }
12785
+ } else if (platform === "darwin") {
12786
+ osName = `macOS (${release})`;
12787
+ } else if (platform === "win32") {
12788
+ osName = `Windows (${release})`;
12789
+ }
12790
+ const desktop = env.XDG_CURRENT_DESKTOP || env.XDG_SESSION_DESKTOP || env.DESKTOP_SESSION || void 0;
12791
+ const sessionType = env.XDG_SESSION_TYPE || void 0;
12792
+ const shell = env.SHELL || (platform === "win32" ? env.COMSPEC || "PowerShell" : void 0);
12793
+ return {
12794
+ platform,
12795
+ osName,
12796
+ arch,
12797
+ desktop,
12798
+ sessionType,
12799
+ shell
12800
+ };
12801
+ }
12802
+ function formatHostEnvironmentContent(details) {
12803
+ const lines = ["--- \u5BBF\u4E3B\u73AF\u5883\uFF08Host Environment\uFF09---"];
12804
+ lines.push(`\u64CD\u4F5C\u7CFB\u7EDF: ${details.osName} (${details.arch})`);
12805
+ if (details.desktop || details.sessionType) {
12806
+ const desktopParts = [];
12807
+ if (details.desktop) desktopParts.push(details.desktop);
12808
+ if (details.sessionType) desktopParts.push(details.sessionType);
12809
+ lines.push(`\u684C\u9762\u73AF\u5883: ${desktopParts.join(" / ")}`);
12810
+ }
12811
+ if (details.shell) {
12812
+ lines.push(`\u9ED8\u8BA4 Shell: ${details.shell}`);
12813
+ }
12814
+ return lines.join("\n");
12815
+ }
12816
+ var cachedLayer = null;
12817
+ function buildHostEnvironmentLayer(options) {
12818
+ if (!options && cachedLayer) {
12819
+ return cachedLayer;
12820
+ }
12821
+ const details = probeHostEnvironment(options);
12822
+ const content = formatHostEnvironmentContent(details);
12823
+ const layer = {
12824
+ id: "host-environment",
12825
+ owner: "runtime",
12826
+ cacheScope: "session",
12827
+ content
12828
+ };
12829
+ if (!options) {
12830
+ cachedLayer = layer;
12831
+ }
12832
+ return layer;
12833
+ }
12834
+
12835
+ // packages/agent-runtime/agentsMd.ts
12836
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
11794
12837
  import { join } from "node:path";
11795
12838
  var AGENTS_MD_MAX_BYTES = 8192;
11796
12839
  var AGENTS_MD_CANDIDATES = ["AGENTS.md", "CLAUDE.md"];
11797
12840
  function readAgentsMdLayerFromDisk(cwd) {
11798
12841
  for (const name of AGENTS_MD_CANDIDATES) {
11799
12842
  const filePath = join(cwd, name);
11800
- if (!existsSync(filePath)) continue;
12843
+ if (!existsSync2(filePath)) continue;
11801
12844
  try {
11802
- let content = readFileSync(filePath, "utf8").trim();
12845
+ let content = readFileSync2(filePath, "utf8").trim();
11803
12846
  if (!content) continue;
11804
12847
  if (Buffer.byteLength(content, "utf8") > AGENTS_MD_MAX_BYTES) {
11805
12848
  content = Buffer.from(content, "utf8").subarray(0, AGENTS_MD_MAX_BYTES).toString("utf8") + "\n\n<!-- AGENTS.md truncated -->";
@@ -11869,14 +12912,14 @@ function runDoDCommands(commands, cwd, deps = {}) {
11869
12912
  }
11870
12913
 
11871
12914
  // packages/cli/agentRunPrompts.ts
11872
- import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync, statSync } from "node:fs";
12915
+ import { existsSync as existsSync3, readFileSync as readFileSync3, readdirSync, statSync as statSync2 } from "node:fs";
11873
12916
  import { dirname, extname, isAbsolute, join as join2, relative as relativePath, resolve, sep } from "node:path";
11874
12917
  function workflowRefToCandidatePath(cwd, ref) {
11875
12918
  const normalized = ref.trim();
11876
12919
  if (!normalized) return "";
11877
12920
  if (normalized.endsWith(".md") || normalized.includes("/") || normalized.includes("\\")) {
11878
12921
  const directPath = resolve(cwd, normalized);
11879
- if (existsSync2(directPath)) return directPath;
12922
+ if (existsSync3(directPath)) return directPath;
11880
12923
  }
11881
12924
  const fileName = normalized.replace(/[^a-zA-Z0-9一-鿿]+/g, "-").replace(/^-+|-+$/g, "");
11882
12925
  return resolve(cwd, "docs", "workflows", `${fileName}.md`);
@@ -11889,21 +12932,21 @@ function skillRefToCandidatePath(cwd, ref) {
11889
12932
  if (!normalized) return "";
11890
12933
  if (normalized.endsWith(".md") || normalized.includes("/") || normalized.includes("\\")) {
11891
12934
  const directPath = resolve(cwd, normalized);
11892
- if (existsSync2(directPath)) return directPath;
12935
+ if (existsSync3(directPath)) return directPath;
11893
12936
  }
11894
12937
  const fileName = normalized.replace(/[^a-zA-Z0-9一-鿿]+/g, "-").replace(/^-+|-+$/g, "");
11895
12938
  for (const dir of SKILL_SEARCH_DIRS) {
11896
12939
  const skillMdPath = resolve(cwd, dir, fileName, "SKILL.md");
11897
- if (existsSync2(skillMdPath)) return skillMdPath;
12940
+ if (existsSync3(skillMdPath)) return skillMdPath;
11898
12941
  }
11899
12942
  return resolve(cwd, ".agents", "skills", fileName, "SKILL.md");
11900
12943
  }
11901
12944
  async function resolveWorkflowReference(ref, cwd = process.cwd()) {
11902
- const path = workflowRefToCandidatePath(cwd, ref);
11903
- if (!path || !existsSync2(path)) {
12945
+ const path2 = workflowRefToCandidatePath(cwd, ref);
12946
+ if (!path2 || !existsSync3(path2)) {
11904
12947
  throw new Error(`Workflow reference not found: ${ref}`);
11905
12948
  }
11906
- const markdown = readFileSync2(path, "utf8");
12949
+ const markdown = readFileSync3(path2, "utf8");
11907
12950
  const parsed = parseSkillDocProtocol(markdown);
11908
12951
  return {
11909
12952
  ref,
@@ -11920,8 +12963,8 @@ function inlineRelativeRefs(body, skillDir) {
11920
12963
  const absPath = resolve(skillDir, cleaned);
11921
12964
  const relative = relativePath(normalizedSkillDir, absPath);
11922
12965
  if (relative.startsWith("..") || isAbsolute(relative)) return match;
11923
- if (!existsSync2(absPath) || !absPath.endsWith(".md")) return match;
11924
- const refContent = readFileSync2(absPath, "utf8");
12966
+ if (!existsSync3(absPath) || !absPath.endsWith(".md")) return match;
12967
+ const refContent = readFileSync3(absPath, "utf8");
11925
12968
  return `
11926
12969
 
11927
12970
  ### ${label}
@@ -11933,7 +12976,7 @@ ${refContent}
11933
12976
  }
11934
12977
  function listSkillScripts(skillDir) {
11935
12978
  const scriptsDir = join2(skillDir, "scripts");
11936
- if (!existsSync2(scriptsDir) || !statSync(scriptsDir).isDirectory()) return null;
12979
+ if (!existsSync3(scriptsDir) || !statSync2(scriptsDir).isDirectory()) return null;
11937
12980
  const entries = readdirSync(scriptsDir).filter((e) => !e.startsWith("."));
11938
12981
  if (entries.length === 0) return null;
11939
12982
  return [
@@ -11959,13 +13002,13 @@ async function resolveSkillReference(ref, options = {}) {
11959
13002
  markdown = String(contentText);
11960
13003
  } else {
11961
13004
  const cwd = options.cwd ?? process.cwd();
11962
- const path = skillRefToCandidatePath(cwd, ref);
11963
- if (!path || !existsSync2(path)) {
13005
+ const path2 = skillRefToCandidatePath(cwd, ref);
13006
+ if (!path2 || !existsSync3(path2)) {
11964
13007
  throw new Error(`Skill reference not found: ${ref}`);
11965
13008
  }
11966
- markdown = readFileSync2(path, "utf8");
11967
- filePath = path;
11968
- skillDir = dirname(path);
13009
+ markdown = readFileSync3(path2, "utf8");
13010
+ filePath = path2;
13011
+ skillDir = dirname(path2);
11969
13012
  }
11970
13013
  const parsed = parseSkillDocProtocol(markdown);
11971
13014
  const name = parsed.meta?.skillConfig?.name;
@@ -12068,12 +13111,12 @@ function prependSubjectDialogMarker(message, subjectDialogKey) {
12068
13111
  function normalizeCliImageInput(input) {
12069
13112
  if (/^(https?:|data:|file:)/i.test(input)) return input;
12070
13113
  const absolutePath = resolve(input);
12071
- if (!existsSync2(absolutePath)) return input;
12072
- const base64 = readFileSync2(absolutePath).toString("base64");
13114
+ if (!existsSync3(absolutePath)) return input;
13115
+ const base64 = readFileSync3(absolutePath).toString("base64");
12073
13116
  return `data:${imageMimeTypeForPath(absolutePath)};base64,${base64}`;
12074
13117
  }
12075
- function imageMimeTypeForPath(path) {
12076
- switch (extname(path).toLowerCase()) {
13118
+ function imageMimeTypeForPath(path2) {
13119
+ switch (extname(path2).toLowerCase()) {
12077
13120
  case ".jpg":
12078
13121
  case ".jpeg":
12079
13122
  return "image/jpeg";
@@ -12495,8 +13538,8 @@ var scoreMemoryItem = (item, query, nowMs = Date.now(), context) => {
12495
13538
  const confidence = item.confidence ?? 0;
12496
13539
  const typeFit = typeFitScore(item);
12497
13540
  const understanding = understandingScore(item);
12498
- const path = pathScore(item, context);
12499
- return 0.25 * queryMatch + 0.2 * identifierMatch + 0.2 * path + 0.09 * retrieval + // weak retrieval signal, NOT successful-use reinforcement
13541
+ const path2 = pathScore(item, context);
13542
+ return 0.25 * queryMatch + 0.2 * identifierMatch + 0.2 * path2 + 0.09 * retrieval + // weak retrieval signal, NOT successful-use reinforcement
12500
13543
  0.16 * createdRecency + 0.06 * importance + 0.03 * confidence + 0.02 * typeFit + 0.01 * understanding;
12501
13544
  };
12502
13545
  var rankMemoryCandidates = (items, query, context) => {
@@ -12512,75 +13555,52 @@ var rankMemoryCandidates = (items, query, context) => {
12512
13555
  });
12513
13556
  };
12514
13557
 
12515
- // packages/ai/memory/vnext/store.ts
12516
- var enc = (value) => encodeURIComponent(value).replace(/-/g, "%2D");
12517
- var rangeOf = (prefix) => ({ gte: prefix, lte: `${prefix}\uFFFF` });
12518
- var entityKey = (ownerId, id) => `mem2-e-${enc(ownerId)}-${enc(id)}`;
12519
- var entityOwnerPrefix = (ownerId) => `mem2-e-${enc(ownerId)}-`;
12520
- var stateKey = (ownerId, id) => `mem2-s-${enc(ownerId)}-${enc(id)}`;
12521
- var stateEntityIndexKey = (ownerId, entityId, stateId) => `mem2-si-${enc(ownerId)}-${enc(entityId)}-${enc(stateId)}`;
12522
- var stateEntityIndexPrefix = (ownerId, entityId) => `mem2-si-${enc(ownerId)}-${enc(entityId)}-`;
12523
- var evidenceKey = (ownerId, id) => `mem2-v-${enc(ownerId)}-${enc(id)}`;
12524
- var relationKey = (ownerId, id) => `mem2-r-${enc(ownerId)}-${enc(id)}`;
12525
- var relationFromIndexKey = (ownerId, from, relationId) => `mem2-rf-${enc(ownerId)}-${enc(from)}-${enc(relationId)}`;
12526
- var relationToIndexKey = (ownerId, to, relationId) => `mem2-rt-${enc(ownerId)}-${enc(to)}-${enc(relationId)}`;
12527
- var readIndexed = async (db, prefix) => {
12528
- const refs = [];
12529
- for await (const [, value] of db.iterator({ ...rangeOf(prefix), reverse: false })) {
12530
- if (typeof value?.key === "string") refs.push(value.key);
12531
- }
12532
- const rows = await Promise.all(refs.map((key) => db.get(key).catch(() => null)));
12533
- return rows.filter((row) => !!row);
12534
- };
12535
- var getMemoryEntityVNext = async (db, ownerId, entityId) => db.get(entityKey(ownerId, entityId)).catch(() => null);
12536
- var listMemoryEntitiesVNext = async (db, ownerId) => {
12537
- const rows = [];
12538
- for await (const [, value] of db.iterator({
12539
- ...rangeOf(entityOwnerPrefix(ownerId)),
12540
- reverse: false
12541
- })) {
12542
- if (value) rows.push(value);
12543
- }
12544
- return rows;
12545
- };
12546
- var loadMemoryVNextCatalog = async (db, ownerId) => {
12547
- const entities = await listMemoryEntitiesVNext(db, ownerId);
12548
- const states = (await Promise.all(entities.map((entity) => listMemoryStatesForEntityVNext(db, ownerId, entity.id)))).flat();
12549
- return { entities, states };
12550
- };
12551
- var getMemoryStateVNext = async (db, ownerId, stateId) => db.get(stateKey(ownerId, stateId)).catch(() => null);
12552
- var listMemoryStatesForEntityVNext = (db, ownerId, entityId) => readIndexed(db, stateEntityIndexPrefix(ownerId, entityId));
12553
- var putMemoryEvidenceVNext = async (db, evidence) => {
12554
- await db.put(evidenceKey(evidence.ownerId, evidence.id), evidence);
12555
- };
12556
- var getMemoryEvidenceVNext = async (db, ownerId, evidenceId) => db.get(evidenceKey(ownerId, evidenceId)).catch(() => null);
12557
- var getMemoryEvidenceVNextStrict = async (db, ownerId, evidenceId) => {
12558
- try {
12559
- return await db.get(evidenceKey(ownerId, evidenceId));
12560
- } catch (error) {
12561
- if (isLevelNotFoundError(error)) return null;
12562
- throw error;
12563
- }
12564
- };
12565
- var _appendEntityBatch = (batch, entity) => {
12566
- batch.put(entityKey(entity.ownerId, entity.id), entity);
12567
- };
12568
- var _appendEvidenceBatch = (batch, evidence) => {
12569
- batch.put(evidenceKey(evidence.ownerId, evidence.id), evidence);
12570
- };
12571
- var _appendStateBatch = (batch, state2) => {
12572
- const key = stateKey(state2.ownerId, state2.id);
12573
- batch.put(key, state2);
12574
- batch.put(stateEntityIndexKey(state2.ownerId, state2.entityId, state2.id), { key });
12575
- };
12576
- var _appendRetiredStateBatch = (batch, state2) => {
12577
- batch.put(stateKey(state2.ownerId, state2.id), state2);
12578
- };
12579
- var _appendRelationBatch = (batch, relation) => {
12580
- const key = relationKey(relation.ownerId, relation.id);
12581
- batch.put(key, relation);
12582
- batch.put(relationFromIndexKey(relation.ownerId, relation.from, relation.id), { key });
12583
- batch.put(relationToIndexKey(relation.ownerId, relation.to, relation.id), { key });
13558
+ // packages/ai/memory/vnext/detachedThrottle.ts
13559
+ var DEFAULT_DETACHED_MEMORY_COOLDOWN_MS = 10 * 60 * 1e3;
13560
+ var MAX_COOLDOWN_KEYS = 512;
13561
+ var readMsEnv = (raw, fallback, allowZero) => {
13562
+ if (raw === void 0 || raw.trim() === "") return fallback;
13563
+ const parsed = Number(raw);
13564
+ if (!Number.isFinite(parsed) || parsed < 0) return fallback;
13565
+ if (parsed === 0 && !allowZero) return fallback;
13566
+ return parsed;
13567
+ };
13568
+ var createDetachedThrottle = (input) => {
13569
+ let inFlight2 = false;
13570
+ const lastStartedAt = /* @__PURE__ */ new Map();
13571
+ const resolveCooldownMs = (env = typeof process !== "undefined" ? process.env : {}) => readMsEnv(env[input.cooldownEnvKey], input.defaultCooldownMs, true);
13572
+ const rememberStart = (key, clockMs) => {
13573
+ lastStartedAt.delete(key);
13574
+ lastStartedAt.set(key, clockMs);
13575
+ while (lastStartedAt.size > MAX_COOLDOWN_KEYS) {
13576
+ lastStartedAt.delete(lastStartedAt.keys().next().value);
13577
+ }
13578
+ };
13579
+ return {
13580
+ name: input.name,
13581
+ defaultCooldownMs: input.defaultCooldownMs,
13582
+ cooldownEnvKey: input.cooldownEnvKey,
13583
+ resolveCooldownMs,
13584
+ tryAcquire(key, clockMs, cooldownMs) {
13585
+ if (inFlight2) return "busy";
13586
+ const interval = cooldownMs ?? resolveCooldownMs();
13587
+ const lastStarted = lastStartedAt.get(key);
13588
+ if (interval > 0 && lastStarted !== void 0 && clockMs - lastStarted < interval) {
13589
+ return "cooldown";
13590
+ }
13591
+ inFlight2 = true;
13592
+ rememberStart(key, clockMs);
13593
+ return "run";
13594
+ },
13595
+ release() {
13596
+ inFlight2 = false;
13597
+ },
13598
+ isInFlight: () => inFlight2,
13599
+ reset() {
13600
+ inFlight2 = false;
13601
+ lastStartedAt.clear();
13602
+ }
13603
+ };
12584
13604
  };
12585
13605
 
12586
13606
  // packages/ai/memory/vnext/recall.ts
@@ -12743,6 +13763,20 @@ var buildLegacyMemoryEvidence = (item) => {
12743
13763
  // packages/ai/memory/vnext/shadowRead.ts
12744
13764
  var SHADOW_TIMEOUT_MS = 2e4;
12745
13765
  var ERROR_MESSAGE_MAX = 120;
13766
+ var MEMORY_VNEXT_SHADOW_READ_COOLDOWN_ENV = "NOLO_MEMORY_VNEXT_SHADOW_READ_COOLDOWN_MS";
13767
+ var DEFAULT_SHADOW_READ_COOLDOWN_MS = DEFAULT_DETACHED_MEMORY_COOLDOWN_MS;
13768
+ var shadowReadThrottle = createDetachedThrottle({
13769
+ name: "shadow_read",
13770
+ defaultCooldownMs: DEFAULT_SHADOW_READ_COOLDOWN_MS,
13771
+ cooldownEnvKey: MEMORY_VNEXT_SHADOW_READ_COOLDOWN_ENV
13772
+ });
13773
+ var resolveShadowReadCooldownMs = (env) => shadowReadThrottle.resolveCooldownMs(env);
13774
+ var shadowReadThrottleKey = (owners) => owners.map(
13775
+ (owner) => resolveLegacyMemoryPrincipal({
13776
+ ownerType: owner.ownerType,
13777
+ ownerId: owner.ownerId
13778
+ }).principalId
13779
+ ).sort().join("");
12746
13780
  var normalizeTextKey = (text) => text.trim().replace(/\s+/g, " ").toLowerCase();
12747
13781
  var legacyItemKeys = (item) => {
12748
13782
  const keys = [normalizeTextKey(item.content ?? "")];
@@ -12779,14 +13813,35 @@ var withTimeout = async (promise, timeoutMs, label) => {
12779
13813
  };
12780
13814
  var runMemoryVNextShadowRead = async (input) => {
12781
13815
  const now = input.ctx.now ?? (() => performance.now());
12782
- const defaultEmit = (observation2) => {
13816
+ const defaultEmit = (observation) => {
12783
13817
  const payload = {
12784
13818
  event: "memory_vnext_shadow_read",
12785
- ...observation2
13819
+ ...observation
12786
13820
  };
12787
13821
  console.info("[memory] vnext shadow read", payload);
12788
13822
  };
12789
13823
  const emit = input.emit ?? defaultEmit;
13824
+ const throttle = shadowReadThrottle.tryAcquire(
13825
+ shadowReadThrottleKey(input.ctx.owners),
13826
+ now(),
13827
+ input.ctx.cooldownMs ?? resolveShadowReadCooldownMs()
13828
+ );
13829
+ if (throttle !== "run") {
13830
+ const skippedObservation = {
13831
+ legacyHitCount: input.legacyItems.length,
13832
+ vnextHitCount: 0,
13833
+ overlapCount: null,
13834
+ legacyOnlyCount: null,
13835
+ vnextOnlyCount: null,
13836
+ legacyLatencyMs: input.legacyLatencyMs,
13837
+ vnextLatencyMs: 0,
13838
+ legacyContextChars: input.legacyContextChars,
13839
+ vnextContextChars: 0,
13840
+ skipped: throttle === "busy" ? "skipped_busy" : "skipped_cooldown"
13841
+ };
13842
+ emit(skippedObservation);
13843
+ return skippedObservation;
13844
+ }
12790
13845
  const legacyKeys = new Set(
12791
13846
  input.legacyItems.flatMap((item) => legacyItemKeys(item))
12792
13847
  );
@@ -12823,31 +13878,35 @@ var runMemoryVNextShadowRead = async (input) => {
12823
13878
  } catch (error) {
12824
13879
  vnextError = shortError(error);
12825
13880
  }
12826
- const vnextLatencyMs = Math.round((now() - vnextStartedAt) * 10) / 10;
12827
- let overlapCount = null;
12828
- let legacyOnlyCount = null;
12829
- let vnextOnlyCount = null;
12830
- if (!vnextError) {
12831
- let overlap = 0;
12832
- for (const key of vnextKeys) if (legacyKeys.has(key)) overlap += 1;
12833
- overlapCount = overlap;
12834
- legacyOnlyCount = Math.max(0, legacyKeys.size - overlap);
12835
- vnextOnlyCount = Math.max(0, vnextKeys.size - overlap);
12836
- }
12837
- const observation = {
12838
- legacyHitCount: input.legacyItems.length,
12839
- vnextHitCount,
12840
- overlapCount,
12841
- legacyOnlyCount,
12842
- vnextOnlyCount,
12843
- legacyLatencyMs: input.legacyLatencyMs,
12844
- vnextLatencyMs,
12845
- legacyContextChars: input.legacyContextChars,
12846
- vnextContextChars: vnextChars,
12847
- ...vnextError ? { vnextError } : {}
12848
- };
12849
- emit(observation);
12850
- return observation;
13881
+ try {
13882
+ const vnextLatencyMs = Math.round((now() - vnextStartedAt) * 10) / 10;
13883
+ let overlapCount = null;
13884
+ let legacyOnlyCount = null;
13885
+ let vnextOnlyCount = null;
13886
+ if (!vnextError) {
13887
+ let overlap = 0;
13888
+ for (const key of vnextKeys) if (legacyKeys.has(key)) overlap += 1;
13889
+ overlapCount = overlap;
13890
+ legacyOnlyCount = Math.max(0, legacyKeys.size - overlap);
13891
+ vnextOnlyCount = Math.max(0, vnextKeys.size - overlap);
13892
+ }
13893
+ const observation = {
13894
+ legacyHitCount: input.legacyItems.length,
13895
+ vnextHitCount,
13896
+ overlapCount,
13897
+ legacyOnlyCount,
13898
+ vnextOnlyCount,
13899
+ legacyLatencyMs: input.legacyLatencyMs,
13900
+ vnextLatencyMs,
13901
+ legacyContextChars: input.legacyContextChars,
13902
+ vnextContextChars: vnextChars,
13903
+ ...vnextError ? { vnextError } : {}
13904
+ };
13905
+ emit(observation);
13906
+ return observation;
13907
+ } finally {
13908
+ shadowReadThrottle.release();
13909
+ }
12851
13910
  };
12852
13911
  var isMemoryVNextShadowReadEnabled = (env = typeof process !== "undefined" ? process.env : {}) => env.NOLO_MEMORY_VNEXT_SHADOW_READ === "1" || env.NOLO_MEMORY_VNEXT_SHADOW_READ === "true";
12853
13912
 
@@ -13507,6 +14566,31 @@ var shortError2 = (error) => {
13507
14566
  const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
13508
14567
  return message.length > ERROR_MESSAGE_MAX2 ? `${message.slice(0, ERROR_MESSAGE_MAX2)}\u2026` : message;
13509
14568
  };
14569
+ var DEFAULT_LAZY_PROMOTION_COOLDOWN_MS = DEFAULT_DETACHED_MEMORY_COOLDOWN_MS;
14570
+ var DEFAULT_LAZY_PROMOTION_TIMEOUT_MS = 2e4;
14571
+ var MEMORY_VNEXT_LAZY_PROMOTION_COOLDOWN_ENV = "NOLO_MEMORY_VNEXT_LAZY_PROMOTION_COOLDOWN_MS";
14572
+ var MEMORY_VNEXT_LAZY_PROMOTION_TIMEOUT_ENV = "NOLO_MEMORY_VNEXT_LAZY_PROMOTION_TIMEOUT_MS";
14573
+ var promotionThrottle = createDetachedThrottle({
14574
+ name: "lazy_promotion",
14575
+ defaultCooldownMs: DEFAULT_LAZY_PROMOTION_COOLDOWN_MS,
14576
+ cooldownEnvKey: MEMORY_VNEXT_LAZY_PROMOTION_COOLDOWN_ENV
14577
+ });
14578
+ var resolveLazyPromotionTimeoutMs = (env = typeof process !== "undefined" ? process.env : {}) => readMsEnv(
14579
+ env[MEMORY_VNEXT_LAZY_PROMOTION_TIMEOUT_ENV],
14580
+ DEFAULT_LAZY_PROMOTION_TIMEOUT_MS,
14581
+ false
14582
+ );
14583
+ var withTimeout2 = async (promise, timeoutMs, label) => {
14584
+ let timer;
14585
+ const timeout = new Promise((_, reject) => {
14586
+ timer = setTimeout(() => reject(new Error(label)), timeoutMs);
14587
+ });
14588
+ try {
14589
+ return await Promise.race([promise, timeout]);
14590
+ } finally {
14591
+ if (timer) clearTimeout(timer);
14592
+ }
14593
+ };
13510
14594
  var loadExistingContext = async (db, ownerId) => {
13511
14595
  const { entities, states } = await loadMemoryVNextCatalog(db, ownerId);
13512
14596
  return { entityIds: entities.map((entity) => entity.id), states };
@@ -13610,6 +14694,17 @@ var runMemoryVNextLazyPromotion = async (input) => {
13610
14694
  if (inFlight.has(flightKey)) {
13611
14695
  return finish({ status: "in_flight" });
13612
14696
  }
14697
+ const throttle = promotionThrottle.tryAcquire(
14698
+ deterministicEvidence.ownerId,
14699
+ clock(),
14700
+ input.cooldownMs
14701
+ );
14702
+ if (throttle === "busy") {
14703
+ return finish({ status: "skipped_busy" });
14704
+ }
14705
+ if (throttle === "cooldown") {
14706
+ return finish({ status: "skipped_cooldown" });
14707
+ }
13613
14708
  inFlight.add(flightKey);
13614
14709
  try {
13615
14710
  const evidenceResult = await applyLegacyMemoryEvidence(input.db, input.item);
@@ -13625,14 +14720,19 @@ var runMemoryVNextLazyPromotion = async (input) => {
13625
14720
  if (alreadyCovered) {
13626
14721
  return finish({ status: "already_covered" });
13627
14722
  }
13628
- const interpreted = await runLegacyMemoryMigrationShadow({
13629
- item: input.item,
13630
- provider: input.provider,
13631
- existing,
13632
- ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs },
13633
- ...input.now === void 0 ? {} : { now: input.now },
13634
- ...input.nextId ? { nextId: input.nextId } : {}
13635
- });
14723
+ const timeoutMs = input.timeoutMs ?? resolveLazyPromotionTimeoutMs();
14724
+ const interpreted = await withTimeout2(
14725
+ runLegacyMemoryMigrationShadow({
14726
+ item: input.item,
14727
+ provider: input.provider,
14728
+ existing,
14729
+ timeoutMs,
14730
+ ...input.now === void 0 ? {} : { now: input.now },
14731
+ ...input.nextId ? { nextId: input.nextId } : {}
14732
+ }),
14733
+ timeoutMs,
14734
+ `memory vnext lazy promotion interpreter timed out after ${timeoutMs}ms`
14735
+ );
13636
14736
  const semanticMutation = withoutImportedEvidence(interpreted.mutation, evidence.id);
13637
14737
  if (!hasWrites(semanticMutation)) {
13638
14738
  recordNoOpSuppression(
@@ -13648,6 +14748,7 @@ var runMemoryVNextLazyPromotion = async (input) => {
13648
14748
  return finish({ status: "error", error: shortError2(error) });
13649
14749
  } finally {
13650
14750
  inFlight.delete(flightKey);
14751
+ promotionThrottle.release();
13651
14752
  }
13652
14753
  };
13653
14754
  var isMemoryVNextLazyPromotionEnabled = (env = typeof process !== "undefined" ? process.env : {}) => env.NOLO_MEMORY_VNEXT_LAZY_PROMOTION === "1" || env.NOLO_MEMORY_VNEXT_LAZY_PROMOTION === "true";
@@ -13733,9 +14834,9 @@ async function resolvePureVNextRuntime(input) {
13733
14834
  });
13734
14835
  const entityById = new Map(catalog.entities.map((e) => [e.id, e]));
13735
14836
  for (const hit of hits) {
13736
- const stateKey2 = `${hit.state.ownerId}\0${hit.state.id}`;
13737
- if (seenStateKeys.has(stateKey2)) continue;
13738
- seenStateKeys.add(stateKey2);
14837
+ const stateKey = `${hit.state.ownerId}\0${hit.state.id}`;
14838
+ if (seenStateKeys.has(stateKey)) continue;
14839
+ seenStateKeys.add(stateKey);
13739
14840
  selectedItems.push(
13740
14841
  buildSynthesizedStateItem(hit.state, entityById.get(hit.state.entityId), owner.ownerType, owner.ownerId)
13741
14842
  );
@@ -14134,8 +15235,9 @@ function fingerprintFor(kind, detail) {
14134
15235
  function sanitizeFp(s) {
14135
15236
  return s.replace(/\s+/g, " ").slice(0, 80);
14136
15237
  }
14137
- var queryRemoteMemory = async (serverUrl, authToken, agentKey, userInput, spaceId) => {
15238
+ var queryRemoteMemory = async (serverUrl, authToken, agentKey, userInput, spaceId, signal) => {
14138
15239
  try {
15240
+ if (signal?.aborted) throw signal.reason ?? new DOMException("Aborted", "AbortError");
14139
15241
  const response = await fetch(`${serverUrl}/api/memory/query`, {
14140
15242
  method: "POST",
14141
15243
  headers: {
@@ -14147,7 +15249,7 @@ var queryRemoteMemory = async (serverUrl, authToken, agentKey, userInput, spaceI
14147
15249
  userInput,
14148
15250
  ...spaceId ? { spaceId } : {}
14149
15251
  }),
14150
- signal: AbortSignal.timeout(5e3)
15252
+ signal: signal ? AbortSignal.any([signal, AbortSignal.timeout(5e3)]) : AbortSignal.timeout(5e3)
14151
15253
  });
14152
15254
  if (!response.ok) {
14153
15255
  logDeduped(
@@ -14161,6 +15263,7 @@ var queryRemoteMemory = async (serverUrl, authToken, agentKey, userInput, spaceI
14161
15263
  const block = typeof payload?.promptBlock === "string" ? payload.promptBlock.trim() : "";
14162
15264
  return block || null;
14163
15265
  } catch (error) {
15266
+ if (signal?.aborted) throw error;
14164
15267
  logDeduped(
14165
15268
  "info",
14166
15269
  fingerprintFor("remote-failed", error instanceof Error ? error.name : void 0),
@@ -14184,17 +15287,21 @@ var queryLocalMemory = async (env, agentKey, userInput, spaceId) => {
14184
15287
  return resolution.promptBlock;
14185
15288
  };
14186
15289
  var resolveCliMemory = async (input) => {
15290
+ if (input.signal?.aborted) throw input.signal.reason ?? new DOMException("Aborted", "AbortError");
14187
15291
  if (input.authToken && input.serverUrl) {
14188
15292
  const remoteBlock = await queryRemoteMemory(
14189
15293
  input.serverUrl,
14190
15294
  input.authToken,
14191
15295
  input.agentKey,
14192
15296
  input.userInput,
14193
- input.spaceId
15297
+ input.spaceId,
15298
+ input.signal
14194
15299
  );
14195
15300
  if (remoteBlock) return remoteBlock;
14196
15301
  }
15302
+ if (input.signal?.aborted) throw input.signal.reason ?? new DOMException("Aborted", "AbortError");
14197
15303
  try {
15304
+ if (input.signal?.aborted) throw input.signal.reason ?? new DOMException("Aborted", "AbortError");
14198
15305
  return await queryLocalMemory(
14199
15306
  input.env,
14200
15307
  input.agentKey,
@@ -14202,6 +15309,7 @@ var resolveCliMemory = async (input) => {
14202
15309
  input.spaceId
14203
15310
  );
14204
15311
  } catch (error) {
15312
+ if (input.signal?.aborted) throw error;
14205
15313
  logDeduped(
14206
15314
  "warn",
14207
15315
  fingerprintFor("local-failed", error instanceof Error ? error.name : void 0),
@@ -14231,13 +15339,6 @@ function resolveRunOutcome(input) {
14231
15339
  }
14232
15340
  }
14233
15341
  }
14234
- var FAILED_EMPTY_ASSISTANT_REASONS = /* @__PURE__ */ new Set([
14235
- "length_truncated",
14236
- "stream_truncated",
14237
- "repetition_loop",
14238
- "stagnant_tool_calls"
14239
- ]);
14240
- var isRunResultStalledOrTruncated = (result) => !result.emptyAssistantOutputUsable && FAILED_EMPTY_ASSISTANT_REASONS.has(result.emptyAssistantFallbackReason ?? "");
14241
15342
  var resolveRunSettlementNote = (result) => {
14242
15343
  const reason = result.emptyAssistantFallbackReason;
14243
15344
  if (!reason || !FAILED_EMPTY_ASSISTANT_REASONS.has(reason)) return {};
@@ -14260,6 +15361,18 @@ async function resolveAgentRunAgentKey(args) {
14260
15361
  });
14261
15362
  return resolved?.agentKey;
14262
15363
  }
15364
+ var MACHINE_SHELL_REQUESTED_POLICY = { runtimeTools: ["execShell"] };
15365
+ async function resolveAgentBoundMachineIdFromRecord(args) {
15366
+ const db = await getReadableCliDb(args.output);
15367
+ const record = await resolveAgentRecordFromHybridStore({
15368
+ agentInput: args.agentKey,
15369
+ cliArgs: args.cliArgs,
15370
+ env: args.env,
15371
+ db,
15372
+ fetchImpl: fetch
15373
+ }).catch(() => null);
15374
+ return resolveBoundMachineId(record) || void 0;
15375
+ }
14263
15376
  async function runAgentRunCommand(args, deps) {
14264
15377
  const env = deps.env ?? process.env;
14265
15378
  const output = deps.output ?? {
@@ -14270,7 +15383,14 @@ async function runAgentRunCommand(args, deps) {
14270
15383
  writeUsage(output, deps.commandPath);
14271
15384
  return 0;
14272
15385
  }
14273
- const parsed = parseAgentRunArgs(args, { commandPath: deps.commandPath });
15386
+ let parsed;
15387
+ try {
15388
+ parsed = parseAgentRunArgs(args, { commandPath: deps.commandPath });
15389
+ } catch (error) {
15390
+ output.write(`[nolo] ${toErrorMessage(error)}
15391
+ `);
15392
+ return 1;
15393
+ }
14274
15394
  if (!parsed) {
14275
15395
  writeUsage(output, deps.commandPath);
14276
15396
  return 1;
@@ -14307,7 +15427,19 @@ async function runAgentRunCommand(args, deps) {
14307
15427
  const watchdogFailure = armStallWatchdog || armTimeoutWatchdog ? new Promise((_, reject) => {
14308
15428
  rejectOnWatchdogFailure = reject;
14309
15429
  }) : void 0;
14310
- const raceWithWatchdog = (work) => watchdogFailure ? Promise.race([work, watchdogFailure]) : work;
15430
+ const terminalStatus = createOneShotTerminalStatus(
15431
+ parsed.eventsMode || parsed.background || hasRegistry ? null : deps.output ? deps.output : {
15432
+ write: (chunk) => process.stdout.write(chunk),
15433
+ isTTY: process.stdout.isTTY === true
15434
+ }
15435
+ );
15436
+ const raceWithWatchdog = (work) => {
15437
+ const raced = watchdogFailure ? Promise.race([work, watchdogFailure]) : work;
15438
+ return raced.catch((error) => {
15439
+ terminalStatus.fail();
15440
+ throw error;
15441
+ });
15442
+ };
14311
15443
  const exitFromWatchdog = (code) => {
14312
15444
  try {
14313
15445
  processExit(code);
@@ -14352,6 +15484,7 @@ async function runAgentRunCommand(args, deps) {
14352
15484
  const note = `stalled: no progress for ${stallTimeoutMs}ms`;
14353
15485
  output.write(`[nolo] local run ${note}
14354
15486
  `);
15487
+ terminalStatus.fail();
14355
15488
  const outcome = resolveRunOutcome({ kind: "stall" });
14356
15489
  const currentActivity = activityTracker?.getActivity();
14357
15490
  await finalizeWatchdogOutcome(outcome, note, {
@@ -14370,6 +15503,7 @@ async function runAgentRunCommand(args, deps) {
14370
15503
  const note = `timed out after ${parsed.timeoutMs}ms`;
14371
15504
  output.write(`[nolo] local run ${note}
14372
15505
  `);
15506
+ terminalStatus.fail();
14373
15507
  const outcome = resolveRunOutcome({ kind: "timeout" });
14374
15508
  await finalizeWatchdogOutcome(outcome, note);
14375
15509
  rejectOnWatchdogFailure?.(new Error(`[nolo] local run ${note}`));
@@ -14380,7 +15514,16 @@ async function runAgentRunCommand(args, deps) {
14380
15514
  const rawAgentInput = resolveRawAgentInput(args, deps.commandPath) ?? parsed.agentKey;
14381
15515
  const fullstackLocal = isFullstackCodingAgentRef(rawAgentInput, parsed.agentKey);
14382
15516
  const explicitLocalCli = isLocalCliAgentKey(parsed.agentKey);
14383
- const isLocalRun = parsed.runtimeMode === "local" || !parsed.runtimeMode && (fullstackLocal || explicitLocalCli || args.includes("--dangerously-allow-shell"));
15517
+ const dockerRuntimeLocal = typeof parsed.runtimeKey === "string" && /^docker(:.+)?$/.test(parsed.runtimeKey.trim());
15518
+ const instaboxRuntimeLocal = typeof parsed.runtimeKey === "string" && parsed.runtimeKey.trim() === "instabox";
15519
+ const hostRuntimeLocal = typeof parsed.runtimeKey === "string" && parsed.runtimeKey.trim() === "local";
15520
+ if (hostRuntimeLocal && !args.includes("--allow-host-writes")) {
15521
+ output.write(
15522
+ "[nolo] runtimeKey=local \u4F1A\u5728**\u5BBF\u4E3B\u6587\u4EF6\u7CFB\u7EDF**\u4E0A\u6267\u884C\u5E76\u5199\u5165\uFF0C\u5FC5\u987B\u663E\u5F0F\u52A0 --allow-host-writes \u786E\u8BA4\uFF1B\u8981\u9694\u79BB\u6267\u884C\u8BF7\u7701\u7565 --runtime-key\uFF08\u9ED8\u8BA4\u8FDB docker \u6C99\u76D2\uFF09\u3002\n"
15523
+ );
15524
+ return 1;
15525
+ }
15526
+ const isLocalRun = (dockerRuntimeLocal || instaboxRuntimeLocal || hostRuntimeLocal || !parsed.runtimeKey) && (parsed.runtimeMode === "local" || hostRuntimeLocal || !parsed.runtimeMode && (fullstackLocal || explicitLocalCli || args.includes("--dangerously-allow-shell")));
14384
15527
  if (wantsFallbackSuggestions && !isLocalRun) {
14385
15528
  output.write("[nolo] --fallback-agent (suggestions) is only supported for local CLI runs (use --local)\n");
14386
15529
  return 1;
@@ -14391,13 +15534,47 @@ async function runAgentRunCommand(args, deps) {
14391
15534
 
14392
15535
  [Quota fallback context for agent decision: If this execution for ${parsed.agentKey} hits subscription quota, YOU (the agent) must decide the next agent to use. Do not rely on automatic wrapper. Reason based on the specific task (complexity, length, domain), agent strengths, cost, previous attempt results. Suggested alternatives: ${parsed.fallbackAgentKeys.join(", ")}. Update the task row with attempt history and dispatch the chosen next (via startAgentRun \u5F02\u6B65\u6D3E\u53D1)).]`;
14393
15536
  }
14394
- const resolvedAgentKey = parsed.runtimeMode !== "local" ? await (deps.resolveAgentRunAgentKey ?? resolveAgentRunAgentKey)({
15537
+ const resolvedAgentKey = parsed.runtimeMode !== "local" && !hostRuntimeLocal ? await (deps.resolveAgentRunAgentKey ?? resolveAgentRunAgentKey)({
14395
15538
  agentInput: resolveRawAgentInput(args, deps.commandPath) ?? parsed.agentKey,
14396
15539
  cliArgs: args,
14397
15540
  env,
14398
15541
  output
14399
15542
  }).catch(() => void 0) : void 0;
14400
15543
  const agentKey = resolvedAgentKey ?? parsed.agentKey;
15544
+ let machineShellOverride;
15545
+ if (parsed.machineShell) {
15546
+ const envRuntimeMode = env.NOLO_RUNTIME_MODE;
15547
+ const requestedRuntimeMode = parsed.runtimeMode ? parsed.runtimeMode : envRuntimeMode === "local" || envRuntimeMode === "server" || envRuntimeMode === "auto" ? envRuntimeMode : void 0;
15548
+ if (requestedRuntimeMode === "local") {
15549
+ output.write(MACHINE_SHELL_LOCAL_REFUSAL_MESSAGE);
15550
+ return 1;
15551
+ }
15552
+ const machineId = await (deps.resolveAgentBoundMachineId ?? resolveAgentBoundMachineIdFromRecord)({
15553
+ agentKey,
15554
+ cliArgs: args,
15555
+ env,
15556
+ output
15557
+ }).catch(() => void 0);
15558
+ if (!machineId) {
15559
+ output.write(
15560
+ `[nolo] --machine-shell requires ${agentKey} to be bound to a machine (runtimeBinding.machineId); none found.
15561
+ [nolo] bind it with \`nolo agent bind-current ${agentKey}\` on the target computer, then retry.
15562
+ `
15563
+ );
15564
+ return 1;
15565
+ }
15566
+ machineShellOverride = normalizeRuntimeToolPolicyOverride(
15567
+ MACHINE_SHELL_REQUESTED_POLICY
15568
+ );
15569
+ const baselinePolicy = resolveEffectiveRuntimeToolPolicy({
15570
+ agentConfig: { runtimeToolPolicy: machineShellOverride },
15571
+ host: "web"
15572
+ });
15573
+ output.write(
15574
+ `[nolo] machine-shell: dispatch=server(required) machine=${machineId} runtimeTools=${(machineShellOverride?.runtimeTools ?? []).join(",") || "-"} sandbox=${baselinePolicy?.isolation?.mode ?? "-"} approval=${baselinePolicy?.shell?.commandPolicy ?? "-"} networkPolicy=${baselinePolicy?.shell?.networkPolicy ?? "-"} policySource=web-runtime-safety-baseline
15575
+ `
15576
+ );
15577
+ }
14401
15578
  let effectiveAgentKey = agentKey;
14402
15579
  let modelOverride = null;
14403
15580
  const autoRouteRequested = deps.commandPath?.join(" ") === "chat" && !parsed.continueDialogId && (args.includes("--auto-route") || env.NOLO_AUTO_ROUTE === "1") && env.NOLO_AUTO_ROUTE !== "0";
@@ -14415,13 +15592,12 @@ async function runAgentRunCommand(args, deps) {
14415
15592
  }
14416
15593
  if (hasExplicitAgent && !modelOverride) {
14417
15594
  output.write(
14418
- "[nolo] auto-route: \u8986\u76D6\u6E90 agent \u8BFB\u53D6\u5931\u8D25\uFF0C\u6309\u539F\u6837\u76F4\u8DD1\u6240\u9009 agent\u3002\n"
15595
+ t("agentRun.autoRouteOverrideFailed")
14419
15596
  );
14420
15597
  } else {
14421
15598
  effectiveAgentKey = CLI_AUTO_ROUTE_AGENT_KEY;
14422
15599
  if (modelOverride) {
14423
- output.write(`[nolo] auto-route: model \u5C42\u8986\u76D6\u4E3A ${agentKey}
14424
- `);
15600
+ output.write(t("agentRun.autoRouteModelOverride", agentKey));
14425
15601
  }
14426
15602
  }
14427
15603
  }
@@ -14477,7 +15653,7 @@ async function runAgentRunCommand(args, deps) {
14477
15653
  }
14478
15654
  }
14479
15655
  let localRuntimeCwd = parsed.cwd;
14480
- if (!localRuntimeCwd && parsed.runtimeMode === "local") {
15656
+ if (!localRuntimeCwd && (parsed.runtimeMode === "local" || hostRuntimeLocal)) {
14481
15657
  localRuntimeCwd = process.cwd();
14482
15658
  }
14483
15659
  const runEnv = buildLocalRunEnv({
@@ -14504,7 +15680,8 @@ async function runAgentRunCommand(args, deps) {
14504
15680
  spawn: deps.spawn,
14505
15681
  fs: deps.fs,
14506
15682
  now: deps.now,
14507
- generateRunId: deps.generateRunId
15683
+ generateRunId: deps.generateRunId,
15684
+ shellApprovalHost: deps.shellApprovalHost
14508
15685
  }
14509
15686
  );
14510
15687
  output.write(`[nolo] runId=${runId}
@@ -14533,6 +15710,7 @@ async function runAgentRunCommand(args, deps) {
14533
15710
  if (agentsMdLayer) scopedLayers.push(agentsMdLayer);
14534
15711
  skillContentBlocks.push(...buildSkillContextBlocks(skillReferences));
14535
15712
  scopedLayers.push(buildSkillDiscoveryContextLayer(cliCwd));
15713
+ scopedLayers.push(buildHostEnvironmentLayer());
14536
15714
  if (!deps.memoryRecallDisabled) {
14537
15715
  try {
14538
15716
  memoryPromptBlock = await resolveCliMemory({
@@ -14561,6 +15739,14 @@ async function runAgentRunCommand(args, deps) {
14561
15739
  );
14562
15740
  extraContextBlocks.push(...contextBlockScopes.map((block) => block.content));
14563
15741
  }
15742
+ const runRecordParentDialogId = !parsed.parentDialogId && typeof childRunId === "string" && childRunId.length > 0 ? asOptionalTrimmedString(
15743
+ (deps.readRunRecord ?? readRunRecord)(childRunId, {
15744
+ env,
15745
+ homedir: deps.homedir,
15746
+ fs: deps.fs
15747
+ })?.parentDialogId
15748
+ ) : void 0;
15749
+ const effectiveParentDialogId = parsed.parentDialogId ?? runRecordParentDialogId;
14564
15750
  const formatTurnMessage = (msg) => prependWorkflowReferencePrompt(
14565
15751
  prependSubjectDialogMarker(
14566
15752
  prependFeatureWorktreeInstruction(
@@ -14571,239 +15757,263 @@ async function runAgentRunCommand(args, deps) {
14571
15757
  ),
14572
15758
  workflowReference
14573
15759
  );
14574
- const buildRunOptions = (targetAgentKey, turnMessage = effectiveMessage) => ({
14575
- agentName: targetAgentKey,
14576
- agentKey: targetAgentKey,
14577
- serverUrl: resolveServerUrl(env),
14578
- message: formatTurnMessage(turnMessage),
14579
- imageUrls: parsed.imageUrls.map(normalizeCliImageInput),
14580
- scriptDir: deps.scriptDir,
14581
- env: runEnv,
14582
- output,
14583
- ...deps.localRuntimeAdapterFactory ? { localRuntimeAdapterFactory: deps.localRuntimeAdapterFactory } : {},
14584
- ...localRuntimeCwd ? { localRuntimeCwd } : {},
14585
- ...parsed.runtimeMode ? { runtimeMode: parsed.runtimeMode } : {},
14586
- ...parsed.continueDialogId ? { continueDialogId: parsed.continueDialogId } : {},
14587
- ...parsed.spaceId ? { spaceId: parsed.spaceId } : {},
14588
- ...parsed.category ? { category: parsed.category } : {},
14589
- ...parsed.inheritedFromDialogKey ? { inheritedFromDialogKey: parsed.inheritedFromDialogKey } : {},
14590
- ...parsed.parentDialogId ? { parentDialogId: parsed.parentDialogId } : {},
14591
- ...parsed.parentWakeOnTerminal ? { parentWakeOnTerminal: true } : {},
14592
- ...parsed.subjectDialogKey ? { subjectDialogKey: parsed.subjectDialogKey } : {},
14593
- ...parsed.subjectRefs?.length ? { subjectRefs: parsed.subjectRefs } : {},
14594
- ...skillAllowedToolOverride !== void 0 ? { allowedToolNames: skillAllowedToolOverride } : parsed.allowedToolNames?.length ? { allowedToolNames: parsed.allowedToolNames } : {},
14595
- ...parsed.blockedToolNames?.length ? { blockedToolNames: parsed.blockedToolNames } : {},
14596
- ...activityTracker ? { onLoopEvent: activityTracker.onLoopEvent } : {},
14597
- background: parsed.background,
14598
- noStream: parsed.noStream,
14599
- ephemeral: parsed.ephemeral,
14600
- ...typeof parsed.timeoutMs === "number" ? { timeoutMs: parsed.timeoutMs } : {},
14601
- traceTools: parsed.traceTools,
14602
- ...parsed.eventsMode ? { eventsMode: parsed.eventsMode } : {},
14603
- ...parsed.taskEvidence ? { taskEvidence: parsed.taskEvidence } : {},
14604
- ...contextBlockScopes.length > 0 ? { contextBlockScopes } : extraContextBlocks.length > 0 ? { extraContextBlocks } : {}
14605
- });
14606
- let result = await raceWithWatchdog(
14607
- runner({
14608
- ...buildRunOptions(effectiveAgentKey),
14609
- ...modelOverride ? { modelOverride } : {}
14610
- })
14611
- );
14612
- clearWatchdogs();
14613
- let runCreditsTotal = result.turnCredits;
14614
- if (result.exitCode !== 0 && isQuotaExhaustedError(result.localError) && isLocalRun && parsed.fallbackAgentKeys && parsed.fallbackAgentKeys.length > 0) {
14615
- const fallbackAgentKey = parsed.fallbackAgentKeys[0];
14616
- output.write(
14617
- `[nolo] quota exhausted on ${agentKey}, falling back to ${fallbackAgentKey}
14618
- `
14619
- );
14620
- const fallbackResult = await raceWithWatchdog(
15760
+ const shellApprovalChild = process.connected && typeof process.send === "function" ? createShellApprovalChild(process) : void 0;
15761
+ try {
15762
+ const buildRunOptions = (targetAgentKey, turnMessage = effectiveMessage) => ({
15763
+ ...shellApprovalChild ? { execShellApproval: targetAgentKey === agentKey ? shellApprovalChild.authority : {
15764
+ request: async () => {
15765
+ throw new Error("Shell approval agent binding mismatch");
15766
+ },
15767
+ consume: () => {
15768
+ throw new Error("Shell approval agent binding mismatch");
15769
+ }
15770
+ } } : {},
15771
+ agentName: targetAgentKey,
15772
+ agentKey: targetAgentKey,
15773
+ serverUrl: resolveServerUrl(env),
15774
+ message: formatTurnMessage(turnMessage),
15775
+ imageUrls: parsed.imageUrls.map(normalizeCliImageInput),
15776
+ scriptDir: deps.scriptDir,
15777
+ env: runEnv,
15778
+ output,
15779
+ ...deps.localRuntimeAdapterFactory ? { localRuntimeAdapterFactory: deps.localRuntimeAdapterFactory } : {},
15780
+ ...localRuntimeCwd ? { localRuntimeCwd } : {},
15781
+ // `--machine-shell` 强制锁定 server 派发:绑定校验通过后 runtimeMode 一律为
15782
+ // "server"(+ requireRemoteDispatch 在派发层再兜一次),既不给 auto→local 早退
15783
+ // 留口子,也不受 NOLO_RUNTIME_MODE=local 覆盖(resolveRequestedRuntimeMode 以
15784
+ // options.runtimeMode 优先)。这是在唯一构造 runner 参数的入口做的,quota
15785
+ // fallback / 重试等复用 buildRunOptions 的路径同样被锁住。
15786
+ // 非 machine-shell 时保留本地通道判定:显式 runtimeMode 优先,其次
15787
+ // docker/host 本地目标在本地 run 上回落 runtimeMode=local。
15788
+ ...parsed.machineShell ? { runtimeMode: "server", requireRemoteDispatch: true } : parsed.runtimeMode ? { runtimeMode: parsed.runtimeMode } : (dockerRuntimeLocal || instaboxRuntimeLocal || hostRuntimeLocal) && isLocalRun ? { runtimeMode: "local" } : {},
15789
+ // runtimeKey 与 machine-shell 的组合已在 parseAgentRunArgs 入口显式拒绝,
15790
+ // 这里直接透传即可(不再静默丢弃参数)。
15791
+ ...parsed.runtimeKey ? { runtimeKey: parsed.runtimeKey } : {},
15792
+ ...parsed.continueDialogId ? { continueDialogId: parsed.continueDialogId } : {},
15793
+ ...parsed.strictContinueHistory ? { strictContinueHistory: true } : {},
15794
+ ...parsed.spaceId ? { spaceId: parsed.spaceId } : {},
15795
+ ...parsed.category ? { category: parsed.category } : {},
15796
+ ...parsed.inheritedFromDialogKey ? { inheritedFromDialogKey: parsed.inheritedFromDialogKey } : {},
15797
+ ...effectiveParentDialogId ? { parentDialogId: effectiveParentDialogId } : {},
15798
+ ...parsed.parentWakeOnTerminal ? { parentWakeOnTerminal: true } : {},
15799
+ ...parsed.subjectDialogKey ? { subjectDialogKey: parsed.subjectDialogKey } : {},
15800
+ ...parsed.subjectRefs?.length ? { subjectRefs: parsed.subjectRefs } : {},
15801
+ ...skillAllowedToolOverride !== void 0 ? { allowedToolNames: skillAllowedToolOverride } : parsed.allowedToolNames?.length ? { allowedToolNames: parsed.allowedToolNames } : {},
15802
+ ...parsed.blockedToolNames?.length ? { blockedToolNames: parsed.blockedToolNames } : {},
15803
+ ...machineShellOverride ? { runtimeToolPolicyOverride: machineShellOverride } : {},
15804
+ ...activityTracker ? { onLoopEvent: activityTracker.onLoopEvent } : {},
15805
+ background: parsed.background,
15806
+ noStream: parsed.noStream,
15807
+ ephemeral: parsed.ephemeral,
15808
+ ...typeof parsed.timeoutMs === "number" ? { timeoutMs: parsed.timeoutMs } : {},
15809
+ traceTools: parsed.traceTools,
15810
+ ...parsed.eventsMode ? { eventsMode: parsed.eventsMode } : {},
15811
+ ...parsed.taskEvidence ? { taskEvidence: parsed.taskEvidence } : {},
15812
+ ...contextBlockScopes.length > 0 ? { contextBlockScopes } : extraContextBlocks.length > 0 ? { extraContextBlocks } : {}
15813
+ });
15814
+ terminalStatus.working();
15815
+ let result = await raceWithWatchdog(
14621
15816
  runner({
14622
- ...buildRunOptions(fallbackAgentKey),
14623
- ...result.dialogId ? { continueDialogId: result.dialogId } : {}
15817
+ ...buildRunOptions(effectiveAgentKey),
15818
+ ...modelOverride ? { modelOverride } : {}
14624
15819
  })
14625
15820
  );
14626
15821
  clearWatchdogs();
14627
- if (fallbackResult.exitCode === 0) {
14628
- result = fallbackResult;
14629
- }
14630
- if (fallbackResult.turnCredits !== void 0) {
14631
- runCreditsTotal = (runCreditsTotal ?? 0) + fallbackResult.turnCredits;
14632
- }
14633
- if (fallbackResult.exitCode !== 0) {
14634
- result = {
14635
- ...fallbackResult,
14636
- ...fallbackResult.dialogId || result.dialogId ? { dialogId: fallbackResult.dialogId ?? result.dialogId } : {}
14637
- };
15822
+ let runCreditsTotal = result.turnCredits;
15823
+ if (result.exitCode !== 0 && isQuotaExhaustedError(result.localError) && isLocalRun && parsed.fallbackAgentKeys && parsed.fallbackAgentKeys.length > 0) {
15824
+ const fallbackAgentKey = parsed.fallbackAgentKeys[0];
14638
15825
  output.write(
14639
- `[nolo] fallback to ${fallbackAgentKey} also failed: ${fallbackResult.localError instanceof Error ? fallbackResult.localError.message : String(fallbackResult.localError ?? "unknown error")}
15826
+ `[nolo] quota exhausted on ${agentKey}, falling back to ${fallbackAgentKey}
14640
15827
  `
14641
15828
  );
14642
- }
14643
- } else if (result.localError instanceof CliProviderQuotaError) {
14644
- output.write(`
15829
+ const fallbackResult = await raceWithWatchdog(
15830
+ runner({
15831
+ ...buildRunOptions(fallbackAgentKey),
15832
+ ...result.dialogId ? { continueDialogId: result.dialogId } : {}
15833
+ })
15834
+ );
15835
+ clearWatchdogs();
15836
+ if (fallbackResult.exitCode === 0) {
15837
+ result = fallbackResult;
15838
+ }
15839
+ if (fallbackResult.turnCredits !== void 0) {
15840
+ runCreditsTotal = (runCreditsTotal ?? 0) + fallbackResult.turnCredits;
15841
+ }
15842
+ if (fallbackResult.exitCode !== 0) {
15843
+ result = {
15844
+ ...fallbackResult,
15845
+ ...fallbackResult.dialogId || result.dialogId ? { dialogId: fallbackResult.dialogId ?? result.dialogId } : {}
15846
+ };
15847
+ output.write(
15848
+ `[nolo] fallback to ${fallbackAgentKey} also failed: ${fallbackResult.localError instanceof Error ? fallbackResult.localError.message : String(fallbackResult.localError ?? "unknown error")}
15849
+ `
15850
+ );
15851
+ }
15852
+ } else if (result.localError instanceof CliProviderQuotaError) {
15853
+ output.write(`
14645
15854
  [nolo] Quota limit hit for ${parsed.agentKey} (CliProviderQuotaError).
14646
15855
  `);
14647
- if (parsed.fallbackAgentKeys && parsed.fallbackAgentKeys.length > 0) {
14648
- output.write(`Suggested alternatives for your decision: ${parsed.fallbackAgentKeys.join(", ")}
15856
+ if (parsed.fallbackAgentKeys && parsed.fallbackAgentKeys.length > 0) {
15857
+ output.write(`Suggested alternatives for your decision: ${parsed.fallbackAgentKeys.join(", ")}
14649
15858
  `);
14650
- }
14651
- output.write(`As the orchestrating agent, decide next based on task and re-dispatch (update task state with this attempt).
14652
- `);
14653
- }
14654
- const queueFilePath = parsed.queueFile ?? (childRunId ? resolveRunQueuePath(childRunId, env, deps.homedir) : void 0);
14655
- const queueFs = deps.fs ?? nodeFs;
14656
- if (queueFilePath && queueFs.existsSync(queueFilePath) && result.dialogId && result.exitCode === 0) {
14657
- const MAX_DRAIN_TURNS = 200;
14658
- let drainTurns = 0;
14659
- const popSingle = deps.popSingleQueueMessage ?? popSingleQueueMessage;
14660
- while (drainTurns < MAX_DRAIN_TURNS && queueFs.existsSync(queueFilePath)) {
14661
- const nextEntry = await popSingle(queueFilePath, deps);
14662
- if (!nextEntry) {
14663
- break;
14664
15859
  }
14665
- drainTurns += 1;
14666
- try {
14667
- const turnResult = await raceWithWatchdog(
14668
- runner({
14669
- ...buildRunOptions(effectiveAgentKey, nextEntry.text),
14670
- continueDialogId: result.dialogId,
14671
- ...modelOverride ? { modelOverride } : {}
14672
- })
14673
- );
14674
- clearWatchdogs();
14675
- result = turnResult;
14676
- if (turnResult.turnCredits !== void 0) {
14677
- runCreditsTotal = (runCreditsTotal ?? 0) + turnResult.turnCredits;
15860
+ output.write(`As the orchestrating agent, decide next based on task and re-dispatch (update task state with this attempt).
15861
+ `);
15862
+ }
15863
+ const queueFilePath = parsed.queueFile ?? (childRunId ? resolveRunQueuePath(childRunId, env, deps.homedir) : void 0);
15864
+ const queueFs = deps.fs ?? nodeFs;
15865
+ if (queueFilePath && queueFs.existsSync(queueFilePath) && result.dialogId && result.exitCode === 0) {
15866
+ const MAX_DRAIN_TURNS = 200;
15867
+ let drainTurns = 0;
15868
+ const popSingle = deps.popSingleQueueMessage ?? popSingleQueueMessage;
15869
+ while (drainTurns < MAX_DRAIN_TURNS && queueFs.existsSync(queueFilePath)) {
15870
+ const nextEntry = await popSingle(queueFilePath, deps);
15871
+ if (!nextEntry) {
15872
+ break;
14678
15873
  }
14679
- if (result.exitCode !== 0) {
15874
+ drainTurns += 1;
15875
+ try {
15876
+ const turnResult = await raceWithWatchdog(
15877
+ runner({
15878
+ ...buildRunOptions(effectiveAgentKey, nextEntry.text),
15879
+ continueDialogId: result.dialogId,
15880
+ ...modelOverride ? { modelOverride } : {}
15881
+ })
15882
+ );
15883
+ clearWatchdogs();
15884
+ result = turnResult;
15885
+ if (turnResult.turnCredits !== void 0) {
15886
+ runCreditsTotal = (runCreditsTotal ?? 0) + turnResult.turnCredits;
15887
+ }
15888
+ if (result.exitCode !== 0) {
15889
+ break;
15890
+ }
15891
+ } catch (drainError) {
15892
+ clearWatchdogs();
15893
+ console.error(`[nolo] queue turn failed with exception: ${toErrorMessage(drainError)}`);
15894
+ result = {
15895
+ ...result,
15896
+ exitCode: 1,
15897
+ localError: drainError
15898
+ };
14680
15899
  break;
14681
15900
  }
14682
- } catch (drainError) {
14683
- clearWatchdogs();
14684
- console.error(`[nolo] queue turn failed with exception: ${toErrorMessage(drainError)}`);
14685
- result = {
14686
- ...result,
14687
- exitCode: 1,
14688
- localError: drainError
14689
- };
14690
- break;
15901
+ }
15902
+ if (drainTurns >= MAX_DRAIN_TURNS) {
15903
+ console.error(
15904
+ `[nolo] Warning: queue drain loop reached defensive limit of ${MAX_DRAIN_TURNS} turns, stopping.`
15905
+ );
14691
15906
  }
14692
15907
  }
14693
- if (drainTurns >= MAX_DRAIN_TURNS) {
14694
- console.error(
14695
- `[nolo] Warning: queue drain loop reached defensive limit of ${MAX_DRAIN_TURNS} turns, stopping.`
14696
- );
14697
- }
14698
- }
14699
- if (result.dialogId) {
14700
- if (parsed.background) {
14701
- output.write(`
15908
+ terminalStatus.settle({
15909
+ exitCode: result.exitCode,
15910
+ streamInterrupted: result.streamInterrupted,
15911
+ stalledOrTruncated: isRunResultStalledOrTruncated(result)
15912
+ });
15913
+ if (result.dialogId) {
15914
+ if (parsed.background) {
15915
+ output.write(`
14702
15916
  [nolo] background dialog ${result.dialogId}
14703
15917
  `);
14704
- output.write(`[nolo] read: nolo dialog read ${result.dialogId}
15918
+ output.write(`[nolo] read: nolo dialog read ${result.dialogId}
14705
15919
  `);
14706
- } else {
14707
- output.write(`
15920
+ } else {
15921
+ output.write(`
14708
15922
  [nolo] dialog ${result.dialogId}
14709
15923
  `);
15924
+ }
14710
15925
  }
14711
- }
14712
- if (shouldPrintLocalRunSummary({ parsed, localRuntimeCwd })) {
14713
- try {
14714
- const inspect = deps.inspectLocalRunWorkspace ?? inspectLocalRunWorkspace;
14715
- const inspection = await inspect(localRuntimeCwd);
14716
- output.write(formatLocalRunSummary({
14717
- dialogId: result.dialogId,
14718
- inspection
14719
- }));
14720
- } catch (error) {
14721
- output.write(
14722
- `
15926
+ if (shouldPrintLocalRunSummary({ parsed, localRuntimeCwd })) {
15927
+ try {
15928
+ const inspect = deps.inspectLocalRunWorkspace ?? inspectLocalRunWorkspace;
15929
+ const inspection = await inspect(localRuntimeCwd);
15930
+ output.write(formatLocalRunSummary({
15931
+ dialogId: result.dialogId,
15932
+ inspection
15933
+ }));
15934
+ } catch (error) {
15935
+ output.write(
15936
+ `
14723
15937
  [nolo] local run summary unavailable: ${toErrorMessage(error)}
14724
15938
  `
14725
- );
14726
- }
14727
- }
14728
- if (typeof childRunId === "string" && childRunId.length > 0) {
14729
- const childRecordForDoD = (deps.readRunRecord ?? readRunRecord)(childRunId, {
14730
- env,
14731
- homedir: deps.homedir,
14732
- fs: deps.fs
14733
- });
14734
- const isStalledOrTruncated = isRunResultStalledOrTruncated(result);
14735
- const truncationNote = resolveRunSettlementNote(result);
14736
- const outcome = resolveRunOutcome({
14737
- kind: "result",
14738
- exitCode: result.exitCode,
14739
- isStalledOrTruncated
14740
- });
14741
- let dodResults;
14742
- try {
14743
- dodResults = (deps.runDoDCommands ?? runDoDCommands)(
14744
- childRecordForDoD?.dodCommands,
14745
- childRecordForDoD?.cwd
14746
- );
14747
- } catch (dodError) {
14748
- console.warn(`[nolo] DoD verification failed to run for ${childRunId}:`, dodError);
14749
- }
14750
- let failureReason;
14751
- let toolCallCount;
14752
- if (outcome.status === "failed") {
14753
- if (result.emptyAssistantFallbackReason === "repetition_loop" || result.emptyAssistantFallbackReason === "stagnant_tool_calls") {
14754
- failureReason = "stalled";
14755
- } else if (result.localError && isQuotaExhaustedError(result.localError)) {
14756
- failureReason = "provider_rate_limited";
14757
- } else if (result.localError) {
14758
- const errMsg = toErrorMessage(result.localError).toLowerCase();
14759
- if (errMsg.includes("config_unresolved") || errMsg.includes("unresolved config")) {
14760
- failureReason = "config_unresolved";
14761
- } else {
14762
- failureReason = "provider_error";
14763
- }
14764
- }
14765
- const currentActivity = activityTracker?.getActivity();
14766
- const rawToolCount = currentActivity?.counters?.toolCalls ?? childRecordForDoD?.activity?.counters?.toolCalls;
14767
- if (typeof rawToolCount === "number" && rawToolCount > 0) {
14768
- toolCallCount = rawToolCount;
15939
+ );
14769
15940
  }
14770
15941
  }
14771
- await settleRunTerminalAuthoritatively(
14772
- childRunId,
14773
- {
14774
- status: outcome.status,
14775
- exitCode: outcome.exitCode,
14776
- dialogId: result.dialogId,
14777
- ...dodResults ? { dodResults } : {},
14778
- // run 级累计的平台积分(主轮 + fallback + drain 轮):dock 行据此显示
14779
- // 「⚡ x.xx」,让派发任务的消耗可见。undefined = 全程无平台计费。
14780
- ...runCreditsTotal !== void 0 ? { credits: runCreditsTotal } : {},
14781
- ...failureReason ? { failureReason } : {},
14782
- ...toolCallCount !== void 0 ? { toolCallCount } : {},
14783
- ...truncationNote
14784
- },
14785
- {
15942
+ if (typeof childRunId === "string" && childRunId.length > 0) {
15943
+ const childRecordForDoD = (deps.readRunRecord ?? readRunRecord)(childRunId, {
14786
15944
  env,
14787
15945
  homedir: deps.homedir,
14788
- fs: deps.fs,
14789
- now: deps.now,
14790
- sleep: deps.sleep
14791
- },
14792
- deps.transitionRunToTerminal
14793
- );
15946
+ fs: deps.fs
15947
+ });
15948
+ const isStalledOrTruncated = isRunResultStalledOrTruncated(result);
15949
+ const truncationNote = resolveRunSettlementNote(result);
15950
+ const outcome = resolveRunOutcome({
15951
+ kind: "result",
15952
+ exitCode: result.exitCode,
15953
+ isStalledOrTruncated
15954
+ });
15955
+ let dodResults;
15956
+ try {
15957
+ dodResults = (deps.runDoDCommands ?? runDoDCommands)(
15958
+ childRecordForDoD?.dodCommands,
15959
+ childRecordForDoD?.cwd
15960
+ );
15961
+ } catch (dodError) {
15962
+ console.warn(`[nolo] DoD verification failed to run for ${childRunId}:`, dodError);
15963
+ }
15964
+ let failureReason;
15965
+ let toolCallCount;
15966
+ if (outcome.status === "failed") {
15967
+ if (result.emptyAssistantFallbackReason === "repetition_loop" || result.emptyAssistantFallbackReason === "stagnant_tool_calls") {
15968
+ failureReason = "stalled";
15969
+ } else if (result.localError && isQuotaExhaustedError(result.localError)) {
15970
+ failureReason = "provider_rate_limited";
15971
+ } else if (result.localError) {
15972
+ const errMsg = toErrorMessage(result.localError).toLowerCase();
15973
+ if (errMsg.includes("config_unresolved") || errMsg.includes("unresolved config")) {
15974
+ failureReason = "config_unresolved";
15975
+ } else {
15976
+ failureReason = "provider_error";
15977
+ }
15978
+ }
15979
+ const currentActivity = activityTracker?.getActivity();
15980
+ const rawToolCount = currentActivity?.counters?.toolCalls ?? childRecordForDoD?.activity?.counters?.toolCalls;
15981
+ if (typeof rawToolCount === "number" && rawToolCount > 0) {
15982
+ toolCallCount = rawToolCount;
15983
+ }
15984
+ }
15985
+ await settleRunTerminalAuthoritatively(
15986
+ childRunId,
15987
+ {
15988
+ status: outcome.status,
15989
+ exitCode: outcome.exitCode,
15990
+ dialogId: result.dialogId,
15991
+ ...dodResults ? { dodResults } : {},
15992
+ // run 级累计的平台积分(主轮 + fallback + drain 轮):dock 行据此显示
15993
+ // 「⚡ x.xx」,让派发任务的消耗可见。undefined = 全程无平台计费。
15994
+ ...runCreditsTotal !== void 0 ? { credits: runCreditsTotal } : {},
15995
+ ...failureReason ? { failureReason } : {},
15996
+ ...toolCallCount !== void 0 ? { toolCallCount } : {},
15997
+ ...result.finalText ? { lastAssistantText: result.finalText } : {},
15998
+ // 仅用于 .result.md 头(front matter):旁路读取,不改 result 形状。
15999
+ ...getRunResultHeaderMeta(result),
16000
+ ...truncationNote
16001
+ },
16002
+ {
16003
+ env,
16004
+ homedir: deps.homedir,
16005
+ fs: deps.fs,
16006
+ now: deps.now,
16007
+ sleep: deps.sleep
16008
+ },
16009
+ deps.transitionRunToTerminal
16010
+ );
16011
+ }
16012
+ return result.exitCode;
16013
+ } finally {
16014
+ shellApprovalChild?.close();
16015
+ if (shellApprovalChild && process.connected) process.disconnect();
14794
16016
  }
14795
- return result.exitCode;
14796
- }
14797
- var BALANCE_ERROR_PATTERNS = [
14798
- /UPSTREAM_402/i,
14799
- /Insufficient Balance/i,
14800
- /insufficient\s+balance/i,
14801
- /余额不足/
14802
- ];
14803
- function isBalanceExhaustedError(error) {
14804
- if (!error) return false;
14805
- const message = error instanceof Error ? error.message : typeof error === "string" ? error : String(error?.message ?? "");
14806
- return BALANCE_ERROR_PATTERNS.some((pattern) => pattern.test(message));
14807
16017
  }
14808
16018
 
14809
16019
  export {
@@ -14839,6 +16049,7 @@ export {
14839
16049
  applyDetectedBackground,
14840
16050
  renderSurfaceLine,
14841
16051
  surfaceBackgroundSequence,
16052
+ composerSurfaceBackgroundSequence,
14842
16053
  userSurfaceBackgroundSequence,
14843
16054
  themeText,
14844
16055
  tuiRenderThemeFingerprint,
@@ -14846,12 +16057,16 @@ export {
14846
16057
  polishBreathInsertsBlankBetween,
14847
16058
  formatAssistantDisplay,
14848
16059
  redactSecrets,
16060
+ safeAskText,
14849
16061
  TUI_TREE_MARKER,
16062
+ estimateMessagesTokens,
16063
+ historyTokensBeforeLatestAssistant,
14850
16064
  resolveAgentModelIdentity,
14851
16065
  resolveAgentContextWindow,
14852
16066
  platformCreditsFromUsage,
14853
16067
  formatCreditsChip,
14854
- formatTokenCount,
16068
+ resolveAuthorityTurnCount,
16069
+ computeBaselineContextTokens,
14855
16070
  renderTokenStatus,
14856
16071
  COLLAPSED_PASTE_PLACEHOLDER_RE,
14857
16072
  shouldCollapsePaste,
@@ -14863,18 +16078,22 @@ export {
14863
16078
  releaseCollapsedPasteReferences,
14864
16079
  expandRangeToCollapsedPasteChips,
14865
16080
  findCollapsedPasteSpanAt,
16081
+ emitTerminalProgramStatus,
16082
+ isBalanceExhaustedError,
14866
16083
  runAgentTurn,
14867
16084
  resolveWorkflowReference,
14868
16085
  resolveSkillReference,
14869
16086
  buildSkillContextBlocks,
14870
16087
  prependSubjectDialogMarker,
14871
16088
  normalizeCliImageInput,
16089
+ buildHostEnvironmentLayer,
14872
16090
  readAgentsMdLayerFromDisk,
14873
16091
  resolveCliMemory,
16092
+ FAILED_EMPTY_ASSISTANT_REASONS,
16093
+ isRunResultStalledOrTruncated,
16094
+ resolveTerminalProgramStatusState,
14874
16095
  inspectLocalRunWorkspace,
14875
16096
  resolveRunOutcome,
14876
- isRunResultStalledOrTruncated,
14877
16097
  resolveRunSettlementNote,
14878
- runAgentRunCommand,
14879
- isBalanceExhaustedError
16098
+ runAgentRunCommand
14880
16099
  };