nolo-cli 0.148.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-NFJAMAGJ.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-4KW33JII.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-CMQR4RQ4.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-OZ33K224.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-523WHFSL.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-P4BX6FFU.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-BKWMNZ2X.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-T7F46O36.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-YUWMM4US.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-LPVCRQMM.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-FWQEKRTD.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-DIXLJWCD.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-T767MPHB.js → chunk-SMENBO3M.js} +354 -120
  123. package/{chunk-PCVVZ2MH.js → chunk-SSFDFOVT.js} +26 -31
  124. package/chunk-SW4S4XYB.js +1794 -0
  125. package/{chunk-HUFPWXFW.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-2JMMBU6V.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-DCFPQW22.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-YOEQUA7T.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-5EJL6ROU.js → createAgentAutomationAction-QOPOLCRK.js} +53 -44
  167. package/createDialogAction-MZ66VY5Q.js +76 -0
  168. package/{createPageAction-75ELC64R.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-KSXPGJB2.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-AROBVRCR.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-EGNWHAUB.js → handleSendMessageAction-DVG5U26T.js} +619 -165
  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-ARZYKGGE.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-3XOFVARF.js → readlineWorkspace-RIE62QVZ.js} +5022 -921
  200. package/{removeDialogAgentAction-OSYNZRX7.js → removeDialogAgentAction-E2H3OZU6.js} +29 -28
  201. package/{runAgentClientLoop-UMF7VZYZ.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-GYGMYOSM.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-4U5W4AMH.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-4YBSYPIY.js +0 -134
  222. package/agentRunCommand-5MU5X5OT.js +0 -161
  223. package/browser-image-compression-MFDTD7K6.js +0 -1763
  224. package/chatQueueReduxAdapter-HVHA2HPM.js +0 -186
  225. package/chromeOpsCommands-IXRLN57H.js +0 -289
  226. package/chunk-42Z3EMC4.js +0 -25363
  227. package/chunk-CQ3WA2NE.js +0 -299
  228. package/chunk-CYSYR67N.js +0 -93
  229. package/chunk-IAG4FHOJ.js +0 -34
  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-QU5A4LYX.js +0 -2415
  239. package/chunk-URMS4XY2.js +0 -10
  240. package/chunk-UV6VISQJ.js +0 -20
  241. package/chunk-VJVNU77E.js +0 -83
  242. package/chunk-WRMKCKZ3.js +0 -13807
  243. package/chunk-Y5GCAMGP.js +0 -9
  244. package/chunk-YPREESF4.js +0 -225
  245. package/contentThunks-AK2F3KNC.js +0 -73
  246. package/createDialogAction-F5WEWA47.js +0 -66
  247. package/dialogCommands-G7YBVAMC.js +0 -102
  248. package/levelLazyShim-GZBKODGI.js +0 -7
  249. package/machineWsRunDispatch-I7F4L532.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-DU4JXVAV.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
@@ -0,0 +1,1794 @@
1
+ // packages/cli/tui/i18n.ts
2
+ var ZH_PATTERNS = /^zh/i;
3
+ function parseCliLocale(raw) {
4
+ const normalized = raw?.trim().toLowerCase();
5
+ if (!normalized) return null;
6
+ if (ZH_PATTERNS.test(normalized)) return "zh";
7
+ if (normalized === "en" || normalized.startsWith("en")) return "en";
8
+ return null;
9
+ }
10
+ function detectLocaleFromEnv(env) {
11
+ const explicit = parseCliLocale(env.NOLO_LANG);
12
+ if (explicit) return explicit;
13
+ const candidates = [env.LC_ALL, env.LC_CTYPE, env.LANG].filter(Boolean);
14
+ for (const candidate of candidates) {
15
+ if (ZH_PATTERNS.test(candidate)) return "zh";
16
+ if (candidate && !candidate.startsWith("C.") && !candidate.startsWith("POSIX")) {
17
+ return "en";
18
+ }
19
+ }
20
+ return null;
21
+ }
22
+ function detectLocale(env) {
23
+ return detectLocaleFromEnv(env) ?? "zh";
24
+ }
25
+ var currentLocale = detectLocale(process.env);
26
+ function getCliLocale() {
27
+ return currentLocale;
28
+ }
29
+ function setCliLocale(locale) {
30
+ currentLocale = locale;
31
+ }
32
+ function initCliLocale(env = process.env) {
33
+ currentLocale = detectLocale(env);
34
+ }
35
+ function newlineHint(platform = process.platform) {
36
+ return platform === "win32" ? "Ctrl+J" : "Shift+Enter";
37
+ }
38
+ var WELCOME_TIPS = {
39
+ en: [
40
+ `Tip: ${newlineHint()} for a newline; /help lists all commands.`,
41
+ "Tip: drag an image file into the terminal \u2014 nolo sees it. A plain path works too.",
42
+ "Tip: /doc attach <doc> brings a doc into this conversation's context.",
43
+ "Tip: /theme switches colors; terminal mode follows your terminal's day/night.",
44
+ "Tip: /history resumes a recent dialog; /agents lists your agents."
45
+ ],
46
+ zh: [
47
+ `\u63D0\u793A\uFF1A${newlineHint()} \u6362\u884C\uFF1B/help \u5217\u51FA\u5168\u90E8\u547D\u4EE4\u3002`,
48
+ "\u63D0\u793A\uFF1A\u628A\u56FE\u7247\u6587\u4EF6\u62D6\u8FDB\u7EC8\u7AEF\u6700\u7701\u4E8B\uFF1B\u4E5F\u80FD\u76F4\u63A5\u8F93\u5165\u56FE\u7247\u8DEF\u5F84\u3002",
49
+ "\u63D0\u793A\uFF1A/doc attach <doc> \u628A\u6587\u6863\u6302\u8FDB\u5F53\u524D\u5BF9\u8BDD\u4E0A\u4E0B\u6587\u3002",
50
+ "\u63D0\u793A\uFF1A/theme \u5207\u6362\u914D\u8272\uFF1B\u65E5\u591C\u95F4\u8DDF\u968F\u7EC8\u7AEF\u4E3B\u9898\u3002",
51
+ "\u63D0\u793A\uFF1A/history \u6062\u590D\u6700\u8FD1\u5BF9\u8BDD\uFF1B/agents \u5217\u51FA\u4F60\u7684\u667A\u80FD\u4F53\u3002"
52
+ ]
53
+ };
54
+ function dailyWelcomeTip(now = Date.now()) {
55
+ const tips = WELCOME_TIPS[currentLocale];
56
+ const day = Math.floor(now / 864e5);
57
+ return tips[day % tips.length];
58
+ }
59
+ var STRINGS = {
60
+ // Welcome hint lives in WELCOME_TIPS + dailyWelcomeTip() (rotating daily
61
+ // tips); the composer placeholder already covers "type / for commands".
62
+ promptLabel: {
63
+ en: "\u276F ",
64
+ zh: "\u276F "
65
+ },
66
+ continueLabel: {
67
+ en: "\u2502 ",
68
+ zh: "\u2502 "
69
+ },
70
+ placeholder: {
71
+ en: "Type a message or / for commands...",
72
+ zh: "\u8F93\u5165\u6D88\u606F\uFF0C\u6216\u7528 / \u67E5\u770B\u547D\u4EE4\u2026"
73
+ },
74
+ newDialog: {
75
+ en: "new dialog",
76
+ zh: "\u65B0\u5BF9\u8BDD"
77
+ },
78
+ startedFreshDialog: {
79
+ en: "Started a fresh dialog.",
80
+ zh: "\u5DF2\u5F00\u59CB\u65B0\u5BF9\u8BDD\u3002"
81
+ },
82
+ clearingDialog: {
83
+ en: "Clearing current dialog messages...",
84
+ zh: "\u6B63\u5728\u6E05\u9664\u5F53\u524D\u5BF9\u8BDD\u6D88\u606F\u2026"
85
+ },
86
+ clearedDialog: {
87
+ en: "Cleared current dialog messages.",
88
+ zh: "\u5DF2\u6E05\u9664\u5F53\u524D\u5BF9\u8BDD\u6D88\u606F\u3002"
89
+ },
90
+ persistentProcessesLeft: {
91
+ en: "{0} persistent process(es) left running in the background.",
92
+ zh: "\u4ECD\u6709 {0} \u4E2A\u5E38\u9A7B\u540E\u53F0\u8FDB\u7A0B\u5728\u540E\u53F0\u7EE7\u7EED\u8FD0\u884C\u3002"
93
+ },
94
+ clearNoDialog: {
95
+ en: "No current dialog messages to clear.",
96
+ zh: "\u5F53\u524D\u6CA1\u6709\u53EF\u6E05\u9664\u7684\u5BF9\u8BDD\u6D88\u606F\u3002"
97
+ },
98
+ clearUsage: {
99
+ en: "Usage: /clear",
100
+ zh: "\u7528\u6CD5\uFF1A/clear"
101
+ },
102
+ contextNextClear: {
103
+ en: "clear current dialog messages",
104
+ zh: "\u6E05\u9664\u5F53\u524D\u5BF9\u8BDD\u6D88\u606F"
105
+ },
106
+ bye: {
107
+ en: "Bye.",
108
+ zh: "\u518D\u89C1\u3002"
109
+ },
110
+ resumedDialogPrefix: {
111
+ en: "Resumed dialog",
112
+ zh: "\u5DF2\u6062\u590D\u5BF9\u8BDD"
113
+ },
114
+ resumeInvalidId: {
115
+ en: "does not look like a dialog id. Use /history to pick one.",
116
+ zh: "\u770B\u8D77\u6765\u4E0D\u662F dialog id\u3002\u7528 /history \u4ECE\u5217\u8868\u91CC\u9009\u4E00\u4E2A\u3002"
117
+ },
118
+ dialogResumeCancelled: {
119
+ en: "Dialog resume cancelled.",
120
+ zh: "\u5DF2\u53D6\u6D88\u6062\u590D\u5BF9\u8BDD\u3002"
121
+ },
122
+ agentSwitchCancelled: {
123
+ en: "Agent switch cancelled.",
124
+ zh: "\u5DF2\u53D6\u6D88\u5207\u6362 agent\u3002"
125
+ },
126
+ agentPickerLoading: {
127
+ en: "Loading agents\u2026",
128
+ zh: "\u6B63\u5728\u52A0\u8F7D agent \u5217\u8868\u2026"
129
+ },
130
+ /**
131
+ * /switch 目录视图的一行提示:收藏项 hydrate 失败时出现,让「收藏看不到」
132
+ * 有任何线索;失败数为 0 时不渲染这一行。
133
+ */
134
+ agentCatalogUnavailableFavorites: {
135
+ en: "\u26A0 {0} favorite(s) unavailable right now",
136
+ zh: "\u26A0 {0} \u4E2A\u6536\u85CF\u9879\u6682\u65F6\u4E0D\u53EF\u7528"
137
+ },
138
+ historyPickerTitle: {
139
+ en: "Resume dialog (\u2191\u2193 Enter Esc)",
140
+ zh: "\u6062\u590D\u5BF9\u8BDD\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
141
+ },
142
+ noDialogsYet: {
143
+ en: "No dialogs yet.",
144
+ zh: "\u8FD8\u6CA1\u6709\u5386\u53F2\u5BF9\u8BDD\u3002"
145
+ },
146
+ langUsage: {
147
+ en: "Usage: /lang <zh|en>",
148
+ zh: "\u7528\u6CD5\uFF1A/lang <zh|en>"
149
+ },
150
+ stopHint: {
151
+ en: "Esc to stop",
152
+ zh: "Esc \u505C\u6B62\u56DE\u590D"
153
+ },
154
+ flushQueuedIdleHint: {
155
+ en: "Flushed {0} queued messages as one.",
156
+ zh: "\u5DF2\u628A {0} \u6761\u6392\u961F\u6D88\u606F\u5408\u5E76\u53D1\u9001\u3002"
157
+ },
158
+ flushQueuedBusyHint: {
159
+ en: "Stopped this reply and flushed {0} queued messages as one.",
160
+ zh: "\u5DF2\u505C\u6B62\u5F53\u524D\u56DE\u590D\uFF0C\u5E76\u628A {0} \u6761\u6392\u961F\u6D88\u606F\u5408\u5E76\u53D1\u9001\u3002"
161
+ },
162
+ turnStopped: {
163
+ en: "Stopped this reply.",
164
+ zh: "\u5DF2\u505C\u6B62\u672C\u6B21\u56DE\u590D\u3002"
165
+ },
166
+ turnStoppedToolPending: {
167
+ en: "Stopped waiting. {0} may still be finishing in the background \u2014 its result won't be added to this conversation.",
168
+ zh: "\u5DF2\u505C\u6B62\u7B49\u5F85\u3002{0} \u53EF\u80FD\u4ECD\u5728\u540E\u53F0\u5B8C\u6210\uFF0C\u5176\u7ED3\u679C\u4E0D\u4F1A\u8BA1\u5165\u672C\u6B21\u5BF9\u8BDD\u3002"
169
+ },
170
+ turnStopping: {
171
+ en: "Stopping\u2026 press Esc again to force",
172
+ zh: "\u6B63\u5728\u505C\u6B62\u2026\u518D\u6309\u4E00\u6B21 Esc \u5F3A\u5236\u505C\u6B62"
173
+ },
174
+ forceStopped: {
175
+ en: "Force stopped. Background tasks may still be finishing.",
176
+ zh: "\u5DF2\u5F3A\u5236\u505C\u6B62\uFF0C\u540E\u53F0\u4EFB\u52A1\u53EF\u80FD\u4ECD\u5728\u6536\u5C3E\u3002"
177
+ },
178
+ turnFailed: {
179
+ en: "This reply failed. Queued messages are kept \u2014 press Enter to resend.",
180
+ zh: "\u672C\u6B21\u56DE\u590D\u51FA\u9519\u3002\u5DF2\u6392\u961F\u7684\u6D88\u606F\u4ECD\u4FDD\u7559\uFF0C\u6309 Enter \u53EF\u91CD\u65B0\u53D1\u9001\u3002"
181
+ },
182
+ quotaExhaustedHint: {
183
+ en: "This agent seems to have hit a quota/rate limit (HTTP 429).\nUse /agent to switch to another agent and keep going \u2014 the dialog context is preserved.",
184
+ zh: "\u5F53\u524D agent \u4F3C\u4E4E\u989D\u5EA6/\u901F\u7387\u53D7\u9650\uFF08429\uFF09\u3002\n\u53EF\u4EE5\u7528 /agent \u5207\u6362\u5230\u5176\u4ED6 agent \u540E\u7EE7\u7EED\uFF0C\u540C\u4E00\u5BF9\u8BDD\u4F1A\u4FDD\u7559\u4E0A\u4E0B\u6587\u3002"
185
+ },
186
+ balanceExhaustedHint: {
187
+ en: 'Your message is saved in this dialog \u2014 top up, then send again or say "continue" to pick up where you left off.',
188
+ zh: "\u4F60\u521A\u53D1\u7684\u8BDD\u5DF2\u4FDD\u5B58\u5728\u5F53\u524D\u5BF9\u8BDD\u91CC\u2014\u2014\u5145\u503C\u540E\u76F4\u63A5\u518D\u8BF4\u4E00\u53E5\u6216\u8BF4\u300C\u7EE7\u7EED\u300D\u5373\u53EF\u63A5\u7740\u804A\uFF0C\u4E0D\u4F1A\u4E22\u4E0A\u4E0B\u6587\u3002"
189
+ },
190
+ balanceInsufficientReason: {
191
+ en: "Insufficient balance: requires > {required}, current balance {current}.",
192
+ zh: "\u4F59\u989D\u4E0D\u8DB3\uFF1A\u9700\u8981\u4F59\u989D > {required}\uFF0C\u5F53\u524D {current}\u3002"
193
+ },
194
+ dialogPreservedHint: {
195
+ en: 'This turn failed, but the dialog is kept. Send another message (or say "continue") to keep going in the same conversation.',
196
+ zh: "\u672C\u8F6E\u5931\u8D25\u4E86\uFF0C\u4F46\u5BF9\u8BDD\u5DF2\u4FDD\u7559\u3002\u76F4\u63A5\u518D\u8BF4\u4E00\u53E5\uFF08\u6216\u8BF4\u300C\u7EE7\u7EED\u300D\uFF09\u5373\u53EF\u5728\u540C\u4E00\u5BF9\u8BDD\u91CC\u63A5\u7740\u804A\u3002"
197
+ },
198
+ dialogNotSavedHint: {
199
+ en: "This turn did not create a dialog. Your next message will start a new conversation \u2014 restate what you need.",
200
+ zh: "\u672C\u8F6E\u6CA1\u6709\u5EFA\u6210\u5BF9\u8BDD\u3002\u4E0B\u4E00\u53E5\u4F1A\u662F\u65B0\u5BF9\u8BDD\u2014\u2014\u8BF7\u628A\u4F60\u60F3\u505A\u7684\u4E8B\u518D\u8BF4\u4E00\u904D\u3002"
201
+ },
202
+ copiedLastReply: {
203
+ en: "Copied the last reply to the clipboard.",
204
+ zh: "\u5DF2\u590D\u5236\u6700\u540E\u4E00\u6761\u56DE\u590D\u5230\u526A\u8D34\u677F\u3002"
205
+ },
206
+ copyNothing: {
207
+ en: "Nothing to copy yet.",
208
+ zh: "\u8FD8\u6CA1\u6709\u53EF\u590D\u5236\u7684\u5185\u5BB9\u3002"
209
+ },
210
+ copyFailed: {
211
+ en: "Copy failed",
212
+ zh: "\u590D\u5236\u5931\u8D25"
213
+ },
214
+ copyUnavailable: {
215
+ en: "Clipboard is unavailable in this environment. The last reply was printed above for manual copy.",
216
+ zh: "\u5F53\u524D\u73AF\u5883\u6CA1\u6709\u53EF\u7528\u7684\u526A\u8D34\u677F\u3002\u6700\u540E\u4E00\u6761\u56DE\u590D\u5DF2\u6253\u5370\u5728\u4E0A\u65B9\uFF0C\u53EF\u624B\u52A8\u590D\u5236\u3002"
217
+ },
218
+ copyUsage: {
219
+ en: "Usage: /copy",
220
+ zh: "\u7528\u6CD5\uFF1A/copy"
221
+ },
222
+ copiedToClipboard: {
223
+ en: "\u2713 Copied to clipboard.",
224
+ zh: "\u2713 \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F\u3002"
225
+ },
226
+ copiedSelection: {
227
+ en: "\u2713 Copied the selection to the clipboard.",
228
+ zh: "\u2713 \u5DF2\u590D\u5236\u9009\u533A\u5230\u526A\u8D34\u677F\u3002"
229
+ },
230
+ copiedSelectionBusy: {
231
+ en: "\u2713 Copied the selection to the clipboard. Press Esc to stop generating.",
232
+ zh: "\u2713 \u5DF2\u590D\u5236\u9009\u533A\u5230\u526A\u8D34\u677F\u3002\u6309 Esc \u505C\u6B62\u751F\u6210\u3002"
233
+ },
234
+ copiedAllHistory: {
235
+ en: "\u2713 Copied the full conversation to the clipboard.",
236
+ zh: "\u2713 \u5DF2\u590D\u5236\u5B8C\u6574\u5BF9\u8BDD\u5230\u526A\u8D34\u677F\u3002"
237
+ },
238
+ copyAllNothing: {
239
+ en: "No conversation to copy yet.",
240
+ zh: "\u8FD8\u6CA1\u6709\u53EF\u590D\u5236\u7684\u5BF9\u8BDD\u5185\u5BB9\u3002"
241
+ },
242
+ ctrlCExitHint: {
243
+ en: "[\u63D0\u793A] \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA | \u8F93\u5165 /copy \u53EF\u590D\u5236\u6700\u65B0\u56DE\u590D",
244
+ zh: "[\u63D0\u793A] \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA | \u8F93\u5165 /copy \u53EF\u590D\u5236\u6700\u65B0\u56DE\u590D"
245
+ },
246
+ ctrlCClearedDraft: {
247
+ en: "Draft cleared.",
248
+ zh: "\u8F93\u5165\u8349\u7A3F\u5DF2\u6E05\u7A7A\u3002"
249
+ },
250
+ // 空草稿按 Backspace 逐个撤销附件(composer 附件条)。
251
+ attachmentRemovedHint: {
252
+ en: "Removed attachment {0}, {1} remaining",
253
+ zh: "\u5DF2\u79FB\u9664\u9644\u4EF6 {0}\uFF0C\u5269\u4F59 {1} \u5F20"
254
+ },
255
+ historyNoToken: {
256
+ en: "History requires an auth token. Run `nolo login` or set AUTH_TOKEN.",
257
+ zh: "\u67E5\u770B\u5386\u53F2\u5BF9\u8BDD\u9700\u8981\u767B\u5F55\u51ED\u8BC1\u3002\u8BF7\u8FD0\u884C `nolo login` \u6216\u8BBE\u7F6E AUTH_TOKEN\u3002"
258
+ },
259
+ historyBadToken: {
260
+ en: "Could not read a user id from AUTH_TOKEN. Run `nolo login` again.",
261
+ zh: "\u65E0\u6CD5\u4ECE AUTH_TOKEN \u89E3\u6790\u51FA\u7528\u6237 id\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C `nolo login`\u3002"
262
+ },
263
+ mouseOn: {
264
+ en: "Mouse mode on: wheel scrolls the transcript; hold Shift (or Option/Fn) to select text.",
265
+ zh: "\u9F20\u6807\u6A21\u5F0F\u5DF2\u5F00\u542F\uFF1A\u6EDA\u8F6E\u6EDA\u52A8\u5BF9\u8BDD\u8BB0\u5F55\uFF1B\u6309\u4F4F Shift\uFF08\u6216 Option/Fn\uFF09\u53EF\u62D6\u9009\u590D\u5236\u3002"
266
+ },
267
+ mouseOff: {
268
+ en: "Mouse mode off: drag to select/copy freely; scroll with PageUp/PageDown.",
269
+ zh: "\u9F20\u6807\u6A21\u5F0F\u5DF2\u5173\u95ED\uFF1A\u53EF\u76F4\u63A5\u62D6\u9009\u590D\u5236\uFF1B\u7528 PageUp/PageDown \u6EDA\u52A8\u5BF9\u8BDD\u8BB0\u5F55\u3002"
270
+ },
271
+ mouseUsage: {
272
+ en: "Usage: /mouse <on|off>",
273
+ zh: "\u7528\u6CD5\uFF1A/mouse <on|off>"
274
+ },
275
+ mathOn: {
276
+ en: "Math rendering on: LaTeX formulas rendered with Unicode symbols.",
277
+ zh: "\u6570\u5B66\u516C\u5F0F\u6E32\u67D3\u5DF2\u5F00\u542F\uFF1ALaTeX \u516C\u5F0F\u5C06\u8F6C\u5199\u4E3A Unicode \u7B26\u53F7\u3002"
278
+ },
279
+ mathOff: {
280
+ en: "Math rendering off: raw LaTeX formulas preserved.",
281
+ zh: "\u6570\u5B66\u516C\u5F0F\u6E32\u67D3\u5DF2\u5173\u95ED\uFF1A\u4FDD\u7559\u539F\u59CB LaTeX \u516C\u5F0F\u3002"
282
+ },
283
+ mathUsage: {
284
+ en: "Usage: /math <on|off>",
285
+ zh: "\u7528\u6CD5\uFF1A/math <on|off>"
286
+ },
287
+ altscreenOn: {
288
+ en: "Alternate screen on: the TUI uses a private buffer so the terminal wheel no longer fights its own scroll state.",
289
+ zh: "\u5907\u7528\u5C4F\u5DF2\u5F00\u542F\uFF1ATUI \u4F7F\u7528\u72EC\u7ACB\u7F13\u51B2\u533A\uFF0C\u7EC8\u7AEF\u6EDA\u8F6E\u4E0D\u518D\u4E0E\u81EA\u8EAB\u6EDA\u52A8\u72B6\u6001\u4E92\u76F8\u6253\u67B6\u3002"
290
+ },
291
+ altscreenOff: {
292
+ en: "Alternate screen off: the TUI shares the shell scrollback (wheel may desync the viewport).",
293
+ zh: "\u5907\u7528\u5C4F\u5DF2\u5173\u95ED\uFF1ATUI \u4E0E shell \u5171\u7528\u56DE\u6EDA\u7F13\u51B2\u533A\uFF08\u6EDA\u8F6E\u53EF\u80FD\u8BA9\u89C6\u53E3\u9519\u4F4D\uFF09\u3002"
294
+ },
295
+ altscreenUsage: {
296
+ en: "Usage: /altscreen <on|off>",
297
+ zh: "\u7528\u6CD5\uFF1A/altscreen <on|off>"
298
+ },
299
+ autoCurrent: {
300
+ en: "Permission auto-approve: {0}",
301
+ zh: "\u6743\u9650\u81EA\u52A8\u5316\uFF1A{0}"
302
+ },
303
+ autoUsage: {
304
+ en: "Usage: /auto <on|off>",
305
+ zh: "\u7528\u6CD5\uFF1A/auto <on|off>"
306
+ },
307
+ autoOn: {
308
+ en: "Permission auto-approve ON \u2014 destructive shell and external-file confirmations will be skipped for this session.",
309
+ zh: "\u6743\u9650\u81EA\u52A8\u5316\u5DF2\u5F00\u542F\uFF1A\u672C\u4F1A\u8BDD\u5185\u7834\u574F\u6027 shell \u4E0E\u5916\u90E8\u6587\u4EF6\u8BBF\u95EE\u786E\u8BA4\u5C06\u81EA\u52A8\u653E\u884C\u3002"
310
+ },
311
+ autoOff: {
312
+ en: "Permission auto-approve OFF \u2014 confirmations will ask again.",
313
+ zh: "\u6743\u9650\u81EA\u52A8\u5316\u5DF2\u5173\u95ED\uFF1A\u6062\u590D\u9010\u6B21\u786E\u8BA4\u3002"
314
+ },
315
+ langSwitched: {
316
+ en: "Language switched to English.",
317
+ zh: "\u5DF2\u5207\u6362\u4E3A\u4E2D\u6587\u3002"
318
+ },
319
+ // --- Tool trace copy ------------------------------------------------------
320
+ // The compact trace shows only status, never timing or output size: a line
321
+ // count told the user nothing actionable and the ms figure read as noise.
322
+ workingFallback: {
323
+ en: "Working\u2026",
324
+ zh: "\u5904\u7406\u4E2D\u2026"
325
+ },
326
+ // 回合结束的淡色收尾行:耗时 · 输出 token · 积分(后两段可缺省)。
327
+ turnSummaryOutput: {
328
+ en: "{0} out",
329
+ zh: "\u8F93\u51FA {0}"
330
+ },
331
+ thinkingActive: {
332
+ en: "Thinking\u2026",
333
+ zh: "\u601D\u8003\u4E2D\u2026"
334
+ },
335
+ thinkingActivePreview: {
336
+ en: "Thinking: {0}",
337
+ zh: "\u601D\u8003\u4E2D\uFF1A{0}"
338
+ },
339
+ // --- Pre-delta turn phase labels (ctx-overflow-feedback batch 3) ----------
340
+ // Rendered on the spinner / activity line while the local runtime checks the
341
+ // context window, compacts history, or waits for the first model delta —
342
+ // the previously silent pre-delta window (batch 1/2a 修好 runtime 与 SSE,
343
+ // 这里补齐 CLI/TUI 的状态行投影)。compacting 行附带可取消提示:Esc /
344
+ // Ctrl+C 即 abort,语义与 localLoop 的 abortSignal 一致。
345
+ contextChecking: {
346
+ en: "Checking this model's context window\u2026",
347
+ zh: "\u6B63\u5728\u68C0\u67E5\u5F53\u524D\u6A21\u578B\u7684\u4E0A\u4E0B\u6587\u7A97\u53E3\u2026"
348
+ },
349
+ contextCompacting: {
350
+ en: "Compacting history\u2026 (Esc/Ctrl+C to cancel)",
351
+ zh: "\u6B63\u5728\u538B\u7F29\u5386\u53F2\u8BB0\u5F55\u2026\uFF08Esc/Ctrl+C \u53D6\u6D88\uFF09"
352
+ },
353
+ waitingForModel: {
354
+ en: "Waiting for the model\u2026",
355
+ zh: "\u6B63\u5728\u7B49\u5F85\u6A21\u578B\u54CD\u5E94\u2026"
356
+ },
357
+ // --- Local turn deadline failure (single actionable line) -----------------
358
+ // localLoop 主请求 idle deadline(DEFAULT_LLM_REQUEST_TIMEOUT_MS 兜底或调用方
359
+ // timeoutMs)到达后抛 code=LLM_REQUEST_TIMEOUT;generic 分支的「修本地
360
+ // 凭据」文案在这里是错误指引(请求已发出,问题在上游无响应)。
361
+ // 语义是 idle(静默窗):{0} 内没有任何新输出才放弃,不是说模型「完全没
362
+ // 响应」——文案必须与这个语义一致,否则会把正在生成的用户推向重复发送
363
+ // (2026-10 ctx-overflow-feedback review 修复 1)。
364
+ llmRequestTimedOut: {
365
+ en: "No new model output for {0}, so this turn was stopped. Your message was kept. Retry in this conversation, switch to another model, or run /compact first.",
366
+ zh: "\u6A21\u578B\u5DF2 {0} \u6CA1\u6709\u65B0\u8F93\u51FA\uFF0C\u672C\u8F6E\u5DF2\u505C\u6B62\u7B49\u5F85\uFF08\u53EF\u80FD\u4ECD\u5728\u751F\u6210\uFF09\u3002\u4F60\u7684\u6D88\u606F\u5DF2\u4FDD\u7559\u3002\u53EF\u5728\u672C\u5BF9\u8BDD\u91CD\u8BD5\u3001\u5207\u6362\u5230\u5176\u4ED6\u6A21\u578B\uFF0C\u6216\u5148 /compact \u538B\u7F29\u5BF9\u8BDD\u3002"
367
+ },
368
+ // --- Local run 429/rate-limit display (compact 3-line block) --------------
369
+ // 旧 429 文案是一条巨长英文 + 结尾拼接中文冷却说明(又长又中英混排)。现在按
370
+ // locale 渲染 3 行:headline(含上游 tag 与清洗后的详情)+ 冷却/探测 + 出口。
371
+ // {0} = 上游标签(antigravity · gemini-3.8-flash-tiered;取不到回退 transport 名)
372
+ // {1} = 清洗后的上游原文(去 details= / 传输前缀 / 结尾复位句,折叠空白,≤140 字符)
373
+ localRunRateLimitQuota: {
374
+ en: "[nolo] Upstream quota exhausted ({0}): {1}",
375
+ zh: "[nolo] \u4E0A\u6E38\u989D\u5EA6\u5DF2\u7528\u5C3D\uFF08{0}\uFF09\uFF1A{1}"
376
+ },
377
+ localRunRateLimitThrottled: {
378
+ en: "[nolo] Upstream rate limit ({0}): {1}",
379
+ zh: "[nolo] \u4E0A\u6E38\u9650\u6D41\uFF08{0}\uFF09\uFF1A{1}"
380
+ },
381
+ // 第 2 行复位提示:沿用 extractRateLimitResetHint 抓到的上游原文(不换算),
382
+ // 只作括号补充;没抓到就没有这段括号。
383
+ localRunRateLimitResetNote: {
384
+ en: " (upstream reset in {0})",
385
+ zh: "\uFF08\u4E0A\u6E38\u7EA6 {0}\u540E\u590D\u4F4D\uFF09"
386
+ },
387
+ // 第 2 行:{0} = 冷却截止(本地时间,当天 HH:MM / 跨天 MM-DD HH:MM),
388
+ // {1} = 复位提示或空串,{2} = 自动探测间隔(分钟)。无 cooldownUntil 时整行省略。
389
+ localRunRateLimitCooldown: {
390
+ en: " Cooldown until {0}{1}; auto-probing every {2} min meanwhile (the upstream may not be restored by then).",
391
+ zh: " \u51B7\u5374\u81F3 {0}{1}\uFF1B\u671F\u95F4\u6BCF {2} \u5206\u949F\u81EA\u52A8\u8BD5\u63A2\u4E00\u6B21\uFF08\u4E0A\u6E38\u672A\u5FC5\u5C4A\u65F6\u6062\u590D\uFF09\u3002"
392
+ },
393
+ // 第 3 行:三个出口(换 agent / 强制走服务器 / 已充值清冷却)。
394
+ localRunRateLimitExits: {
395
+ en: " Switch agent: nolo agent list; force server: --server; topped up: nolo auth cooldown, then --clear <credential>",
396
+ zh: " \u6362 agent\uFF1Anolo agent list\uFF1B\u5F3A\u5236\u8D70\u670D\u52A1\u5668\uFF1A--server\uFF1B\u5DF2\u5145\u503C\uFF1Anolo auth cooldown \u67E5\u51ED\u8BC1\u540D\u540E --clear <\u51ED\u8BC1\u540D>"
397
+ },
398
+ // --- Local run 402/余额不足 display (compact 3-line block) ----------------
399
+ // 与 429 同结构:headline(余额不足 / Coding Plan 额度用尽 + 上游 tag)+ 复位
400
+ // 时刻(仅当报文确实给了 reset_at)+ 出口。{0} = 上游标签(provider · model,
401
+ // 取不到回退 transport 名),{1} = 清洗后的原因(或定量原因)。
402
+ localRunBalanceExhausted: {
403
+ en: "[nolo] Insufficient balance, cannot continue ({0}): {1}",
404
+ zh: "[nolo] \u4F59\u989D\u4E0D\u8DB3\uFF0C\u65E0\u6CD5\u7EE7\u7EED\uFF08{0}\uFF09\uFF1A{1}"
405
+ },
406
+ // 报文带 coding_plan_exhausted 时的措辞:计划额度与钱包余额是两笔要分别充的账。
407
+ localRunBalanceCodingPlan: {
408
+ en: "[nolo] Coding Plan quota exhausted and the wallet balance is insufficient ({0}): {1}",
409
+ zh: "[nolo] Coding Plan \u989D\u5EA6\u5DF2\u7528\u5C3D\u4E14\u94B1\u5305\u4F59\u989D\u4E0D\u8DB3\uFF08{0}\uFF09\uFF1A{1}"
410
+ },
411
+ // 第 2 行:{0} = 计划额度复位时刻(本地时间)。报文没给复位时刻时整行省略。
412
+ localRunBalanceReset: {
413
+ en: " Plan quota resets at {0} \u2014 this restores the plan quota only; it does not top up your wallet.",
414
+ zh: " \u8BA1\u5212\u989D\u5EA6 {0} \u590D\u4F4D\u2014\u2014\u53EA\u6062\u590D\u8BA1\u5212\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u7ED9\u94B1\u5305\u5145\u503C\u3002"
415
+ },
416
+ // 清洗后仍取不到原因(报文只有 `{"error":{}}` 这类空壳)时的兜底:避免悬空冒号。
417
+ localRunBalanceUnknownReason: {
418
+ en: "the provider returned a payment-required error without a reason line",
419
+ zh: "\u4E0A\u6E38\u53EA\u8FD4\u56DE\u4E86\u300C\u9700\u8981\u4ED8\u6B3E\u300D\u9519\u8BEF\uFF0C\u6CA1\u6709\u7ED9\u51FA\u539F\u56E0"
420
+ },
421
+ // 第 3 行:出口(充值后重发 / 换 agent / 强制走服务器)。刻意不重复 TUI 那句
422
+ //「你刚发的话已保存在当前对话里」。
423
+ localRunBalanceExits: {
424
+ en: " Top up and send again; or switch agent: nolo agent list; force server: --server",
425
+ zh: " \u5145\u503C\u540E\u91CD\u53D1\u5373\u53EF\uFF1B\u6216\u6362 agent\uFF1Anolo agent list\uFF1B\u5F3A\u5236\u8D70\u670D\u52A1\u5668\uFF1A--server"
426
+ },
427
+ // 派发前的本地冷却拦截(原两行英文 → 本地化单行压缩)。
428
+ agentCooldownBlocked: {
429
+ en: "[nolo] Agent {0} is in 429 cooldown until {1}. This dispatch was not sent \u2014 pick another agent, or retry after the cooldown.",
430
+ zh: "[nolo] Agent {0} \u51B7\u5374\u4E2D\uFF0C\u81F3 {1}\u3002\u672C\u6B21\u6D3E\u53D1\u672A\u53D1\u51FA\u2014\u2014\u6362\u4E00\u4E2A agent\uFF0C\u6216\u5230\u70B9\u540E\u91CD\u8BD5\u3002"
431
+ },
432
+ thinkingTraceLine: {
433
+ en: "\u273B Thought for {0}",
434
+ zh: "\u273B \u601D\u8003 {0}"
435
+ },
436
+ toolNeedsAction: {
437
+ en: "needs action",
438
+ zh: "\u5F85\u786E\u8BA4"
439
+ },
440
+ toolTimedOut: {
441
+ en: "timed out",
442
+ zh: "\u5DF2\u8D85\u65F6"
443
+ },
444
+ toolExitCode: {
445
+ en: "exit",
446
+ zh: "\u9000\u51FA\u7801"
447
+ },
448
+ toolFailed: {
449
+ en: "failed",
450
+ zh: "\u5931\u8D25"
451
+ },
452
+ usedSkillLabel: {
453
+ en: "Used Skill",
454
+ zh: "\u5DF2\u52A0\u8F7D\u6280\u80FD"
455
+ },
456
+ // --- Agent-run orchestration cards (injected into packages/ai helpers) ---
457
+ runStatusLabel: {
458
+ en: "Run status",
459
+ zh: "\u8FD0\u884C\u72B6\u6001"
460
+ },
461
+ runStartedLabel: {
462
+ en: "Run started",
463
+ zh: "\u8FD0\u884C\u5DF2\u542F\u52A8"
464
+ },
465
+ runStoppedLabel: {
466
+ en: "Run stopped",
467
+ zh: "\u8FD0\u884C\u5DF2\u505C\u6B62"
468
+ },
469
+ runFinishedLabel: {
470
+ en: "Run finished",
471
+ zh: "\u8FD0\u884C\u5DF2\u7ED3\u675F"
472
+ },
473
+ runLogTailLabel: {
474
+ en: "Log tail:",
475
+ zh: "\u65E5\u5FD7\u5C3E\u90E8\uFF1A"
476
+ },
477
+ // Normal-mode safe projection: the raw errorMessage/logLines of a failed run
478
+ // stay in pro/verbose; normal mode names the failure and points at pro.
479
+ runsListLabel: {
480
+ en: "Runs ({0})",
481
+ zh: "\u8FD0\u884C ({0})"
482
+ },
483
+ // Tool-count fact on run rows/cards/panel (`12 tools` / `12 个工具`).
484
+ runToolsCount: {
485
+ en: "{0} tools",
486
+ zh: "{0} \u4E2A\u5DE5\u5177"
487
+ },
488
+ // Card-body status words / row labels. Display labels only: raw log lines,
489
+ // protocol params and tool ids stay untranslated.
490
+ runStatusNotFound: { en: "not_found", zh: "\u672A\u627E\u5230" },
491
+ runRowAgent: { en: "agent", zh: "\u6267\u884C\u8005" },
492
+ runRowStatus: { en: "status", zh: "\u72B6\u6001" },
493
+ runRowTools: { en: "tools", zh: "\u5DE5\u5177" },
494
+ runRowNote: { en: "note", zh: "\u5907\u6CE8" },
495
+ runRowError: { en: "error", zh: "\u9519\u8BEF" },
496
+ runRowTask: { en: "task", zh: "\u4EFB\u52A1" },
497
+ // listAgents card header (`Agents (3)` / `智能体 (3)`). The shared ai
498
+ // renderer keeps the English default; the CLI relabels the header line.
499
+ agentsListLabel: { en: "Agents ({0})", zh: "\u667A\u80FD\u4F53 ({0})" },
500
+ // Fallback identity for auto-generated agent ids (run zone / dock / panel).
501
+ subAgentName: {
502
+ en: "Sub-agent",
503
+ zh: "\u5B50\u667A\u80FD\u4F53"
504
+ },
505
+ // Status vocabulary the fixed run zone does not label (running shows only its
506
+ // elapsed time there). `en` must stay equal to the raw store status so a
507
+ // switch of locale never changes what an English reader already understood.
508
+ runZoneRunning: { en: "running", zh: "\u8FD0\u884C\u4E2D" },
509
+ runZonePending: { en: "pending", zh: "\u7B49\u5F85\u4E2D" },
510
+ runZoneCancelling: { en: "cancelling", zh: "\u6B63\u5728\u53D6\u6D88" },
511
+ // controlAgentRun displayData: wait timeout and stop-not-confirmed outcomes.
512
+ agentRunWaitTimeout: {
513
+ en: "\u23F3 wait timed out after {0}s \u2014 the run is still running: wait again later, or use status/stop",
514
+ zh: "\u23F3 wait \u8D85\u65F6\uFF08{0}s\uFF09\uFF0Crun \u4ECD\u5728\u8FD0\u884C\uFF1A\u53EF\u7A0D\u540E\u518D wait\uFF0C\u6216\u6539\u7528 status/stop"
515
+ },
516
+ agentRunStopFailedAlive: {
517
+ en: "stop failed: process {0} still alive after SIGKILL",
518
+ zh: "\u505C\u6B62\u5931\u8D25\uFF1A\u8FDB\u7A0B {0} \u5728 SIGKILL \u540E\u4ECD\u7136\u5B58\u6D3B"
519
+ },
520
+ agentRunPendingReconcile: {
521
+ en: "{0} (pending reconcile)",
522
+ zh: "{0}\uFF08\u5F85\u5BF9\u8D26\uFF09"
523
+ },
524
+ // --- Fixed run zone (top of composer, replaces the ⚙ running status chip) --
525
+ // Each active run renders as `⚙ <title> · <agent> · <elapsed> · N tools`.
526
+ // runZoneFor is the elapsed-time fact for a *running* run (`for 1m23s` /
527
+ // `已运行 1m23s`); terminal runs print `<status> <age>` instead and don't use it.
528
+ runZoneFor: {
529
+ en: "for {0}",
530
+ zh: "\u5DF2\u8FD0\u884C {0}"
531
+ },
532
+ // Terminal linger line: `✓ <run> · done · took 12m03s`.
533
+ runZoneDone: { en: "done", zh: "\u5B8C\u6210" },
534
+ runZoneFailed: { en: "failed", zh: "\u5931\u8D25" },
535
+ runZoneCancelled: { en: "cancelled", zh: "\u5DF2\u53D6\u6D88" },
536
+ runZoneTook: { en: "took {0}", zh: "\u7528\u65F6 {0}" },
537
+ // Overflow marker when more runs are active than the zone shows at once.
538
+ runZoneMore: {
539
+ en: "+{0} more",
540
+ zh: "\u8FD8\u6709 {0} \u4E2A"
541
+ },
542
+ // Background-process rows in the same zone (`❯ npm run dev · 已运行 3m · pid 123`).
543
+ // The pid is how the user targets /stop, so it is a fact, not decoration.
544
+ procZonePid: { en: "pid {0}", zh: "pid {0}" },
545
+ // 残留行(进程已退出):running 用 `已运行`,退出的说「用时」,因为它不再走秒。
546
+ procZoneTook: { en: "took {0}", zh: "\u7528\u65F6 {0}" },
547
+ procZoneExit: { en: "exit {0}", zh: "exit {0}" },
548
+ // --- Dialog (picker / confirm) copy --------------------------------------
549
+ // Key-hint wording is unified across select / multi-select / confirm so the
550
+ // three dialogs read as one family: "<Label> <↑↓ move · Enter choose ·
551
+ // Esc cancel> <count>". Connectors are "·" between keys, two spaces between
552
+ // the label, hint, and count. zh uses full-width parentheses to match the
553
+ // existing historyPickerTitle; en uses ASCII parentheses.
554
+ dialogSelectLabel: {
555
+ en: "Select",
556
+ zh: "\u9009\u62E9"
557
+ },
558
+ dialogSelectHint: {
559
+ en: "(\u2191\u2193 move \xB7 Enter choose \xB7 Esc cancel)",
560
+ zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
561
+ },
562
+ dialogMultiSelectLabel: {
563
+ en: "Select",
564
+ zh: "\u9009\u62E9"
565
+ },
566
+ dialogMultiSelectHint: {
567
+ en: "(\u2191\u2193 move \xB7 Space toggle \xB7 Enter submit \xB7 Esc cancel)",
568
+ zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Space \u5207\u6362 \xB7 Enter \u63D0\u4EA4 \xB7 Esc \u53D6\u6D88\uFF09"
569
+ },
570
+ dialogMultiSelectSelected: {
571
+ en: "selected",
572
+ zh: "\u5DF2\u9009"
573
+ },
574
+ dialogMultiSelectRequired: {
575
+ en: "Pick at least one option to submit",
576
+ zh: "\u81F3\u5C11\u9009\u62E9\u4E00\u9879\u624D\u80FD\u63D0\u4EA4"
577
+ },
578
+ dialogConfirmHint: {
579
+ en: "(\u2191\u2193 move \xB7 Enter choose \xB7 Esc cancel)",
580
+ zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
581
+ },
582
+ dialogConfirmTitle: {
583
+ en: "Confirm destructive shell command",
584
+ zh: "\u786E\u8BA4\u6267\u884C\u7834\u574F\u6027 shell \u547D\u4EE4"
585
+ },
586
+ dialogConfirmBody: {
587
+ en: "This command may delete or reset user content and needs explicit confirmation before it runs.",
588
+ zh: "\u8BE5\u547D\u4EE4\u53EF\u80FD\u5220\u9664\u6216\u91CD\u7F6E\u7528\u6237\u5185\u5BB9\uFF0C\u9700\u8981\u7528\u6237\u660E\u786E\u786E\u8BA4\u540E\u624D\u80FD\u6267\u884C\u3002"
589
+ },
590
+ dialogConfirmExternalFileTitle: {
591
+ en: "Confirm reading a file outside the workspace",
592
+ zh: "\u786E\u8BA4\u8BFB\u53D6\u5DE5\u4F5C\u533A\u5916\u90E8\u6587\u4EF6"
593
+ },
594
+ dialogConfirmExternalFileBody: {
595
+ en: "This path is outside the current workspace. Allow this one-time access, or deny it.",
596
+ zh: "\u8BE5\u8DEF\u5F84\u4F4D\u4E8E\u5F53\u524D\u5DE5\u4F5C\u533A\u4E4B\u5916\u3002\u786E\u8BA4\u540E\u672C\u6B21\u8BBF\u95EE\u653E\u884C\uFF0C\u5426\u5219\u62D2\u7EDD\u3002"
597
+ },
598
+ dialogConfirmCommandTruncated: {
599
+ en: "(truncated)",
600
+ zh: "\uFF08\u5DF2\u622A\u65AD\uFF09"
601
+ },
602
+ dialogConfirmAllowLabel: {
603
+ en: "Allow",
604
+ zh: "\u5141\u8BB8"
605
+ },
606
+ dialogConfirmAllowDetail: {
607
+ en: "execute this time",
608
+ zh: "\u672C\u6B21\u6267\u884C"
609
+ },
610
+ dialogConfirmCancelLabel: {
611
+ en: "Cancel",
612
+ zh: "\u53D6\u6D88"
613
+ },
614
+ dialogConfirmCancelDetail: {
615
+ en: "abort the operation",
616
+ zh: "\u4E2D\u6B62\u64CD\u4F5C"
617
+ },
618
+ // --- Ask choice (ask_user) ------------------------------------------
619
+ askChoiceTitle: {
620
+ en: "question",
621
+ zh: "\u95EE\u9898"
622
+ },
623
+ askChoiceScrollHint: {
624
+ en: "\u2191 Shift+wheel scrolls back terminal history",
625
+ zh: "\u2191 Shift+\u6EDA\u8F6E\u53EF\u56DE\u770B\u4E0A\u65B9\u6D88\u606F"
626
+ },
627
+ askChoiceSubmit: {
628
+ en: "submit \u2193",
629
+ zh: "\u63D0\u4EA4 \u2193"
630
+ },
631
+ askChoiceSubmitRow: {
632
+ en: "Done",
633
+ zh: "\u5B8C\u6210"
634
+ },
635
+ askChoiceSkipRow: {
636
+ en: "Skip",
637
+ zh: "\u8DF3\u8FC7"
638
+ },
639
+ askChoiceOtherLabel: {
640
+ en: "Other",
641
+ zh: "\u5176\u4ED6"
642
+ },
643
+ askChoiceHintSingle: {
644
+ en: "Enter/Space picks \xB7 single question sends \xB7 multi-question jumps to the next unanswered \xB7 Enter in Other confirms and continues",
645
+ zh: "Enter/\u7A7A\u683C \u9009\u62E9\uFF1A\u5355\u9898\u76F4\u63A5\u53D1\u9001\u3001\u591A\u9898\u8DF3\u5230\u4E0B\u4E00\u672A\u7B54\u9898 \xB7 \u5176\u4ED6\u8F93\u5165\u540E Enter \u786E\u8BA4\u5E76\u7EE7\u7EED"
646
+ },
647
+ askChoiceHintOptional: {
648
+ en: "Optional question \u2014 Enter/Space picks (one step) \xB7 skip if you don't want to answer",
649
+ zh: "\u53EF\u9009\u9898 \u2014 Enter/\u7A7A\u683C \u9009\u62E9\u5373\u5B8C\u6210 \xB7 \u4E0D\u60F3\u56DE\u7B54\u53EF\u8DF3\u8FC7"
650
+ },
651
+ askChoiceHintMulti: {
652
+ en: "Enter/Space toggles \xB7 \u2193 to Done row, Enter sends",
653
+ zh: "Enter/\u7A7A\u683C \u5207\u6362\u9009\u4E2D \xB7 \u2193 \u5230\u5B8C\u6210\u884C Enter \u53D1\u9001"
654
+ },
655
+ askChoiceFooterSingle: {
656
+ en: "\u21B5 pick/send \xB7 tab switch \xB7 esc cancel",
657
+ zh: "\u21B5 \u9009\u62E9/\u53D1\u9001 \xB7 tab \u5207\u6362 \xB7 esc \u53D6\u6D88"
658
+ },
659
+ askChoiceFooterSkip: {
660
+ en: "\u21B5 pick/send \xB7 \u2193 skip row \u21B5 skip \xB7 tab switch \xB7 esc cancel",
661
+ zh: "\u21B5 \u9009\u62E9/\u53D1\u9001 \xB7 \u2193 \u8DF3\u8FC7\u884C \u21B5 \u8DF3\u8FC7 \xB7 tab \u5207\u6362 \xB7 esc \u53D6\u6D88"
662
+ },
663
+ askChoiceFooterMulti: {
664
+ en: "\u21B5 toggle \xB7 \u2193 done row \u21B5 send \xB7 ctrl+s send \xB7 tab switch \xB7 esc cancel",
665
+ zh: "\u21B5 \u5207\u6362 \xB7 \u2193 \u5B8C\u6210\u884C \u21B5 \u53D1\u9001 \xB7 ctrl+s \u53D1\u9001 \xB7 tab \u5207\u6362 \xB7 esc \u53D6\u6D88"
666
+ },
667
+ askChoiceValidationRequired: {
668
+ en: "Required questions are unanswered \u2014 jumped to the first one.",
669
+ zh: "\u5FC5\u586B\u95EE\u9898\u5C1A\u672A\u56DE\u7B54 \u2014 \u5DF2\u8DF3\u8F6C\u5230\u7B2C\u4E00\u4E2A\u672A\u7B54\u9898\u3002"
670
+ },
671
+ askChoiceHistoryHint: {
672
+ en: "Type a number to choose, or reply directly:",
673
+ zh: "\u8BF7\u8F93\u5165\u5E8F\u53F7\u9009\u62E9\uFF0C\u6216\u76F4\u63A5\u56DE\u590D\uFF1A"
674
+ },
675
+ askChoiceHistorySelected: {
676
+ en: "selected",
677
+ zh: "\u5DF2\u9009"
678
+ },
679
+ askChoiceHistoryCancelled: {
680
+ en: "cancelled",
681
+ zh: "\u5DF2\u53D6\u6D88"
682
+ },
683
+ contextTitle: {
684
+ en: "Workspace context",
685
+ zh: "\u5DE5\u4F5C\u533A\u4E0A\u4E0B\u6587"
686
+ },
687
+ contextNext: {
688
+ en: "Next:",
689
+ zh: "\u4E0B\u4E00\u6B65\uFF1A"
690
+ },
691
+ contextFieldAgent: {
692
+ en: "agent",
693
+ zh: "\u667A\u80FD\u4F53"
694
+ },
695
+ contextFieldTokens: {
696
+ en: "tokens",
697
+ zh: "\u4EE4\u724C"
698
+ },
699
+ contextFieldDialog: {
700
+ en: "dialog",
701
+ zh: "\u5BF9\u8BDD"
702
+ },
703
+ contextFieldDocs: {
704
+ en: "docs",
705
+ zh: "\u6587\u6863"
706
+ },
707
+ contextFieldSkills: {
708
+ en: "skills",
709
+ zh: "\u6280\u80FD"
710
+ },
711
+ contextFieldProfile: {
712
+ en: "profile",
713
+ zh: "\u914D\u7F6E"
714
+ },
715
+ contextFieldRuntime: {
716
+ en: "runtime",
717
+ zh: "\u8FD0\u884C\u65F6"
718
+ },
719
+ contextFieldServer: {
720
+ en: "server",
721
+ zh: "\u670D\u52A1\u7AEF"
722
+ },
723
+ contextNextAgents: {
724
+ en: "see specialist shortcuts",
725
+ zh: "\u67E5\u770B\u4E13\u7528\u667A\u80FD\u4F53\u5FEB\u6377\u65B9\u5F0F"
726
+ },
727
+ contextNextDoc: {
728
+ en: "add working context",
729
+ zh: "\u6DFB\u52A0\u5DE5\u4F5C\u4E0A\u4E0B\u6587"
730
+ },
731
+ contextNextSkill: {
732
+ en: "attach a skill to this workspace",
733
+ zh: "\u4E3A\u8BE5\u5DE5\u4F5C\u533A\u6302\u8F7D\u6280\u80FD"
734
+ },
735
+ contextNextNew: {
736
+ en: "start a clean dialog",
737
+ zh: "\u5F00\u59CB\u4E00\u4E2A\u5E72\u51C0\u7684\u5BF9\u8BDD"
738
+ },
739
+ agentsTitle: {
740
+ en: "Agents:",
741
+ zh: "\u667A\u80FD\u4F53\uFF1A"
742
+ },
743
+ // --- Paste / clipboard ------------------------------------------------
744
+ pasteUsage: {
745
+ en: "Usage: /paste (no arguments). Reads your clipboard now: an image becomes an attachment, text lands in the draft. Tip: dragging an image file onto the terminal is the most reliable way to attach a picture.",
746
+ zh: "\u7528\u6CD5\uFF1A/paste\uFF08\u65E0\u53C2\u6570\uFF09\u3002\u7ACB\u5373\u8BFB\u53D6\u526A\u8D34\u677F\uFF1A\u56FE\u7247\u53D8\u9644\u4EF6\uFF0C\u6587\u672C\u8FDB\u8349\u7A3F\u3002\u63D0\u793A\uFF1A\u628A\u56FE\u7247\u6587\u4EF6\u62D6\u8FDB\u7EC8\u7AEF\u662F\u9644\u4E0A\u56FE\u7247\u6700\u53EF\u9760\u7684\u65B9\u5F0F\u3002"
747
+ },
748
+ pasteTextInserted: {
749
+ en: "Pasted {0} characters from the clipboard into the draft.",
750
+ zh: "\u5DF2\u4ECE\u526A\u8D34\u677F\u7C98\u8D34 {0} \u4E2A\u5B57\u7B26\u5230\u8349\u7A3F\u3002"
751
+ },
752
+ pasteStaleDropped: {
753
+ en: "Discarded a clipboard read that finished after the draft changed.",
754
+ zh: "\u526A\u8D34\u677F\u8BFB\u53D6\u5B8C\u6210\u65F6\u8349\u7A3F\u5DF2\u53D8\u5316\uFF0C\u7ED3\u679C\u5DF2\u4E22\u5F03\u3002"
755
+ },
756
+ pasteFilePathHint: {
757
+ en: "file reference (path only, content not read): {0}",
758
+ zh: "\u6587\u4EF6\u5F15\u7528\uFF08\u4EC5\u8DEF\u5F84\uFF0C\u672A\u8BFB\u53D6\u5185\u5BB9\uFF09\uFF1A{0}"
759
+ },
760
+ mediaFoundHint: {
761
+ en: "\u{1F3A7} found media (will transcribe): {0}",
762
+ zh: "\u{1F3A7} \u8BC6\u522B\u5230\u97F3\u89C6\u9891\uFF08\u5C06\u8F6C\u5199\uFF09\uFF1A{0}"
763
+ },
764
+ mediaPreprocessStart: {
765
+ en: "\u{1F3A7} {0} preprocessing\u2026",
766
+ zh: "\u{1F3A7} {0} \u9884\u5904\u7406\u4E2D\u2026"
767
+ },
768
+ mediaTranscribeProgress: {
769
+ en: "\u{1F3A7} {0} transcribing\u2026 {1}",
770
+ zh: "\u{1F3A7} {0} \u8F6C\u5199\u4E2D\u2026 {1}"
771
+ },
772
+ mediaTranscribeDone: {
773
+ en: "\u{1F3A7} {0} transcribed \u2014 saved: {1}",
774
+ zh: "\u{1F3A7} {0} \u8F6C\u5199\u5B8C\u6210\u2014\u2014\u5DF2\u4FDD\u5B58\uFF1A{1}"
775
+ },
776
+ mediaTranscribeDoneAttach: {
777
+ en: "\u{1F3A7} {0} transcribed \u2014 txt: {1}\n srt: {2}\n transcript will be attached to your next message.",
778
+ zh: "\u{1F3A7} {0} \u8F6C\u5199\u5B8C\u6210\u2014\u2014txt\uFF1A{1}\n srt\uFF1A{2}\n \u8F6C\u5199\u5185\u5BB9\u5C06\u968F\u4F60\u4E0B\u4E00\u6761\u6D88\u606F\u53D1\u9001\u7ED9\u6A21\u578B\u3002"
779
+ },
780
+ mediaTranscribeFailed: {
781
+ en: "{0} transcription failed: {1}",
782
+ zh: "{0} \u8F6C\u5199\u5931\u8D25\uFF1A{1}"
783
+ },
784
+ mediaSilenceTrimScanning: {
785
+ en: "\u{1F3A7} {0} checking for trailing silence\u2026",
786
+ zh: "\u{1F3A7} {0} \u68C0\u67E5\u5C3E\u90E8\u9759\u97F3\u2026"
787
+ },
788
+ mediaSilenceTrimNotice: {
789
+ en: "\u{1F3A7} {0}: about {1} min of trailing silence \u2014 suggesting cut to {2} (saves ~{1} min).",
790
+ zh: "\u{1F3A7} {0}\uFF1A\u5C3E\u90E8\u7EA6 {1} \u5206\u949F\u57FA\u672C\u65E0\u4EBA\u58F0\uFF0C\u5EFA\u8BAE\u622A\u5230 {2}\uFF08\u53EF\u7701\u7EA6 {1} \u5206\u949F\uFF09\u3002"
791
+ },
792
+ mediaSilenceTrimTitle: {
793
+ en: "Transcribe range \u2014 trailing silence detected",
794
+ zh: "\u8F6C\u5199\u8303\u56F4\u2014\u2014\u68C0\u6D4B\u5230\u5C3E\u90E8\u9759\u97F3"
795
+ },
796
+ mediaSilenceTrimDetail: {
797
+ en: "Suggestion: keep everything before {0} (saves ~{1} min of upload/transcription).",
798
+ zh: "\u5EFA\u8BAE\uFF1A\u53EA\u5904\u7406 {0} \u4E4B\u524D\u7684\u5185\u5BB9\uFF08\u7701\u7EA6 {1} \u5206\u949F\u7684\u9884\u5904\u7406\u4E0E\u8F6C\u5199\uFF09\u3002"
799
+ },
800
+ mediaSilenceTrimOptionAll: {
801
+ en: "Transcribe everything",
802
+ zh: "\u5168\u90E8\uFF08\u4E0D\u88C1\u526A\uFF09"
803
+ },
804
+ mediaSilenceTrimOptionTrim: {
805
+ en: "Follow the suggestion: cut to {0} (saves ~{1} min)",
806
+ zh: "\u6309\u5EFA\u8BAE\uFF1A\u622A\u5230 {0}\uFF08\u7701\u7EA6 {1} \u5206\u949F\uFF09"
807
+ },
808
+ mediaSilenceTrimApplied: {
809
+ en: "\u{1F3A7} following the suggestion \u2014 transcribing up to {0}.",
810
+ zh: "\u{1F3A7} \u5DF2\u6309\u5EFA\u8BAE\u88C1\u526A\u2014\u2014\u53EA\u8F6C\u5199 {0} \u4E4B\u524D\u7684\u5185\u5BB9\u3002"
811
+ },
812
+ mediaSilenceTrimHintOnly: {
813
+ en: "\u{1F3A7} keeping the full file (can't ask right now). To trim, rerun /transcribe with --to {0}.",
814
+ zh: "\u{1F3A7} \u5F53\u524D\u65E0\u6CD5\u4EA4\u4E92\uFF0C\u6309\u5168\u7247\u8F6C\u5199\uFF1B\u5982\u9700\u88C1\u526A\uFF0C\u8BF7\u7528 --to {0} \u91CD\u8DD1 /transcribe\u3002"
815
+ },
816
+ transcribeUsage: {
817
+ en: "Usage: /transcribe <path> [--from ss|mm:ss|hh:mm:ss] [--to ss|mm:ss|hh:mm:ss] [--lang zh|en|...] [--denoise off|light|strong]",
818
+ zh: "\u7528\u6CD5\uFF1A/transcribe <\u8DEF\u5F84> [--from \u79D2|\u5206:\u79D2|\u65F6:\u5206:\u79D2] [--to \u79D2|\u5206:\u79D2|\u65F6:\u5206:\u79D2] [--lang zh|en|...] [--denoise off|light|strong]"
819
+ },
820
+ transcribeArgError: {
821
+ en: "Invalid /transcribe argument: {0}",
822
+ zh: "/transcribe \u53C2\u6570\u9519\u8BEF\uFF1A{0}"
823
+ },
824
+ transcribeNotMedia: {
825
+ en: "Not a media file: {0}",
826
+ zh: "\u4E0D\u662F\u97F3\u89C6\u9891\u6587\u4EF6\uFF1A{0}"
827
+ },
828
+ transcribeBusyHint: {
829
+ en: "/transcribe is unavailable while a reply is running \u2014 it attaches to your next message. Wait for the reply to finish, then run it.",
830
+ zh: "\u56DE\u590D\u8FDB\u884C\u4E2D\u4E0D\u80FD\u6267\u884C /transcribe\u2014\u2014\u8F6C\u5199\u4EA7\u7269\u8981\u968F\u4E0B\u4E00\u6761\u6D88\u606F\u53D1\u9001\u3002\u7B49\u672C\u8F6E\u56DE\u590D\u7ED3\u675F\u540E\u518D\u6267\u884C\u3002"
831
+ },
832
+ busyAttachmentsBlocked: {
833
+ en: "can't queue a message with {0} clipboard image(s) while a turn is running \u2014 draft kept. Send again after this turn ends, or press Backspace to drop the attachment and send text only.",
834
+ zh: "\u5FD9\u788C\u4E2D\u65E0\u6CD5\u6392\u961F\u5E26 {0} \u5F20\u526A\u8D34\u677F\u56FE\u7247\u7684\u6D88\u606F\uFF0C\u8349\u7A3F\u5DF2\u4FDD\u7559\uFF1B\u7B49\u672C\u8F6E\u7ED3\u675F\u540E\u518D\u6309 Enter \u53D1\u9001\uFF0C\u6216 Backspace \u64A4\u9500\u9644\u4EF6\u540E\u6539\u53D1\u7EAF\u6587\u5B57\u3002"
835
+ },
836
+ agentsTip: {
837
+ en: "Tip: run /switch for the full picker, or /switch list for your private agents too.",
838
+ zh: "\u63D0\u793A\uFF1A\u7528 /switch \u6253\u5F00\u5B8C\u6574\u9009\u62E9\u5668\uFF0C\u6216 /switch list \u8FDE\u4F60\u7684\u79C1\u6709\u667A\u80FD\u4F53\u4E00\u8D77\u5217\u51FA\u3002"
839
+ },
840
+ helpText: {
841
+ en: [
842
+ "Commands:",
843
+ " /help Show this help",
844
+ " /new Clear screen and start a fresh dialog",
845
+ " /compact Compact current dialog and fork a new one",
846
+ " /context Show workspace context and next actions",
847
+ " /cd <path> Change the working directory (takes effect on the next turn)",
848
+ " /runtime <mode> Use auto, local, or server runtime",
849
+ " /switch Pick an agent interactively (\u2191\u2193, Enter)",
850
+ " /switch list List agents as text",
851
+ " /switch <name> Switch directly by name, alias, or key (alias: /agent)",
852
+ " /agents List platform agent shortcuts",
853
+ " /history Pick a recent dialog to resume (\u2191\u2193, Enter)",
854
+ " /resume <dialogId> Resume a dialog directly by id",
855
+ " /lang <zh|en> Switch interface language",
856
+ ' /copy [all] Copy the last reply (or the full conversation with "all") to the clipboard',
857
+ " /paste Read the clipboard now (image \u2192 attachment, text \u2192 draft)",
858
+ " /transcribe <media> Transcribe an audio/video file; transcript attaches to your next message",
859
+ " Drag a file in Drop an image file on the terminal to attach it; audio/video transcribes; other files stay paths",
860
+ " Shift+Enter / Ctrl+J Insert a newline in the draft",
861
+ " /mouse <on|off> Toggle mouse mode (off = drag to select text)",
862
+ " /auto <on|off> Toggle permission auto-approve (skip destructive-shell, external-file & file-write confirms)",
863
+ " /shell-revoke Revoke this session's shell grant; the next shell call re-asks (works while a reply runs; does not interrupt a running command)",
864
+ " /math <on|off> Toggle math formula rendering (Unicode transcription)",
865
+ " /altscreen <on|off> Toggle the terminal alternate screen (default on; off shares shell scrollback)",
866
+ " Shift+drag Select text natively even while mouse mode is on (terminal bypass)",
867
+ " /doc List attached docs",
868
+ " /doc attach <doc> Attach a doc to this workspace",
869
+ " /skill List attached skills",
870
+ " /skill attach <ref> Attach a skill (dbKey, name, or SKILL.md path)",
871
+ " /skill detach <ref> Detach a skill",
872
+ " /skill clear Detach all skills",
873
+ " /customize Describe how you want to tune nolo",
874
+ " /tasks List background process tasks (aliases: /jobs, /procs)",
875
+ " /stop <pid|all> Stop background process tasks",
876
+ " /login Show login/profile hint (/login --server <url> to log in here)",
877
+ " /profile Show active profile",
878
+ " /update Update the nolo CLI install",
879
+ " /version Show version/update hint",
880
+ " /logs Show recent diagnostics and the log file path",
881
+ " /learn Review this dialog for reusable tool/prompt improvements",
882
+ " /learn <1-100> Triage recent Evolution candidates and deep-review one",
883
+ " /exit Leave the workspace",
884
+ "",
885
+ "You can also type normally. nolo routes simple read/status requests to CLI commands and sends the rest to the current agent."
886
+ ].join("\n"),
887
+ zh: [
888
+ "\u547D\u4EE4\uFF1A",
889
+ " /help \u663E\u793A\u672C\u5E2E\u52A9",
890
+ " /new \u6E05\u5C4F\u5E76\u5F00\u59CB\u65B0\u5BF9\u8BDD",
891
+ " /compact \u538B\u7F29\u5F53\u524D\u5BF9\u8BDD\u5E76\u5206\u53C9\u51FA\u65B0\u5BF9\u8BDD",
892
+ " /context \u67E5\u770B\u5DE5\u4F5C\u533A\u4E0A\u4E0B\u6587\u4E0E\u540E\u7EED\u64CD\u4F5C",
893
+ " /cd <path> \u5207\u6362\u5DE5\u4F5C\u76EE\u5F55\uFF08\u4E0B\u4E2A turn \u751F\u6548\uFF09",
894
+ " /runtime <mode> \u5207\u6362 runtime\uFF1Aauto\u3001local\u3001server",
895
+ " /switch \u4EA4\u4E92\u5F0F\u9009\u62E9 agent\uFF08\u2191\u2193 \u79FB\u52A8\uFF0CEnter \u786E\u8BA4\uFF09",
896
+ " /switch list \u4EE5\u6587\u672C\u5217\u51FA\u5168\u90E8 agent",
897
+ " /switch <name> \u6309\u540D\u79F0\u3001\u522B\u540D\u6216 key \u76F4\u63A5\u5207\u6362\uFF08\u522B\u540D\uFF1A/agent\uFF09",
898
+ " /agents \u5217\u51FA\u5E73\u53F0 agent \u5FEB\u6377\u65B9\u5F0F",
899
+ " /history \u4ECE\u6700\u8FD1\u5BF9\u8BDD\u4E2D\u9009\u62E9\u5E76\u6062\u590D\uFF08\u2191\u2193\uFF0CEnter\uFF09",
900
+ " /resume <dialogId> \u6309 id \u76F4\u63A5\u6062\u590D\u5BF9\u8BDD",
901
+ " /lang <zh|en> \u5207\u6362\u754C\u9762\u8BED\u8A00",
902
+ " /copy [all] \u590D\u5236\u6700\u540E\u4E00\u6761\u56DE\u590D\u5230\u526A\u8D34\u677F\uFF08\u52A0 all \u590D\u5236\u5B8C\u6574\u5BF9\u8BDD\uFF09",
903
+ " /paste \u7ACB\u5373\u8BFB\u526A\u8D34\u677F\uFF08\u56FE\u7247\u2192\u9644\u4EF6\uFF0C\u6587\u672C\u2192\u8349\u7A3F\uFF09",
904
+ " /transcribe <\u5A92\u4F53> \u8F6C\u5199\u97F3\u89C6\u9891\u6587\u4EF6\uFF1B\u8F6C\u5199\u6587\u672C\u968F\u4E0B\u4E00\u6761\u6D88\u606F\u53D1\u7ED9\u6A21\u578B",
905
+ " \u62D6\u5165\u6587\u4EF6 \u628A\u56FE\u7247\u6587\u4EF6\u62D6\u8FDB\u7EC8\u7AEF\u5373\u6210\u4E3A\u9644\u4EF6\uFF1B\u97F3\u89C6\u9891\u81EA\u52A8\u8F6C\u5199\uFF1B\u5176\u4ED6\u6587\u4EF6\u53EA\u7559\u8DEF\u5F84",
906
+ " Shift+Enter / Ctrl+J \u5728\u8349\u7A3F\u91CC\u6362\u884C",
907
+ " /mouse <on|off> \u5207\u6362\u9F20\u6807\u6A21\u5F0F\uFF08off \u540E\u53EF\u76F4\u63A5\u62D6\u9009\u6587\u672C\uFF09",
908
+ " /auto <on|off> \u5207\u6362\u6743\u9650\u81EA\u52A8\u5316\uFF08\u81EA\u52A8\u653E\u884C\u7834\u574F\u6027 shell\u3001\u5916\u90E8\u6587\u4EF6\u4E0E\u5199\u6587\u4EF6\u786E\u8BA4\uFF09",
909
+ " /shell-revoke \u64A4\u9500\u672C\u4F1A\u8BDD\u7684 shell \u6267\u884C\u6388\u6743\uFF0C\u4E0B\u4E00\u6B21 shell \u8C03\u7528\u91CD\u65B0\u786E\u8BA4\uFF08\u56DE\u590D\u8FDB\u884C\u4E2D\u4E5F\u53EF\u7528\uFF1B\u4E0D\u4E2D\u65AD\u5DF2\u653E\u884C\u7684\u547D\u4EE4\uFF09",
910
+ " /math <on|off> \u5207\u6362\u6570\u5B66\u516C\u5F0F\u6E32\u67D3\uFF08Unicode \u8F6C\u5199\uFF09",
911
+ " /altscreen <on|off> \u5207\u6362\u7EC8\u7AEF\u5907\u7528\u5C4F\uFF08\u9ED8\u8BA4 on\uFF1Boff \u6539\u4E3A\u4E0E shell \u5171\u7528\u56DE\u6EDA\uFF09",
912
+ " Shift+\u62D6\u62FD \u9F20\u6807\u6A21\u5F0F\u5F00\u542F\u65F6\u4E5F\u53EF\u539F\u751F\u9009\u4E2D\u6587\u672C\uFF08\u7EC8\u7AEF\u7ED5\u8FC7\u4FEE\u9970\u952E\uFF09",
913
+ " /doc \u5217\u51FA\u5DF2\u6302\u8F7D\u7684\u6587\u6863",
914
+ " /doc attach <doc> \u6302\u8F7D\u6587\u6863\u5230\u5F53\u524D\u5DE5\u4F5C\u533A",
915
+ " /skill \u5217\u51FA\u5DF2\u6302\u8F7D\u7684\u6280\u80FD",
916
+ " /skill attach <ref> \u6302\u8F7D\u6280\u80FD\uFF08dbKey\u3001\u540D\u79F0\u6216 SKILL.md \u8DEF\u5F84\uFF09",
917
+ " /skill detach <ref> \u5378\u8F7D\u6307\u5B9A\u6280\u80FD",
918
+ " /skill clear \u5378\u8F7D\u5168\u90E8\u6280\u80FD",
919
+ " /customize \u63CF\u8FF0\u4F60\u60F3\u600E\u4E48\u8C03\u6559 nolo",
920
+ " /tasks \u5217\u51FA\u540E\u53F0\u5B50\u8FDB\u7A0B\u4EFB\u52A1\uFF08\u522B\u540D\uFF1A/jobs, /procs\uFF09",
921
+ " /stop <pid|all> \u505C\u6B62\u6307\u5B9A\u7684\u540E\u53F0\u4EFB\u52A1",
922
+ " /login \u67E5\u770B\u767B\u5F55 / \u914D\u7F6E\u63D0\u793A\uFF08/login --server <url> \u53EF\u5728\u672C\u4F1A\u8BDD\u5185\u767B\u5F55\uFF09",
923
+ " /profile \u67E5\u770B\u5F53\u524D\u914D\u7F6E\u73AF\u5883",
924
+ " /update \u66F4\u65B0 nolo CLI",
925
+ " /version \u67E5\u770B\u7248\u672C\u4E0E\u66F4\u65B0\u63D0\u793A",
926
+ " /logs \u67E5\u770B\u6700\u8FD1\u8BCA\u65AD\u8BB0\u5F55\u4E0E\u65E5\u5FD7\u6587\u4EF6\u4F4D\u7F6E",
927
+ " /learn \u4ECE\u5F53\u524D\u5BF9\u8BDD\u590D\u76D8\u53EF\u590D\u7528\u7684\u5DE5\u5177/\u63D0\u793A\u8BCD\u6539\u8FDB",
928
+ " /learn <1-100> \u7B5B\u9009\u8FD1\u671F Evolution Candidate \u5E76\u6DF1\u5EA6\u590D\u76D8\u4E00\u6761",
929
+ " /exit \u9000\u51FA\u5DE5\u4F5C\u533A",
930
+ "",
931
+ "\u4E5F\u53EF\u4EE5\u76F4\u63A5\u8F93\u5165\u81EA\u7136\u8BED\u8A00\u3002\u7B80\u5355\u7684\u8BFB\u53D6/\u72B6\u6001\u8BF7\u6C42\u4F1A\u8D70 CLI \u547D\u4EE4\uFF0C\u5176\u4F59\u4EA4\u7ED9\u5F53\u524D agent\u3002"
932
+ ].join("\n")
933
+ },
934
+ // --- Slash-command output ---------------------------------------------
935
+ // Command results that used to be hardcoded English. Usage lines keep the
936
+ // command literal untouched; only the surrounding words are translated.
937
+ unknownCommand: {
938
+ en: "Unknown command: {0}\n\n",
939
+ zh: "\u672A\u77E5\u547D\u4EE4\uFF1A{0}\n\n"
940
+ },
941
+ noConversationLinks: {
942
+ en: "No links in this conversation yet.",
943
+ zh: "\u672C\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u51FA\u73B0\u94FE\u63A5\u3002"
944
+ },
945
+ conversationLinksCopyHint: {
946
+ en: "Open one by copying its URL (Cmd/Ctrl + click, or select and copy).",
947
+ zh: "\u590D\u5236\u5BF9\u5E94 URL \u5373\u53EF\u6253\u5F00\uFF08Cmd/Ctrl + \u70B9\u51FB\uFF0C\u6216\u9009\u4E2D\u590D\u5236\uFF09\u3002"
948
+ },
949
+ conversationLinksShowing: {
950
+ en: "Links in this conversation (showing first {0} of {1}):",
951
+ zh: "\u672C\u4F1A\u8BDD\u51FA\u73B0\u7684\u94FE\u63A5\uFF08\u663E\u793A\u524D {0} \u4E2A\uFF0C\u5171 {1} \u4E2A\uFF09\uFF1A"
952
+ },
953
+ runtimeUsage: { en: "Usage: /runtime <auto|local|server>", zh: "\u7528\u6CD5\uFF1A/runtime <auto|local|server>" },
954
+ runtimeSet: { en: "Runtime: {0}", zh: "\u8FD0\u884C\u6A21\u5F0F\uFF1A{0}" },
955
+ logsEmpty: {
956
+ en: "No diagnostics recorded in this session.",
957
+ zh: "\u672C\u6B21\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u8BCA\u65AD\u8BB0\u5F55\u3002"
958
+ },
959
+ logsHeader: {
960
+ en: "Recent diagnostics ({0} of {1}) \xB7 full log: {2}",
961
+ zh: "\u6700\u8FD1\u8BCA\u65AD\uFF08{0}/{1} \u6761\uFF09\xB7 \u5B8C\u6574\u65E5\u5FD7\uFF1A{2}"
962
+ },
963
+ tasksRunning: { en: "Running processes ({0}):", zh: "\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\uFF08{0}\uFF09\uFF1A" },
964
+ tasksStopped: { en: "Stopped/exited ({0}):", zh: "\u5DF2\u505C\u6B62/\u5DF2\u9000\u51FA\uFF08{0}\uFF09\uFF1A" },
965
+ tasksNone: { en: "No processes.", zh: "\u6CA1\u6709\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\u3002" },
966
+ stopUsage: { en: "Usage: /stop <pid|label|all>", zh: "\u7528\u6CD5\uFF1A/stop <pid|label|all>" },
967
+ stopAllDone: { en: "Stopped {0} processes", zh: "\u5DF2\u505C\u6B62 {0} \u4E2A\u8FDB\u7A0B" },
968
+ stopNoPid: { en: "No running process with pid {0}", zh: "\u6CA1\u6709 pid \u4E3A {0} \u7684\u8FD0\u884C\u4E2D\u8FDB\u7A0B" },
969
+ stopPidDone: { en: "Stopped pid {0} ({1})", zh: "\u5DF2\u505C\u6B62 pid {0}\uFF08{1}\uFF09" },
970
+ stopNoLabel: { en: "No running process labeled '{0}'", zh: "\u6CA1\u6709\u540D\u4E3A\u201C{0}\u201D\u7684\u8FD0\u884C\u4E2D\u8FDB\u7A0B" },
971
+ stopLabelsDone: { en: "Stopped {0}", zh: "\u5DF2\u505C\u6B62 {0}" },
972
+ compactNothing: {
973
+ en: "Current dialog: new (nothing to compact yet)",
974
+ zh: "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u662F\u65B0\u7684\uFF08\u8FD8\u6CA1\u6709\u53EF\u538B\u7F29\u7684\u5185\u5BB9\uFF09"
975
+ },
976
+ compactingDialog: {
977
+ en: "Compacting current dialog...",
978
+ zh: "\u6B63\u5728\u538B\u7F29\u5F53\u524D\u5BF9\u8BDD\u2026"
979
+ },
980
+ compactPhaseReading: {
981
+ en: "Reading dialog messages\u2026",
982
+ zh: "\u6B63\u5728\u8BFB\u53D6\u5BF9\u8BDD\u6D88\u606F\u2026"
983
+ },
984
+ compactPhaseSummarizing: {
985
+ en: "Generating summary\u2026",
986
+ zh: "\u6B63\u5728\u751F\u6210\u603B\u7ED3\u2026"
987
+ },
988
+ compactPhaseForking: {
989
+ en: "Forking dialog\u2026",
990
+ zh: "\u6B63\u5728\u5206\u53C9\u65B0\u5BF9\u8BDD\u2026"
991
+ },
992
+ compactFailed: {
993
+ en: "Compact failed: {0}",
994
+ zh: "\u538B\u7F29\u5931\u8D25\uFF1A{0}"
995
+ },
996
+ contextLengthExceeded: {
997
+ en: "Model context limit reached (requested {0} tokens / limit {1}). Suggest using /compact to compact current dialog, or /new to start a fresh dialog.",
998
+ zh: "\u5DF2\u8FBE\u6A21\u578B\u4E0A\u4E0B\u6587\u4E0A\u9650\uFF08\u8BF7\u6C42 {0} tokens / \u4E0A\u9650 {1}\uFF09\u3002\u5EFA\u8BAE\u4F7F\u7528 /compact \u538B\u7F29\u5F53\u524D\u5BF9\u8BDD\uFF0C\u6216\u4F7F\u7528 /new \u5F00\u59CB\u65B0\u5BF9\u8BDD\u3002"
999
+ },
1000
+ contextLengthExceededLimitOnly: {
1001
+ en: "Model context limit reached (limit {0}). Suggest using /compact to compact current dialog, or /new to start a fresh dialog.",
1002
+ zh: "\u5DF2\u8FBE\u6A21\u578B\u4E0A\u4E0B\u6587\u4E0A\u9650\uFF08\u4E0A\u9650 {0}\uFF09\u3002\u5EFA\u8BAE\u4F7F\u7528 /compact \u538B\u7F29\u5F53\u524D\u5BF9\u8BDD\uFF0C\u6216\u4F7F\u7528 /new \u5F00\u59CB\u65B0\u5BF9\u8BDD\u3002"
1003
+ },
1004
+ contextLengthExceededGeneric: {
1005
+ en: "Model context limit reached. Suggest using /compact to compact current dialog, or /new to start a fresh dialog.",
1006
+ zh: "\u5DF2\u8FBE\u6A21\u578B\u4E0A\u4E0B\u6587\u4E0A\u9650\u3002\u5EFA\u8BAE\u4F7F\u7528 /compact \u538B\u7F29\u5F53\u524D\u5BF9\u8BDD\uFF0C\u6216\u4F7F\u7528 /new \u5F00\u59CB\u65B0\u5BF9\u8BDD\u3002"
1007
+ },
1008
+ compactDone: {
1009
+ en: "Compacted dialog {0} \u2192 {1}.",
1010
+ zh: "\u5DF2\u538B\u7F29\u5BF9\u8BDD {0} \u2192 {1}\u3002"
1011
+ },
1012
+ compactDoneNoSummary: {
1013
+ en: "Forked dialog {0} \u2192 {1} (no summary needed).",
1014
+ zh: "\u5DF2\u5206\u53C9\u5BF9\u8BDD {0} \u2192 {1}\uFF08\u65E0\u9700\u538B\u7F29\uFF09\u3002"
1015
+ },
1016
+ compactSuccess: {
1017
+ en: "\u2713 Compacted dialog {0} \u2192 {1} in {2}.",
1018
+ zh: "\u2713 \u5DF2\u538B\u7F29\u5BF9\u8BDD {0} \u2192 {1}\uFF0C\u8017\u65F6 {2}\u3002"
1019
+ },
1020
+ compactSuccessWithCount: {
1021
+ en: "\u2713 Compacted dialog {0} \u2192 {1} in {2} ({3} messages compressed).",
1022
+ zh: "\u2713 \u5DF2\u538B\u7F29\u5BF9\u8BDD {0} \u2192 {1}\uFF0C\u8017\u65F6 {2}\uFF08\u538B\u7F29 {3} \u6761\u6D88\u606F\uFF09\u3002"
1023
+ },
1024
+ compactForked: {
1025
+ en: "\u2713 Forked dialog {0} \u2192 {1} in {2} (no summary needed).",
1026
+ zh: "\u2713 \u5DF2\u5206\u53C9\u5BF9\u8BDD {0} \u2192 {1}\uFF0C\u8017\u65F6 {2}\uFF08\u65E0\u9700\u538B\u7F29\uFF09\u3002"
1027
+ },
1028
+ agentCurrent: { en: "Current agent: {0} ({1})", zh: "\u5F53\u524D agent\uFF1A{0}\uFF08{1}\uFF09" },
1029
+ agentPinnedUnaudited: {
1030
+ en: "No audit record for it \u2014 an older build wrote it; see agent-selection.log.",
1031
+ zh: "\u8FD9\u6761\u8BB0\u5F55\u6CA1\u6709\u5BA1\u8BA1\u8BB0\u5F55\uFF0C\u662F\u65E7\u7248\u672C\u5199\u7684\uFF1B\u8BE6\u89C1 agent-selection.log\u3002"
1032
+ },
1033
+ agentPinnedAuditRotated: {
1034
+ en: "The audit log has no entry for it \u2014 it aged out, or another session wrote it.",
1035
+ zh: "\u5BA1\u8BA1\u65E5\u5FD7\u91CC\u6CA1\u6709\u5B83\u7684\u8BB0\u5F55\u2014\u2014\u53EF\u80FD\u5DF2\u88AB\u8F6E\u8F6C\uFF0C\u6216\u662F\u522B\u7684\u4F1A\u8BDD\u5199\u7684\u3002"
1036
+ },
1037
+ agentPinnedFromProfile: {
1038
+ en: 'Agent "{0}" restored from {1} (saved selection). /switch nolo to go back to the default.',
1039
+ zh: "agent\u201C{0}\u201D\u6765\u81EA {1} \u91CC\u4FDD\u5B58\u7684\u9009\u62E9\u3002/switch nolo \u53EF\u5207\u56DE\u9ED8\u8BA4\u6863\u3002"
1040
+ },
1041
+ agentUnknown: {
1042
+ en: `I don't know agent "{0}" yet.
1043
+ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`,
1044
+ zh: "\u8FD8\u4E0D\u8BA4\u8BC6 agent\u201C{0}\u201D\u3002\n\u53EF\u4EE5\u7528 /switch\u3001/switch list\u3001/switch minimax-m3 \u6216\u5B8C\u6574\u7684 agent key \u6765\u5207\u6362\u3002"
1045
+ },
1046
+ themeCurrent: { en: "Current theme: {0} \xB7 {1}", zh: "\u5F53\u524D\u4E3B\u9898\uFF1A{0} \xB7 {1}" },
1047
+ themeUsage: {
1048
+ en: "Usage: /theme <name> | /theme terminal | /theme light | /theme dark | /theme refresh",
1049
+ zh: "\u7528\u6CD5\uFF1A/theme <name> | /theme terminal | /theme light | /theme dark | /theme refresh"
1050
+ },
1051
+ themeAvailable: { en: "Available themes: {0}", zh: "\u53EF\u7528\u4E3B\u9898\uFF1A{0}" },
1052
+ themeBrightnessSwitched: { en: "Switched to {0} background colors.", zh: "\u5DF2\u5207\u6362\u5230 {0} \u80CC\u666F\u8272\u3002" },
1053
+ themeBrightnessAuto: {
1054
+ en: "Theme now follows terminal colors (/theme auto is an alias).",
1055
+ zh: "\u4E3B\u9898\u5DF2\u8DDF\u968F\u7EC8\u7AEF\u914D\u8272\uFF08/theme auto \u4E3A\u517C\u5BB9\u522B\u540D\uFF09\u3002"
1056
+ },
1057
+ themeRefreshed: {
1058
+ en: "Re-detected terminal background: {0}.",
1059
+ zh: "\u5DF2\u91CD\u65B0\u68C0\u6D4B\u7EC8\u7AEF\u80CC\u666F\uFF1A{0}\u3002"
1060
+ },
1061
+ themeRefreshFailed: {
1062
+ en: "Could not detect terminal background (not a TTY or no response).",
1063
+ zh: "\u65E0\u6CD5\u68C0\u6D4B\u7EC8\u7AEF\u80CC\u666F\uFF08\u975E TTY \u6216\u7EC8\u7AEF\u65E0\u54CD\u5E94\uFF09\u3002"
1064
+ },
1065
+ themeSwitched: { en: "Switched to theme: {0}", zh: "\u5DF2\u5207\u6362\u5230\u4E3B\u9898\uFF1A{0}" },
1066
+ themeUnknown: { en: "Unknown theme: {0}. Available themes: {1}", zh: "\u672A\u77E5\u4E3B\u9898\uFF1A{0}\u3002\u53EF\u7528\u4E3B\u9898\uFF1A{1}" },
1067
+ cdUsage: {
1068
+ en: "Usage: /cd <path> (relative, absolute, ~, or -; takes effect on the next turn)",
1069
+ zh: "\u7528\u6CD5\uFF1A/cd <path>\uFF08\u76F8\u5BF9\u3001\u7EDD\u5BF9\u3001~ \u6216 - \u8DEF\u5F84\uFF1B\u4E0B\u4E2A turn \u751F\u6548\uFF09"
1070
+ },
1071
+ cdCurrent: { en: "Current directory: {0}", zh: "\u5F53\u524D\u76EE\u5F55\uFF1A{0}" },
1072
+ cdSwitched: { en: "Working directory: {0}", zh: "\u5DE5\u4F5C\u76EE\u5F55\uFF1A{0}" },
1073
+ cdNotFound: { en: "Directory not found: {0}", zh: "\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A{0}" },
1074
+ cdNotDir: { en: "Not a directory: {0}", zh: "\u4E0D\u662F\u76EE\u5F55\uFF1A{0}" },
1075
+ cdNoPrevious: { en: "No previous directory.", zh: "\u6CA1\u6709\u4E0A\u4E00\u4E2A\u76EE\u5F55\u3002" },
1076
+ cdSwitchedMessage: {
1077
+ en: "Working directory changed: {0} \u2192 {1}. Subsequent tool execution and file operations use the new directory.",
1078
+ zh: "\u5DE5\u4F5C\u76EE\u5F55\u5DF2\u5207\u6362\uFF1A{0} \u2192 {1}\u3002\u540E\u7EED\u5DE5\u5177\u6267\u884C\u4E0E\u6587\u4EF6\u64CD\u4F5C\u4EE5\u65B0\u76EE\u5F55\u4E3A\u51C6\u3002"
1079
+ },
1080
+ docAttachUsage: { en: "Usage: /doc attach <doc>", zh: "\u7528\u6CD5\uFF1A/doc attach <doc>" },
1081
+ docList: { en: "Attached docs: {0}", zh: "\u5DF2\u6302\u8F7D\u6587\u6863\uFF1A{0}" },
1082
+ docNone: { en: "No docs attached. Use /doc attach <doc>.", zh: "\u8FD8\u6CA1\u6709\u6302\u8F7D\u6587\u6863\u3002\u7528 /doc attach <doc> \u6302\u8F7D\u3002" },
1083
+ skillAttachUsage: { en: "Usage: /skill attach <skill-ref>", zh: "\u7528\u6CD5\uFF1A/skill attach <skill-ref>" },
1084
+ skillAttached: { en: "Attached skill: {0}", zh: "\u5DF2\u6302\u8F7D\u6280\u80FD\uFF1A{0}" },
1085
+ skillDetachUsage: { en: "Usage: /skill detach <skill-ref>", zh: "\u7528\u6CD5\uFF1A/skill detach <skill-ref>" },
1086
+ skillDetached: { en: "Detached skill: {0}", zh: "\u5DF2\u5378\u8F7D\u6280\u80FD\uFF1A{0}" },
1087
+ skillNotAttached: { en: "Skill not attached: {0}", zh: "\u6280\u80FD\u672A\u6302\u8F7D\uFF1A{0}" },
1088
+ skillNone: { en: "No skills attached.", zh: "\u8FD8\u6CA1\u6709\u6302\u8F7D\u6280\u80FD\u3002" },
1089
+ skillCleared: { en: "Cleared {0} skill(s).", zh: "\u5DF2\u6E05\u7A7A {0} \u4E2A\u6280\u80FD\u3002" },
1090
+ skillList: {
1091
+ en: "Attached skills: {0}\nUsage: /skill attach <ref> | /skill detach <ref> | /skill clear",
1092
+ zh: "\u5DF2\u6302\u8F7D\u6280\u80FD\uFF1A{0}\n\u7528\u6CD5\uFF1A/skill attach <ref> | /skill detach <ref> | /skill clear"
1093
+ },
1094
+ skillNoneHint: {
1095
+ en: "No skills attached. Use /skill attach <skill-ref> to attach a skill.\nSkill refs can be a dbKey (page-xxx), a skill name (searched in .agents/skills/), or a direct path.",
1096
+ zh: "\u8FD8\u6CA1\u6709\u6302\u8F7D\u6280\u80FD\u3002\u7528 /skill attach <skill-ref> \u6302\u8F7D\u6280\u80FD\u3002\n\u6280\u80FD\u5F15\u7528\u53EF\u4EE5\u662F dbKey\uFF08page-xxx\uFF09\u3001\u6280\u80FD\u540D\uFF08\u4F1A\u5728 .agents/skills/ \u4E2D\u67E5\u627E\uFF09\u6216\u76F4\u63A5\u8DEF\u5F84\u3002"
1097
+ },
1098
+ customizeHint: {
1099
+ en: "Tell nolo what to change, for example: /customize make my default agent more concise.",
1100
+ zh: "\u544A\u8BC9 nolo \u4F60\u60F3\u6539\u4EC0\u4E48\uFF0C\u4F8B\u5982\uFF1A/customize make my default agent more concise\u3002"
1101
+ },
1102
+ /** @deprecated No longer used by `/login` (now runs the in-TUI login flow). Kept to avoid structural churn. */
1103
+ loginHint: {
1104
+ en: "MVP login uses profile/env auth. Set AUTH_TOKEN, NOLO_SERVER, or NOLO_PROFILE before starting nolo.",
1105
+ zh: "MVP \u767B\u5F55\u8D70 profile/\u73AF\u5883\u53D8\u91CF\u8BA4\u8BC1\u3002\u542F\u52A8 nolo \u524D\u8BF7\u8BBE\u7F6E AUTH_TOKEN\u3001NOLO_SERVER \u6216 NOLO_PROFILE\u3002"
1106
+ },
1107
+ /** @deprecated No longer used by `/login` (now runs the in-TUI login flow). Kept to avoid structural churn. */
1108
+ loginTuiStart: {
1109
+ en: "Or run `/login --server <url>` to log in right here (opens a browser authorization URL), or exit and run `nolo login`.",
1110
+ zh: "\u4E5F\u53EF\u4EE5\u6267\u884C /login --server <url> \u76F4\u63A5\u5728\u8FD9\u91CC\u767B\u5F55\uFF08\u4F1A\u7ED9\u51FA\u6D4F\u89C8\u5668\u6388\u6743\u94FE\u63A5\uFF09\uFF0C\u6216\u9000\u51FA\u540E\u8FD0\u884C `nolo login`\u3002"
1111
+ },
1112
+ loginUsage: {
1113
+ en: "Usage: /login [--server <url>]. Unsupported flags: {0}",
1114
+ zh: "\u7528\u6CD5\uFF1A/login [--server <url>]\u3002\u4E0D\u652F\u6301\u7684\u53C2\u6570\uFF1A{0}"
1115
+ },
1116
+ loginStarted: {
1117
+ en: "Open this URL to authorize nolo-cli:\n{0}\nCode: {1}",
1118
+ zh: "\u6253\u5F00\u8FD9\u4E2A\u94FE\u63A5\u6388\u6743 nolo-cli\uFF1A\n{0}\n\u6388\u6743\u7801\uFF1A{1}"
1119
+ },
1120
+ loginBrowserFailed: {
1121
+ en: "Could not open a browser automatically. Paste the URL above into a browser.",
1122
+ zh: "\u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u628A\u4E0A\u9762\u7684\u94FE\u63A5\u7C98\u8D34\u5230\u6D4F\u89C8\u5668\u91CC\u3002"
1123
+ },
1124
+ loginWaiting: {
1125
+ en: "Waiting for browser authorization ({0} remaining)... (Ctrl+C to cancel)",
1126
+ zh: "\u7B49\u5F85\u6D4F\u89C8\u5668\u6388\u6743\uFF08\u5269\u4F59 {0}\uFF09\u2026\u2026\u6309 Ctrl+C \u53D6\u6D88"
1127
+ },
1128
+ loginStillWaiting: {
1129
+ en: "Still waiting... ({0} remaining)",
1130
+ zh: "\u4ECD\u5728\u7B49\u5F85\u2026\u2026\uFF08\u5269\u4F59 {0}\uFF09"
1131
+ },
1132
+ loginSuccess: {
1133
+ en: "Logged in. Token saved to profile; this session now uses it immediately.",
1134
+ zh: "\u767B\u5F55\u6210\u529F\u3002Token \u5DF2\u5199\u5165 profile\uFF0C\u5F53\u524D\u4F1A\u8BDD\u7ACB\u5373\u751F\u6548\u3002"
1135
+ },
1136
+ loginFailed: {
1137
+ en: "Login failed: {0}",
1138
+ zh: "\u767B\u5F55\u5931\u8D25\uFF1A{0}"
1139
+ },
1140
+ loginTimeout: {
1141
+ en: "Login timed out. Run /login again, or use `nolo login --token <jwt>` in a shell.",
1142
+ zh: "\u767B\u5F55\u8D85\u65F6\u3002\u8BF7\u91CD\u65B0\u6267\u884C /login\uFF0C\u6216\u5728 shell \u91CC\u7528 nolo login --token <jwt>\u3002"
1143
+ },
1144
+ loginCancelled: {
1145
+ en: "Login cancelled.",
1146
+ zh: "\u5DF2\u53D6\u6D88\u767B\u5F55\u3002"
1147
+ },
1148
+ welcomeAuthGuidance: {
1149
+ en: 'Not logged in to Nolo \u2014 three ways to get going:\n \xB7 Run a task on local Codex: nolo run "<task>" (no login needed)\n \xB7 Bind your own model subscription: nolo auth antigravity | claude | chatgpt | xai\n \xB7 Use the Nolo platform: type /login (gives you a browser authorization link)',
1150
+ zh: '\u672A\u767B\u5F55 Nolo \u2014\u2014 \u4E09\u6761\u8DEF\u90FD\u80FD\u7528\uFF1A\n \xB7 \u7528\u672C\u5730 Codex \u8DD1\u4EFB\u52A1\uFF1Anolo run "<\u4EFB\u52A1>"\uFF08\u4E0D\u9700\u8981\u767B\u5F55\uFF09\n \xB7 \u7ED1\u5B9A\u4F60\u81EA\u5DF1\u7684\u6A21\u578B\u8BA2\u9605\uFF1Anolo auth antigravity | claude | chatgpt | xai\n \xB7 \u7528 Nolo \u5E73\u53F0\uFF1A\u76F4\u63A5\u8F93\u5165 /login\uFF08\u4F1A\u7ED9\u51FA\u6D4F\u89C8\u5668\u6388\u6743\u94FE\u63A5\uFF09'
1151
+ },
1152
+ versionInfo: {
1153
+ en: "nolo {0}\nUpdate this install with: nolo update\nIf repo-local output differs, publish/install the latest npm package first.",
1154
+ zh: "nolo {0}\n\u7528 nolo update \u66F4\u65B0\u5F53\u524D\u5B89\u88C5\u3002\n\u5982\u679C\u672C\u5730\u4ED3\u5E93\u8F93\u51FA\u7684\u7248\u672C\u4E0D\u540C\uFF0C\u8BF7\u5148\u53D1\u5E03/\u5B89\u88C5\u6700\u65B0\u7684 npm \u5305\u3002"
1155
+ },
1156
+ versionUnknown: { en: "unknown version", zh: "\u672A\u77E5\u7248\u672C" },
1157
+ updateAvailable: {
1158
+ // 保持短:这行在窄终端物理换行会破坏 banner 重绘的行数计算。当前版本
1159
+ // 号上一行 version line 已有,不重复。
1160
+ en: "\u2191 nolo {0} available \u2014 /update to upgrade",
1161
+ zh: "\u2191 nolo {0} \u53EF\u7528 \u2014 /update \u5347\u7EA7"
1162
+ },
1163
+ // --- Dialog list / timestamps -----------------------------------------
1164
+ recentDialogs: { en: "Recent dialogs:", zh: "\u6700\u8FD1\u5BF9\u8BDD\uFF1A" },
1165
+ dialogListTip: {
1166
+ en: "Tip: run /history to pick one interactively, or paste an id after /resume.",
1167
+ zh: "\u63D0\u793A\uFF1A\u7528 /history \u4EA4\u4E92\u5F0F\u9009\u62E9\uFF0C\u6216\u628A id \u7C98\u5230 /resume \u540E\u9762\u3002"
1168
+ },
1169
+ timeJustNow: { en: "just now", zh: "\u521A\u521A" },
1170
+ timeMinutesAgo: { en: "{0}m ago", zh: "{0} \u5206\u949F\u524D" },
1171
+ timeHoursAgo: { en: "{0}h ago", zh: "{0} \u5C0F\u65F6\u524D" },
1172
+ timeDaysAgo: { en: "{0}d ago", zh: "{0} \u5929\u524D" },
1173
+ // Overflow hints shared by select / multi-select / ask-choice. The arrows
1174
+ // and count are part of the copy so each locale can order them naturally.
1175
+ dialogMoreAbove: { en: "\u2191 {0} more", zh: "\u2191 {0} \u66F4\u591A" },
1176
+ dialogMoreBelow: { en: "\u2193 {0} more", zh: "\u2193 {0} \u66F4\u591A" },
1177
+ // Action gate handoff
1178
+ actionGateNeeded: {
1179
+ en: "Action needed in your terminal",
1180
+ zh: "\u7EC8\u7AEF\u9700\u8981\u4F60\u7684\u64CD\u4F5C"
1181
+ },
1182
+ actionGateEnterHint: {
1183
+ en: "Press Enter to run it now. Follow any prompts below, or Ctrl+C to cancel.",
1184
+ zh: "\u6309 Enter \u7ACB\u5373\u6267\u884C\uFF0C\u6309\u4E0B\u65B9\u63D0\u793A\u64CD\u4F5C\uFF0C\u6216\u6309 Ctrl+C \u53D6\u6D88\u3002"
1185
+ },
1186
+ actionGateConfirmHint: { en: "Enter=approve, n=cancel (or type y/yes).", zh: "Enter=\u6279\u51C6\uFF0Cn=\u53D6\u6D88\uFF08\u4E5F\u53EF\u8F93\u5165 y/yes\uFF09\u3002" },
1187
+ actionGateInteractiveTitle: {
1188
+ en: "This command requires an interactive terminal.",
1189
+ zh: "\u8BE5\u547D\u4EE4\u9700\u8981\u4EA4\u4E92\u5F0F\u7EC8\u7AEF"
1190
+ },
1191
+ actionGateInteractiveBody: {
1192
+ en: "Complete it in the terminal, then nolo will continue.",
1193
+ zh: "\u5728\u7EC8\u7AEF\u4E2D\u5B8C\u6210\u64CD\u4F5C\u540E\uFF0Cnolo \u5C06\u7EE7\u7EED\u3002"
1194
+ },
1195
+ // Compact memory-tool trace
1196
+ memoryDeleteRequestedCount: {
1197
+ en: "requested deletion of {0}",
1198
+ zh: "\u5DF2\u8BF7\u6C42\u5220\u9664 {0} \u6761"
1199
+ },
1200
+ // Agent catalog sources
1201
+ agentSourcePlatform: {
1202
+ en: "Platform",
1203
+ zh: "\u5E73\u53F0"
1204
+ },
1205
+ agentSourceSubscription: {
1206
+ en: "Subscription",
1207
+ zh: "\u8BA2\u9605"
1208
+ },
1209
+ agentSourceApi: {
1210
+ en: "API",
1211
+ zh: "API"
1212
+ },
1213
+ // ── Non-TUI CLI output: shared command-group help ─────────────────────────
1214
+ // `nolo <group> --help` renders from the command registry; the frame lines
1215
+ // are localized here while per-command copy lives in cliCommandDescription().
1216
+ "cli.groupCommandsTitle": {
1217
+ en: "nolo {0} commands",
1218
+ zh: "nolo {0} \u547D\u4EE4"
1219
+ },
1220
+ "cli.usageLabel": {
1221
+ en: "Usage:",
1222
+ zh: "\u7528\u6CD5\uFF1A"
1223
+ },
1224
+ // ── Non-TUI CLI output: nolo auth ─────────────────────────────────────────
1225
+ // User-visible copy of `nolo auth <provider>`. Params follow each en string:
1226
+ // {0}=provider, {1}=server origin / saved account / raw detail,
1227
+ // {2}=zone or HTTP status, {3}=optional trailing fragment.
1228
+ "auth.authorizationSaved": {
1229
+ en: "[nolo] {0} authorization saved{1}.",
1230
+ zh: "[nolo] \u5DF2\u4FDD\u5B58 {0} \u6388\u6743{1}\u3002"
1231
+ },
1232
+ // Optional account suffix for authorizationSaved (empty when the provider
1233
+ // reports no account label).
1234
+ "auth.authorizationSavedForAccount": {
1235
+ en: " for {0}",
1236
+ zh: "\uFF08\u8D26\u53F7 {0}\uFF09"
1237
+ },
1238
+ "auth.noLocalCredential": {
1239
+ en: "[nolo] No local {0} credential. Run: nolo auth {0}",
1240
+ zh: "[nolo] \u672C\u5730\u6CA1\u6709 {0} \u51ED\u636E\u3002\u8BF7\u8FD0\u884C\uFF1Anolo auth {0}"
1241
+ },
1242
+ "auth.credentialServerManaged": {
1243
+ en: "[nolo] The {0} credential is already server-managed by {1} (no local refresh token).\nTo sync it again, run: nolo auth {0} --sync-to-server",
1244
+ zh: "[nolo] {0} \u51ED\u636E\u5DF2\u7531 {1} \u670D\u52A1\u7AEF\u6258\u7BA1\uFF08\u672C\u5730\u65E0 refreshToken\uFF09\u3002\n\u5982\u9700\u91CD\u65B0\u540C\u6B65\uFF0C\u8BF7\u8FD0\u884C: nolo auth {0} --sync-to-server"
1245
+ },
1246
+ "auth.verifyUnsupported": {
1247
+ en: '[nolo] --verify is only supported for "nolo auth antigravity".',
1248
+ zh: '[nolo] --verify \u4EC5\u652F\u6301 "nolo auth antigravity"\u3002'
1249
+ },
1250
+ "auth.checkingVerificationChallenge": {
1251
+ en: "[nolo] Checking the current verification challenge (one lightweight request)...",
1252
+ zh: "[nolo] \u6B63\u5728\u68C0\u67E5\u5F53\u524D\u9A8C\u8BC1\u6311\u6218\uFF08\u4E00\u6B21\u8F7B\u91CF\u8BF7\u6C42\uFF09\u2026"
1253
+ },
1254
+ "auth.refreshTokenInvalid": {
1255
+ en: "[nolo] The antigravity refresh token is no longer valid ({0}). Re-run `nolo auth antigravity` to re-authorize this account.",
1256
+ zh: "[nolo] antigravity \u7684 refresh token \u5DF2\u5931\u6548\uFF08{0}\uFF09\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C `nolo auth antigravity` \u91CD\u65B0\u6388\u6743\u8BE5\u8D26\u53F7\u3002"
1257
+ },
1258
+ "auth.credentialIncomplete": {
1259
+ en: "[nolo] The stored antigravity credential is incomplete ({0}). Re-run `nolo auth antigravity` to re-authorize.",
1260
+ zh: "[nolo] \u672C\u5730\u4FDD\u5B58\u7684 antigravity \u51ED\u636E\u4E0D\u5B8C\u6574\uFF08{0}\uFF09\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C `nolo auth antigravity` \u91CD\u65B0\u6388\u6743\u3002"
1261
+ },
1262
+ "auth.providerUnreachable": {
1263
+ en: "[nolo] Could not reach the antigravity provider: {0}. Check your network and retry.",
1264
+ zh: "[nolo] \u65E0\u6CD5\u8BBF\u95EE antigravity provider\uFF1A{0}\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u8BD5\u3002"
1265
+ },
1266
+ "auth.credentialWorking": {
1267
+ en: "[nolo] \u2713 The credential is working \u2014 no verification is required right now. You can retry your agent.",
1268
+ zh: "[nolo] \u2713 \u51ED\u636E\u53EF\u7528\u2014\u2014\u5F53\u524D\u65E0\u9700\u9A8C\u8BC1\u3002\u53EF\u4EE5\u91CD\u8BD5\u4F60\u7684 agent\u3002"
1269
+ },
1270
+ "auth.googleVerificationRequired": {
1271
+ en: "[nolo] Google requires a one-time account verification for {0}.",
1272
+ zh: "[nolo] Google \u9700\u8981\u5BF9 {0} \u505A\u4E00\u6B21\u6027\u8D26\u53F7\u9A8C\u8BC1\u3002"
1273
+ },
1274
+ "auth.verificationOpened": {
1275
+ en: "[nolo] \u2713 Opened it in your browser \u2014 complete the verification there (sign in with the same Google account), then retry your agent.",
1276
+ zh: "[nolo] \u2713 \u5DF2\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u2014\u2014\u8BF7\u5728\u90A3\u91CC\u5B8C\u6210\u9A8C\u8BC1\uFF08\u7528\u540C\u4E00\u4E2A Google \u8D26\u53F7\u767B\u5F55\uFF09\uFF0C\u7136\u540E\u91CD\u8BD5\u4F60\u7684 agent\u3002"
1277
+ },
1278
+ "auth.verificationCopyUrl": {
1279
+ en: "[nolo] Copy the URL above into a browser signed into {0}, complete the verification, then retry your agent.",
1280
+ zh: "[nolo] \u8BF7\u628A\u4E0A\u9762\u7684 URL \u590D\u5236\u5230\u5DF2\u767B\u5F55 {0} \u7684\u6D4F\u89C8\u5668\u4E2D\uFF0C\u5B8C\u6210\u9A8C\u8BC1\u540E\u91CD\u8BD5\u4F60\u7684 agent\u3002"
1281
+ },
1282
+ "auth.httpWithoutVerificationLink": {
1283
+ en: "[nolo] The provider returned HTTP {0} without a verification link \u2014 this is not the one-time-verification case --verify handles.{1} Response detail: {2}",
1284
+ zh: "[nolo] provider \u8FD4\u56DE HTTP {0}\uFF0C\u4F46\u6CA1\u6709\u4EFB\u4F55\u9A8C\u8BC1\u94FE\u63A5\u2014\u2014\u8FD9\u4E0D\u5C5E\u4E8E --verify \u5904\u7406\u7684\u4E00\u6B21\u6027\u9A8C\u8BC1\u573A\u666F\u3002{1}\u54CD\u5E94\u8BE6\u60C5\uFF1A{2}"
1285
+ },
1286
+ // Optional trailing fragment spliced into httpWithoutVerificationLink when a
1287
+ // token refresh also failed earlier. English keeps the leading space.
1288
+ "auth.httpWithoutVerificationLink.refreshSuffix": {
1289
+ en: " (token refresh also failed earlier: {0})",
1290
+ zh: "\uFF08\u6B64\u524D token \u5237\u65B0\u4E5F\u5931\u8D25\uFF1A{0}\uFF09"
1291
+ },
1292
+ "auth.localRefreshTokenDropped": {
1293
+ en: "[nolo] No local refresh token is kept: {0} is refreshed by {1} (fetched on demand).",
1294
+ zh: "[nolo] \u672C\u5730\u4E0D\u518D\u4FDD\u5B58 refresh token\uFF1A{0} \u7531 {1} \u7EDF\u4E00\u5237\u65B0\uFF08\u7528\u5B8C\u5373\u53D6\uFF09\u3002"
1295
+ },
1296
+ "auth.localStateUpdateFailed": {
1297
+ en: "[nolo] Warning: failed to update the local credential state ({0}).",
1298
+ zh: "[nolo] Warning: \u672C\u5730\u51ED\u636E\u72B6\u6001\u66F4\u65B0\u5931\u8D25\uFF08{0}\uFF09\u3002"
1299
+ },
1300
+ "auth.syncMissingConfig": {
1301
+ en: "[nolo] Warning: server sync needs NOLO_SERVER and AUTH_TOKEN env vars, or a configured profile. Skipping server sync.",
1302
+ zh: "[nolo] \u8B66\u544A\uFF1A\u670D\u52A1\u7AEF\u540C\u6B65\u9700\u8981 NOLO_SERVER \u548C AUTH_TOKEN \u73AF\u5883\u53D8\u91CF\uFF0C\u6216\u5DF2\u914D\u7F6E\u7684 profile\u3002\u5DF2\u8DF3\u8FC7\u540C\u6B65\u3002"
1303
+ },
1304
+ "auth.syncedTo": {
1305
+ en: "[nolo] Synced to {0}",
1306
+ zh: "[nolo] \u5DF2\u540C\u6B65\u5230 {0}"
1307
+ },
1308
+ "auth.syncDoneWebUsable": {
1309
+ en: "[nolo] The web app can now use this subscription.",
1310
+ zh: "[nolo] \u7F51\u9875\u7AEF\u73B0\u5728\u53EF\u4EE5\u4F7F\u7528\u8BE5\u8BA2\u9605\u4E86\u3002"
1311
+ },
1312
+ "auth.syncFailed": {
1313
+ en: "[nolo] Warning: server sync failed ({0}). Token saved locally.",
1314
+ zh: "[nolo] \u8B66\u544A\uFF1A\u670D\u52A1\u7AEF\u540C\u6B65\u5931\u8D25\uFF08{0}\uFF09\u3002Token \u5DF2\u4FDD\u5B58\u5728\u672C\u5730\u3002"
1315
+ },
1316
+ "auth.noServerConfigured": {
1317
+ en: "[nolo] No server configured. To use this on the web, run nolo login first, then nolo auth {0} --sync-only",
1318
+ zh: "[nolo] \u672A\u914D\u7F6E\u670D\u52A1\u5668\u3002\u5982\u9700\u5728\u7F51\u9875\u7AEF\u4F7F\u7528\uFF0C\u8BF7\u5148\u8FD0\u884C nolo login\uFF0C\u518D\u8FD0\u884C nolo auth {0} --sync-only"
1319
+ },
1320
+ // {1} is the provider name again so the --no-sync-to-server hint names the
1321
+ // exact command the user would run; keep [Y/n] as the literal answer hint.
1322
+ "auth.syncPrompt": {
1323
+ en: "Sync to {0} so the web app can also use this {1} subscription? The credential is stored encrypted; run nolo auth {1} --no-sync-to-server to turn it off later. [Y/n] ",
1324
+ zh: "\u540C\u6B65\u5230 {0}\uFF0C\u8BA9\u7F51\u9875\u7AEF\u4E5F\u80FD\u4F7F\u7528\u8FD9\u4E2A {1} \u8BA2\u9605\uFF1F\u51ED\u8BC1\u52A0\u5BC6\u5B58\u50A8\uFF0C\u53EF\u968F\u65F6 nolo auth {1} --no-sync-to-server \u5173\u95ED [Y/n] "
1325
+ },
1326
+ "auth.notSyncedToServer": {
1327
+ en: "[nolo] Not synced to the server. For web use, run: nolo auth {0} --sync-to-server (or --sync-only)",
1328
+ zh: "[nolo] \u672A\u540C\u6B65\u51ED\u636E\u5230\u670D\u52A1\u5668\u3002\u5982\u9700\u7F51\u9875\u7AEF\u4F7F\u7528\uFF0C\u8BF7\u8FD0\u884C: nolo auth {0} --sync-to-server\uFF08\u6216 --sync-only\uFF09"
1329
+ },
1330
+ "auth.markFailed": {
1331
+ en: "[nolo] The credential was uploaded to the server, but marking it server-managed locally failed. Re-authorize so both sides cannot race each other's refresh.",
1332
+ zh: "[nolo] \u51ED\u636E\u5DF2\u6210\u529F\u4E0A\u4F20\u670D\u52A1\u5668\uFF0C\u4F46\u672C\u5730\u6253\u4E0A\u6258\u7BA1\u6807\u8BB0\u5931\u8D25\u3002\u4E3A\u9632\u53CC\u65B9\u7ADE\u6001\u5237\u65B0\u5BFC\u81F4\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u6388\u6743\u3002"
1333
+ },
1334
+ "auth.commandFailed": {
1335
+ en: "nolo auth {0} failed: {1}",
1336
+ zh: "nolo auth {0} \u5931\u8D25\uFF1A{1}"
1337
+ },
1338
+ "auth.cloudflareTokenGenerated": {
1339
+ en: "[nolo] Generated Cloudflare API token for zone {0} ({1}).\nStore it as CLOUDFLARE_EMAIL_ROUTING_API_TOKEN:\n {2}\n",
1340
+ zh: "[nolo] \u5DF2\u4E3A zone {0}\uFF08{1}\uFF09\u751F\u6210 Cloudflare API token\u3002\n\u8BF7\u4FDD\u5B58\u4E3A CLOUDFLARE_EMAIL_ROUTING_API_TOKEN\uFF1A\n {2}\n"
1341
+ },
1342
+ "auth.envUpdated": {
1343
+ en: "[nolo] Updated {0} with CLOUDFLARE_EMAIL_ROUTING_API_TOKEN.",
1344
+ zh: "[nolo] \u5DF2\u66F4\u65B0 {0} \u91CC\u7684 CLOUDFLARE_EMAIL_ROUTING_API_TOKEN\u3002"
1345
+ },
1346
+ // ── Non-TUI CLI output: nolo app ──────────────────────────────────────────
1347
+ "app.noApps": {
1348
+ en: "No apps\n",
1349
+ zh: "\u6CA1\u6709\u5E94\u7528\n"
1350
+ },
1351
+ "app.listTitle": {
1352
+ en: "App list ({0})\n\n",
1353
+ zh: "\u5E94\u7528\u5217\u8868 ({0})\n\n"
1354
+ },
1355
+ "app.unnamed": {
1356
+ en: "(unnamed)",
1357
+ zh: "(\u672A\u547D\u540D)"
1358
+ },
1359
+ "app.detailsTitle": {
1360
+ en: "App details\n\n",
1361
+ zh: "\u5E94\u7528\u8BE6\u60C5\n\n"
1362
+ },
1363
+ "app.errorNameRequired": {
1364
+ en: "\nError: provide one of --name / --app-id / --app-key\n",
1365
+ zh: "\n\u9519\u8BEF: \u5FC5\u987B\u63D0\u4F9B --name / --app-id / --app-key \u4E4B\u4E00\n"
1366
+ },
1367
+ "app.errorJobIdRequired": {
1368
+ en: "\nError: --job-id is required\n",
1369
+ zh: "\n\u9519\u8BEF: \u5FC5\u987B\u63D0\u4F9B --job-id\n"
1370
+ },
1371
+ "app.errorNameOrAppId": {
1372
+ en: "\nError: provide --name or --app-id\n",
1373
+ zh: "\n\u9519\u8BEF: \u5FC5\u987B\u63D0\u4F9B --name \u6216 --app-id\n"
1374
+ },
1375
+ "app.errorWithDetail": {
1376
+ en: "\nError: {0}\n",
1377
+ zh: "\n\u9519\u8BEF: {0}\n"
1378
+ },
1379
+ "app.deploySucceeded": {
1380
+ en: "Deploy succeeded\n",
1381
+ zh: "\u90E8\u7F72\u6210\u529F\n"
1382
+ },
1383
+ "app.deployStatusTitle": {
1384
+ en: "Deploy status\n\n",
1385
+ zh: "\u90E8\u7F72\u72B6\u6001\n\n"
1386
+ },
1387
+ "app.deleteConfirm": {
1388
+ en: "About to delete app ({0}) \u2014 this cannot be undone. Confirm? [y/N] ",
1389
+ zh: "\u5373\u5C06\u5220\u9664\u5E94\u7528 ({0})\uFF0C\u6B64\u64CD\u4F5C\u4E0D\u53EF\u64A4\u9500\u3002\u786E\u8BA4\uFF1F[y/N] "
1390
+ },
1391
+ "app.deleteCancelled": {
1392
+ en: "Cancelled\n",
1393
+ zh: "\u5DF2\u53D6\u6D88\n"
1394
+ },
1395
+ "app.deleteDone": {
1396
+ en: "Deleted app ({0})\n",
1397
+ zh: "\u5DF2\u5220\u9664\u5E94\u7528 ({0})\n"
1398
+ },
1399
+ "app.deploy.error.nameOrAppIdRequired": {
1400
+ en: "provide --name or --app-id",
1401
+ zh: "\u5FC5\u987B\u63D0\u4F9B --name \u6216 --app-id"
1402
+ },
1403
+ "app.deploy.error.codeFileUnreadable": {
1404
+ en: "cannot read --code-file: {0}",
1405
+ zh: "\u65E0\u6CD5\u8BFB\u53D6 --code-file: {0}"
1406
+ },
1407
+ "app.deploy.error.filesMustBeArray": {
1408
+ en: "--files must be a JSON array",
1409
+ zh: "--files \u5FC5\u987B\u662F JSON \u6570\u7EC4"
1410
+ },
1411
+ "app.deploy.error.filesParseFailed": {
1412
+ en: "--files parse failed: {0}",
1413
+ zh: "--files \u89E3\u6790\u5931\u8D25: {0}"
1414
+ },
1415
+ "app.deploy.error.codeRequired": {
1416
+ en: "provide one of --code / --code-file / --files",
1417
+ zh: "\u5FC5\u987B\u63D0\u4F9B --code / --code-file / --files \u4E4B\u4E00"
1418
+ },
1419
+ // ── Non-TUI CLI output: nolo agent / nolo run ─────────────────────────────
1420
+ "agent.unavailableHidden": {
1421
+ en: "\u26D4 {0} agent(s) temporarily unavailable (429) hidden. Use --show-unavailable to list them.\n",
1422
+ zh: "\u26D4 \u5DF2\u9690\u85CF {0} \u4E2A\u6682\u65F6\u4E0D\u53EF\u7528\u7684 agent\uFF08429\uFF09\u3002\u7528 --show-unavailable \u5217\u51FA\u5B83\u4EEC\u3002\n"
1423
+ },
1424
+ "agent.rateLimitedRecovery": {
1425
+ en: " - [429 rate-limited] {0} (id: {1}) recovers in {2}s{3}\n",
1426
+ zh: " - [429 \u9650\u6D41] {0} (id: {1}) \u9884\u8BA1 {2} \u79D2\u540E\u6062\u590D{3}\n"
1427
+ },
1428
+ "agentRun.autoRouteOverrideFailed": {
1429
+ en: "[nolo] auto-route: could not read the source agent, running the selected agent as-is.\n",
1430
+ zh: "[nolo] auto-route: \u8986\u76D6\u6E90 agent \u8BFB\u53D6\u5931\u8D25\uFF0C\u6309\u539F\u6837\u76F4\u8DD1\u6240\u9009 agent\u3002\n"
1431
+ },
1432
+ "agentRun.autoRouteModelOverride": {
1433
+ en: "[nolo] auto-route: model override is now {0}\n",
1434
+ zh: "[nolo] auto-route: model \u5C42\u8986\u76D6\u4E3A {0}\n"
1435
+ },
1436
+ // ── Non-TUI CLI output: nolo agent delete ─────────────────────────────────
1437
+ // Flag descriptions for `nolo agent delete --help`; the Chinese copy is the
1438
+ // original wording, kept verbatim so existing users lose no information.
1439
+ "agentDelete.description": {
1440
+ en: "Deletes an agent's private record (agent-{userId}-{id}) and public record (agent-pub-{id}).\n",
1441
+ zh: "\u5220\u9664\u4E00\u4E2A agent \u7684\u79C1\u6709\u8BB0\u5F55 (agent-{userId}-{id}) \u4E0E\u516C\u5F00\u8BB0\u5F55 (agent-pub-{id})\u3002\n"
1442
+ },
1443
+ "agentDelete.tombstoneNote": {
1444
+ en: "The server side is a tombstone soft delete: read after DELETE returns 404.\n",
1445
+ zh: "\u670D\u52A1\u5668\u7AEF\u4E3A tombstone \u8F6F\u5220\u9664\uFF0CDELETE \u540E\u518D\u6B21 read \u4F1A\u8FD4\u56DE 404\u3002\n"
1446
+ },
1447
+ "agentDelete.flagYes": {
1448
+ en: " --yes Actually delete; without it only the dry-run target summary is printed.\n",
1449
+ zh: " --yes \u771F\u6B63\u6267\u884C\u5220\u9664\uFF1B\u7F3A\u7701\u65F6\u4EC5 dry-run \u8F93\u51FA\u76EE\u6807\u6458\u8981\u3002\n"
1450
+ },
1451
+ "agentDelete.flagJson": {
1452
+ en: " --json Print the JSON result.\n",
1453
+ zh: " --json \u8F93\u51FA JSON \u7ED3\u679C\u3002\n"
1454
+ },
1455
+ "agentDelete.flagId": {
1456
+ en: " --id <agent> Same as the positional argument: alias / dbKey / URL / 26-char id.\n",
1457
+ zh: " --id <agent> \u4E0E\u4F4D\u7F6E\u53C2\u6570\u7B49\u4EF7\uFF0C\u4F20\u5165 alias / dbKey / URL / 26-char id\u3002\n"
1458
+ },
1459
+ "agentDelete.flagServer": {
1460
+ en: " --server / --server-url Delete only on the given server (replicas outside the fan-out are kept).\n",
1461
+ zh: " --server / --server-url \u4EC5\u5220\u9664\u6307\u5B9A\u670D\u52A1\u5668\uFF08\u4ECD\u4FDD\u7559\u96C6\u7FA4 fan-out \u4E4B\u5916\u7684\u526F\u672C\uFF09\u3002\n"
1462
+ },
1463
+ "agentDelete.flagUser": {
1464
+ en: " --user <userId> Explicitly override userId (errors when it differs from AUTH_TOKEN).\n",
1465
+ zh: " --user <userId> \u663E\u5F0F\u8986\u76D6 userId\uFF08\u4E0E AUTH_TOKEN \u4E0D\u4E00\u81F4\u5219\u62A5\u9519\uFF09\u3002\n"
1466
+ },
1467
+ "agentDelete.flagToken": {
1468
+ en: " --token / --machine-key Temporarily override AUTH_TOKEN.\n",
1469
+ zh: " --token / --machine-key \u4E34\u65F6\u8986\u76D6 AUTH_TOKEN\u3002\n"
1470
+ },
1471
+ // ── Non-TUI CLI output: shared API error printing ─────────────────────────
1472
+ "api.requestFailed": {
1473
+ en: "Request failed: {0}",
1474
+ zh: "\u8BF7\u6C42\u5931\u8D25: {0}"
1475
+ },
1476
+ "api.requestFailedHttp": {
1477
+ en: "Request failed (HTTP {0})",
1478
+ zh: "\u8BF7\u6C42\u5931\u8D25 (HTTP {0})"
1479
+ },
1480
+ "api.nonJsonResponse": {
1481
+ en: "Server returned a non-JSON response (HTTP {0})",
1482
+ zh: "\u670D\u52A1\u7AEF\u8FD4\u56DE\u975E JSON \u54CD\u5E94 (HTTP {0})"
1483
+ },
1484
+ "api.errorWithCode": {
1485
+ en: "Error [{0}]: {1}",
1486
+ zh: "\u9519\u8BEF [{0}]: {1}"
1487
+ },
1488
+ "api.error": {
1489
+ en: "Error: {0}",
1490
+ zh: "\u9519\u8BEF: {0}"
1491
+ },
1492
+ // ── Non-TUI CLI output: local ChatGPT web image job ───────────────────────
1493
+ "chatgptWebImage.jobInProgress": {
1494
+ en: "A ChatGPT web image job is already running, try again later (lock file held).",
1495
+ zh: "ChatGPT \u7F51\u9875\u751F\u56FE\u4EFB\u52A1\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\uFF08\u9501\u6587\u4EF6\u5360\u7528\uFF09"
1496
+ },
1497
+ "chatgptWebImage.noOutputFile": {
1498
+ en: "ChatGPT web image generation produced no file: {0}",
1499
+ zh: "ChatGPT \u7F51\u9875\u751F\u56FE\u672A\u4EA7\u51FA\u6587\u4EF6\uFF1A{0}"
1500
+ },
1501
+ "chatgptWebImage.outputFileInvalid": {
1502
+ en: "ChatGPT web image file is invalid or empty: {0}",
1503
+ zh: "ChatGPT \u7F51\u9875\u751F\u56FE\u6587\u4EF6\u65E0\u6548\u6216\u4E3A\u7A7A\uFF1A{0}"
1504
+ },
1505
+ "chatgptWebImage.uploadFailed": {
1506
+ en: "Uploading the generated image to Nolo FS failed: {0}",
1507
+ zh: "\u4E0A\u4F20\u751F\u56FE\u7ED3\u679C\u5230 Nolo FS \u5931\u8D25\uFF1A{0}"
1508
+ },
1509
+ "chatgptWebImage.missingUploadFileId": {
1510
+ en: "Upload succeeded but the response has no fileId",
1511
+ zh: "\u4E0A\u4F20\u751F\u56FE\u7ED3\u679C\u6210\u529F\u4F46\u54CD\u5E94\u7F3A\u5C11 fileId"
1512
+ },
1513
+ "chatgptWebImage.missingPrompt": {
1514
+ en: "Missing image prompt (payload.meta.prompt is required)",
1515
+ zh: "\u7F3A\u5C11\u751F\u56FE prompt\uFF08payload.meta.prompt \u5FC5\u586B\uFF09"
1516
+ },
1517
+ // ── Non-TUI CLI output: agent-run orchestration tool errors ───────────────
1518
+ "agentRunTool.missingAgentKey": {
1519
+ en: "startAgentRun: missing agentKey, and the current agent cannot be identified.",
1520
+ zh: "startAgentRun: \u7F3A\u5C11 agentKey \u53C2\u6570\uFF0C\u4E14\u65E0\u6CD5\u8BC6\u522B\u5F53\u524D Agent\u3002"
1521
+ },
1522
+ "agentRunTool.missingTask": {
1523
+ en: "startAgentRun: missing a valid task description.",
1524
+ zh: "startAgentRun: \u7F3A\u5C11\u6709\u6548\u7684 task \u6587\u672C\u63CF\u8FF0\u3002"
1525
+ },
1526
+ "agentRunTool.noDialogToContinue": {
1527
+ en: "This run has no linked dialog and cannot be continued.",
1528
+ zh: "\u8BE5 run \u65E0\u5173\u8054 dialog\uFF0C\u65E0\u6CD5\u7EED\u8DD1\u3002"
1529
+ },
1530
+ "agentRunTool.appendMissingRunId": {
1531
+ en: 'controlAgentRun(action:"append"): missing runId.',
1532
+ zh: 'controlAgentRun(action:"append"): \u7F3A\u5C11 runId\u3002'
1533
+ },
1534
+ "agentRunTool.appendMissingUserInput": {
1535
+ en: 'controlAgentRun(action:"append"): missing a valid userInput text.',
1536
+ zh: 'controlAgentRun(action:"append"): \u7F3A\u5C11\u6709\u6548\u7684 userInput \u6587\u672C\u3002'
1537
+ },
1538
+ "agentRunTool.appendQueueUnsupported": {
1539
+ en: "This run did not start with a queue channel; append while running is not supported. Wait for a terminal state first.",
1540
+ zh: "\u8BE5 run \u542F\u52A8\u65F6\u4E0D\u652F\u6301\u8FD0\u884C\u4E2D\u5165\u961F\uFF08\u65E0\u961F\u5217\u901A\u9053\uFF09\uFF0C\u8BF7\u7B49\u7EC8\u6001\u540E\u518D append"
1541
+ },
1542
+ "agentRunTool.unknownAction": {
1543
+ en: 'controlAgentRun: unknown action "{0}".',
1544
+ zh: 'controlAgentRun: \u672A\u77E5 action "{0}"\u3002'
1545
+ },
1546
+ "agentRunTool.missingRunId": {
1547
+ en: 'controlAgentRun(action:"{0}"): missing runId.',
1548
+ zh: 'controlAgentRun(action:"{0}"): \u7F3A\u5C11 runId\u3002'
1549
+ },
1550
+ "agentRunTool.waitAborted": {
1551
+ en: "controlAgentRun(wait) was aborted.",
1552
+ zh: "controlAgentRun(wait) \u5DF2\u88AB\u4E2D\u6B62\u3002"
1553
+ },
1554
+ // ── Non-TUI CLI output: agent-run OAuth channel ownership + stream failures ──
1555
+ // 用户在 TUI 选了别人的 sshare agent(跑在 agent owner 的 OAuth 订阅上):
1556
+ // auto 模式下模型请求经服务端 owner-required 代理走分享者订阅、文件/shell
1557
+ // 工具留在本机执行(不是转服务端跑整轮)。文案说明模型使用分享者订阅、
1558
+ // 工具在本机;不展示内部 ID,也不提供未经保证的订阅切换建议。
1559
+ "agentRun.oauthChannelOwnerSkip": {
1560
+ en: '[nolo] Using "{0}", shared by someone else: the model uses their subscription; file operations and commands still run on your computer.',
1561
+ zh: "[nolo] \u6B63\u5728\u4F7F\u7528\u5BF9\u65B9\u5206\u4EAB\u7684\u300C{0}\u300D\uFF1A\u6A21\u578B\u4F7F\u7528\u5BF9\u65B9\u7684\u8BA2\u9605\uFF0C\u6587\u4EF6\u64CD\u4F5C\u548C\u547D\u4EE4\u6267\u884C\u4ECD\u5728\u4F60\u7684\u7535\u8111\u4E0A\u8FDB\u884C\u3002"
1562
+ },
1563
+ "agentRun.sharedAgentFallbackName": {
1564
+ en: "Shared agent",
1565
+ zh: "\u5171\u4EAB Agent"
1566
+ },
1567
+ // 分享 OAuth agent 的 shell 会话授权确认(块 D):首次 execShell/
1568
+ // launchProcess 前弹。必须把三件事说清——这是谁的 agent / 命令在哪台
1569
+ // 设备哪个工作区跑 / 任意 shell 可读写该用户可访问的资源。
1570
+ "shellGrant.confirmTitle": {
1571
+ en: "Allow shell commands for shared agent {0}?",
1572
+ zh: "\u5141\u8BB8\u5206\u4EAB agent {0} \u6267\u884C shell \u547D\u4EE4\u5417\uFF1F"
1573
+ },
1574
+ "shellGrant.confirmBody": {
1575
+ en: "Agent {0} (owner {1}) asked to run shell commands on this device.\nDevice: {2} ({3})\nWorkspace: {4}\n\nShell commands can read/write anything this user can access. Allowed for the rest of this session; revoke any time with /shell-revoke.",
1576
+ zh: "\u5206\u4EAB agent {0}\uFF08\u4E3B\u4EBA {1}\uFF09\u8BF7\u6C42\u5728\u672C\u673A\u6267\u884C shell \u547D\u4EE4\u3002\n\u8BBE\u5907\uFF1A{2}\uFF08{3}\uFF09\n\u5DE5\u4F5C\u533A\uFF1A{4}\n\n\u4EFB\u610F shell \u547D\u4EE4\u53EF\u8BFB\u5199\u672C\u673A\u8BE5\u7528\u6237\u80FD\u8BBF\u95EE\u7684\u5168\u90E8\u8D44\u6E90\u3002\u5141\u8BB8\u540E\u5728\u672C\u4F1A\u8BDD\u6301\u7EED\u6709\u6548\uFF1B\u968F\u65F6\u53EF\u7528 /shell-revoke \u64A4\u9500\u3002"
1577
+ },
1578
+ "shellGrant.revoked": {
1579
+ en: "[nolo] Shell permission revoked for shared agents in this session.",
1580
+ zh: "[nolo] \u5DF2\u64A4\u9500\u672C\u4F1A\u8BDD\u4E2D\u5206\u4EAB agent \u7684 shell \u6267\u884C\u6743\u9650\u3002"
1581
+ },
1582
+ "shellGrant.revokeNone": {
1583
+ en: "[nolo] No shell permission is currently granted in this session.",
1584
+ zh: "[nolo] \u672C\u4F1A\u8BDD\u5F53\u524D\u6CA1\u6709\u5DF2\u6388\u4E88\u7684 shell \u6743\u9650\u3002"
1585
+ },
1586
+ // 运行位置展示(块 D):owner-required 场景告诉用户工具实际在哪台设备
1587
+ // 哪个工作区执行。unknown 不猜、不静默标 ready。
1588
+ "toolLocation.line": {
1589
+ en: "[nolo] Tools execute on {0} ({1}) \xB7 workspace {2} \xB7 status: {3}",
1590
+ zh: "[nolo] \u5DE5\u5177\u5728 {0}\uFF08{1}\uFF09\xB7 \u5DE5\u4F5C\u533A {2} \xB7 \u72B6\u6001\uFF1A{3} \u6267\u884C"
1591
+ },
1592
+ "toolLocation.unknown": {
1593
+ en: "[nolo] Tool execution location: unknown",
1594
+ zh: "[nolo] \u5DE5\u5177\u6267\u884C\u4F4D\u7F6E\uFF1A\u672A\u77E5"
1595
+ },
1596
+ // antigravity 502 MALFORMED_FUNCTION_CALL:裸 message 是整段 provider JSON
1597
+ // dump,对用户零信息量。映射成单行可操作文案;原始 JSON 只在既有
1598
+ // NOLO_DEBUG / NOLO_CLI_DEBUG_DETAIL 开关下附加。
1599
+ "agentRunStream.malformedToolCallRejected": {
1600
+ en: "[nolo] The provider rejected the model's generated tool call, so this attempt will not retry automatically. It is usually intermittent: read dialog {0} to check progress, then resend.",
1601
+ zh: "[nolo] \u6A21\u578B\u751F\u6210\u7684\u5DE5\u5177\u8C03\u7528\u88AB\u4E0A\u6E38\u62D2\u7EDD\uFF0C\u672C\u6B21\u4E0D\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002\u8FD9\u79CD\u60C5\u51B5\u901A\u5E38\u662F\u5076\u53D1\u7684\uFF1A\u53EF\u5148\u8BFB\u5BF9\u8BDD {0} \u770B\u8FDB\u5EA6\uFF0C\u7136\u540E\u76F4\u63A5\u91CD\u53D1\u3002"
1602
+ },
1603
+ "agentRunStream.malformedToolCallRejectedNoDialog": {
1604
+ en: "[nolo] The provider rejected the model's generated tool call, so this attempt will not retry automatically. It is usually intermittent: just resend your message.",
1605
+ zh: "[nolo] \u6A21\u578B\u751F\u6210\u7684\u5DE5\u5177\u8C03\u7528\u88AB\u4E0A\u6E38\u62D2\u7EDD\uFF0C\u672C\u6B21\u4E0D\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002\u8FD9\u79CD\u60C5\u51B5\u901A\u5E38\u662F\u5076\u53D1\u7684\uFF1A\u76F4\u63A5\u91CD\u53D1\u5373\u53EF\u3002"
1606
+ },
1607
+ "agentRunStream.interruptedAfterDialog": {
1608
+ en: "\n[nolo] Agent stream transport interrupted after dialog {0} was created: {1}\n",
1609
+ zh: "\n[nolo] \u5BF9\u8BDD {0} \u521B\u5EFA\u540E\uFF0Cagent \u6D41\u5F0F\u8F93\u51FA\u4E2D\u65AD\uFF1A{1}\n"
1610
+ },
1611
+ "agentRunStream.mayStillFinishOnServer": {
1612
+ en: "[nolo] The agent run may still finish on the server; read the dialog before retrying.\n",
1613
+ zh: "[nolo] \u8FD9\u6B21 agent \u8FD0\u884C\u53EF\u80FD\u4ECD\u5728\u670D\u52A1\u7AEF\u7EE7\u7EED\uFF0C\u91CD\u8BD5\u524D\u8BF7\u5148\u8BFB\u4E00\u4E0B\u8BE5\u5BF9\u8BDD\u3002\n"
1614
+ },
1615
+ "agentRunStream.failed": {
1616
+ en: "\n[nolo] Agent stream failed: {0}\n",
1617
+ zh: "\n[nolo] Agent \u6D41\u5F0F\u8FD0\u884C\u5931\u8D25\uFF1A{0}\n"
1618
+ },
1619
+ "agentRunStream.rawErrorDetail": {
1620
+ en: "[nolo] Raw error detail (NOLO_DEBUG=1): {0}\n",
1621
+ zh: "[nolo] \u539F\u59CB\u9519\u8BEF\u8BE6\u60C5\uFF08NOLO_DEBUG=1\uFF09\uFF1A{0}\n"
1622
+ }
1623
+ };
1624
+ function t(key, ...params) {
1625
+ const text = STRINGS[key][currentLocale];
1626
+ if (params.length === 0) return text;
1627
+ return text.replace(/\{(\d+|required|current)\}/g, (match, name) => {
1628
+ const index = name === "required" ? 0 : name === "current" ? 1 : Number(name);
1629
+ const replacement = params[index];
1630
+ return replacement === void 0 ? match : replacement;
1631
+ });
1632
+ }
1633
+ var TOOL_LABELS = {
1634
+ // Local workspace tools (packages/agent-runtime/localWorkspaceTools.ts)
1635
+ readFile: { en: "Read", zh: "\u8BFB\u53D6" },
1636
+ writeFile: { en: "Write", zh: "\u5199\u5165" },
1637
+ editFile: { en: "Edit", zh: "\u7F16\u8F91" },
1638
+ codeSearch: { en: "Search", zh: "\u641C\u7D22" },
1639
+ globFiles: { en: "Glob", zh: "\u5339\u914D" },
1640
+ execShell: { en: "Run", zh: "\u6267\u884C" },
1641
+ runCommand: { en: "Run", zh: "\u6267\u884C" },
1642
+ captureVisualState: { en: "Capture", zh: "\u622A\u5C4F" },
1643
+ // Memory tools
1644
+ rememberMemory: { en: "Remember", zh: "\u8BB0\u4F4F" },
1645
+ queryMemory: { en: "Recall", zh: "\u67E5\u8BB0\u5FC6" },
1646
+ deleteMemory: { en: "Forget", zh: "\u5220\u8BB0\u5FC6" },
1647
+ // Workspace / diagnostics
1648
+ searchWorkspace: { en: "Search workspace", zh: "\u641C\u7D22\u5DE5\u4F5C\u533A" },
1649
+ // 同一工具在 web/server 工具面用 snake_case 命名(packages/ai/tools/index.ts)。
1650
+ search_workspace: { en: "Search workspace", zh: "\u641C\u7D22\u5DE5\u4F5C\u533A" },
1651
+ // 全空间搜索:内置 skill search-all-spaces 声明的工作区工具,loadSkill 后进入
1652
+ // 工具面;同样需要中英文标签,避免回退成裸工具名。
1653
+ search_all_spaces: { en: "Search all spaces", zh: "\u641C\u7D22\u5168\u90E8\u7A7A\u95F4" },
1654
+ cliDoctor: { en: "Doctor", zh: "\u81EA\u68C0" },
1655
+ cliWhoami: { en: "Whoami", zh: "\u67E5\u770B\u8EAB\u4EFD" },
1656
+ checkEnv: { en: "Check env", zh: "\u68C0\u67E5\u73AF\u5883" },
1657
+ configure: { en: "Configure", zh: "\u914D\u7F6E" },
1658
+ notifyUser: { en: "Notify", zh: "\u901A\u77E5" },
1659
+ // Docs / dialogs / spaces
1660
+ readDoc: { en: "Read doc", zh: "\u8BFB\u53D6\u6587\u6863" },
1661
+ createDoc: { en: "Create doc", zh: "\u65B0\u5EFA\u6587\u6863" },
1662
+ updateDoc: { en: "Update doc", zh: "\u66F4\u65B0\u6587\u6863" },
1663
+ readDialog: { en: "Read dialog", zh: "\u8BFB\u53D6\u5BF9\u8BDD" },
1664
+ listDialogs: { en: "List dialogs", zh: "\u5217\u51FA\u5BF9\u8BDD" },
1665
+ queryDialogsBySubjectRef: { en: "Query dialogs", zh: "\u67E5\u8BE2\u5BF9\u8BDD" },
1666
+ searchDialogMessages: { en: "Search messages", zh: "\u641C\u7D22\u6D88\u606F" },
1667
+ listSpaces: { en: "List spaces", zh: "\u5217\u51FA\u7A7A\u95F4" },
1668
+ readSpace: { en: "Read space", zh: "\u8BFB\u53D6\u7A7A\u95F4" },
1669
+ // Tables
1670
+ createTable: { en: "Create table", zh: "\u521B\u5EFA\u8868" },
1671
+ queryTableRows: { en: "Query rows", zh: "\u67E5\u8BE2\u8868\u884C" },
1672
+ addTableRow: { en: "Add row", zh: "\u65B0\u589E\u8868\u884C" },
1673
+ addTableRows: { en: "Add rows", zh: "\u65B0\u589E\u8868\u884C" },
1674
+ updateTableRow: { en: "Update row", zh: "\u66F4\u65B0\u8868\u884C" },
1675
+ deleteTableRow: { en: "Delete row", zh: "\u5220\u9664\u8868\u884C" },
1676
+ // Web
1677
+ // Tree group header uses the same short category noun as Read/Search/Run
1678
+ // ("Fetch" / "抓取网页"), not a longer "Fetch page" phrase.
1679
+ fetchWebpage: { en: "Fetch", zh: "\u6293\u53D6\u7F51\u9875" },
1680
+ readPage: { en: "Read page", zh: "\u8BFB\u53D6\u7F51\u9875" },
1681
+ exa_search: { en: "Web search", zh: "\u8054\u7F51\u641C\u7D22" },
1682
+ // Skill loading
1683
+ loadSkill: { en: "Used Skill", zh: "\u4F7F\u7528\u6280\u80FD" },
1684
+ // Agent orchestration
1685
+ listAgents: { en: "List agents", zh: "\u5217\u51FA\u667A\u80FD\u4F53" },
1686
+ readAgent: { en: "Read agent", zh: "\u8BFB\u53D6\u667A\u80FD\u4F53" },
1687
+ startAgentRun: { en: "Start agent", zh: "\u542F\u52A8\u667A\u80FD\u4F53" },
1688
+ controlAgentRun: { en: "Control agent", zh: "\u63A7\u5236\u667A\u80FD\u4F53" }
1689
+ };
1690
+ function toolLabel(name) {
1691
+ return TOOL_LABELS[name]?.[currentLocale] ?? name;
1692
+ }
1693
+ var COMMAND_DESCRIPTIONS = {
1694
+ "auth cooldown": {
1695
+ en: "List / clear credential availability cooldowns",
1696
+ zh: "\u5217\u51FA / \u6E05\u9664\u51ED\u8BC1\u53EF\u7528\u6027\u51B7\u5374"
1697
+ },
1698
+ "auth cloudflare": {
1699
+ en: "Authorize Cloudflare OAuth",
1700
+ zh: "\u6388\u6743 Cloudflare OAuth"
1701
+ },
1702
+ "auth chatgpt": {
1703
+ en: "Authorize ChatGPT / OpenAI Codex OAuth",
1704
+ zh: "\u6388\u6743 ChatGPT / OpenAI Codex OAuth"
1705
+ },
1706
+ "auth xai": {
1707
+ en: "Authorize xAI Grok OAuth (SuperGrok subscription)",
1708
+ zh: "\u6388\u6743 xAI Grok OAuth\uFF08SuperGrok \u8BA2\u9605\uFF09"
1709
+ },
1710
+ "auth antigravity": {
1711
+ en: "Authorize Google Antigravity OAuth",
1712
+ zh: "\u6388\u6743 Google Antigravity OAuth"
1713
+ },
1714
+ "auth claude": {
1715
+ en: "Authorize Claude Pro/Max OAuth",
1716
+ zh: "\u6388\u6743 Claude Pro/Max OAuth"
1717
+ },
1718
+ "auth cursor": {
1719
+ en: "Authorize Cursor Pro OAuth",
1720
+ zh: "\u6388\u6743 Cursor Pro OAuth"
1721
+ },
1722
+ "auth devin": {
1723
+ en: "Authorize Devin OAuth (Free SWE-2)",
1724
+ zh: "\u6388\u6743 Devin OAuth\uFF08\u514D\u8D39 SWE-2\uFF09"
1725
+ }
1726
+ };
1727
+ function cliCommandDescription(commandPath) {
1728
+ return COMMAND_DESCRIPTIONS[commandPath]?.[currentLocale] ?? null;
1729
+ }
1730
+ function toolLabelVariants(name) {
1731
+ const entry = TOOL_LABELS[name];
1732
+ if (!entry) return [name];
1733
+ return [...new Set(Object.values(entry))];
1734
+ }
1735
+ function agentRunStatusWord(status) {
1736
+ switch (status) {
1737
+ case "running":
1738
+ return t("runZoneRunning");
1739
+ case "pending":
1740
+ return t("runZonePending");
1741
+ case "cancelling":
1742
+ return t("runZoneCancelling");
1743
+ case "done":
1744
+ return t("runZoneDone");
1745
+ case "killed":
1746
+ case "cancelled":
1747
+ return t("runZoneCancelled");
1748
+ case "failed":
1749
+ case "timeout":
1750
+ case "orphaned":
1751
+ return t("runZoneFailed");
1752
+ case "not_found":
1753
+ return t("runStatusNotFound");
1754
+ default:
1755
+ return status;
1756
+ }
1757
+ }
1758
+ function agentRunCardLabels() {
1759
+ return {
1760
+ runStatus: t("runStatusLabel"),
1761
+ runStarted: t("runStartedLabel"),
1762
+ runStopped: t("runStoppedLabel"),
1763
+ runFinished: t("runFinishedLabel"),
1764
+ logTail: t("runLogTailLabel"),
1765
+ runs: (count) => t("runsListLabel", String(count)),
1766
+ toolCount: (count) => t("runToolsCount", String(count)),
1767
+ statusWord: agentRunStatusWord,
1768
+ // Same folding rule as the run zone/panel: an unnamed run's machine key
1769
+ // collapses to the kind-of-actor word, never the key itself.
1770
+ unnamedAgent: t("subAgentName"),
1771
+ // Padding rides on the value so the default English layout is unchanged.
1772
+ rows: {
1773
+ agent: `${t("runRowAgent")} `,
1774
+ status: `${t("runRowStatus")} `,
1775
+ tools: `${t("runRowTools")} `,
1776
+ note: `${t("runRowNote")} `,
1777
+ error: `${t("runRowError")} `,
1778
+ task: `${t("runRowTask")} `
1779
+ }
1780
+ };
1781
+ }
1782
+
1783
+ export {
1784
+ parseCliLocale,
1785
+ getCliLocale,
1786
+ setCliLocale,
1787
+ initCliLocale,
1788
+ dailyWelcomeTip,
1789
+ t,
1790
+ toolLabel,
1791
+ cliCommandDescription,
1792
+ toolLabelVariants,
1793
+ agentRunCardLabels
1794
+ };