nolo-cli 0.11.0 → 0.12.0-alpha.10

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 (123) hide show
  1. package/{_executeModel-ZEDPX6OF.js → _executeModel-4F7VZR5U.js} +52 -50
  2. package/{action-AA4IJ5K2.js → action-OTOWUMPW.js} +8 -9
  3. package/{addContentAction-QYVO4SYP.js → addContentAction-JGBUVR7K.js} +7 -9
  4. package/{addDialogAgentAction-WVVKT5WQ.js → addDialogAgentAction-V6CL2UCF.js} +9 -10
  5. package/{agentDeleteCommand-RDPGYIWF.js → agentDeleteCommand-MMRSG6AB.js} +39 -28
  6. package/{agentEmailCommands-2HJJKS5F.js → agentEmailCommands-YFVKOGM7.js} +65 -62
  7. package/{agentListCommands-HFEVV3ZW.js → agentListCommands-2PZHIQ3I.js} +128 -31
  8. package/{agentMachineCommands-25ZOENJU.js → agentMachineCommands-55UUZNHF.js} +38 -26
  9. package/{agentPullCommand-GOL2S4W2.js → agentPullCommand-KRBRIFIY.js} +7 -7
  10. package/{agentRecordCommands-GTCOAM3L.js → agentRecordCommands-BTP3OAPL.js} +57 -54
  11. package/{agentRunCommand-YBS3JDLD.js → agentRunCommand-AA4QLRQZ.js} +60 -59
  12. package/{agentRunControl-K4VKNEHF.js → agentRunControl-IX4F5W2C.js} +3 -3
  13. package/{agentRuntimeLocal-UQBMQI2M.js → agentRuntimeLocal-QDJCBXM2.js} +31 -15
  14. package/{agentSlice-6EKOBCCS.js → agentSlice-6JAJOU3X.js} +8 -9
  15. package/{authCommand-O2OWACN4.js → authCommand-DMW336GT.js} +15 -15
  16. package/{authCommands-H7365TZP.js → authCommands-GH5T6RYV.js} +6 -6
  17. package/{chunk-E4HNJSHC.js → chunk-2BVGERJ2.js} +81 -19
  18. package/{chunk-LP65VRCI.js → chunk-3MI5LDDU.js} +6 -6
  19. package/{chunk-OPZYGHUC.js → chunk-3WGLLTK4.js} +59 -1
  20. package/{chunk-KJR5KAUQ.js → chunk-3XF6LCCN.js} +20 -7
  21. package/{chunk-PXZAAB4L.js → chunk-4LG74DRG.js} +4 -4
  22. package/{chunk-2FTTDCD4.js → chunk-4ON5AV72.js} +2 -1
  23. package/{chunk-IWX4UW2E.js → chunk-524BDL33.js} +89 -8
  24. package/{chunk-ISNCLGUZ.js → chunk-5NBHQD4D.js} +4 -3
  25. package/{chunk-ZPRK73XY.js → chunk-5S4SWV5G.js} +51 -38
  26. package/{chunk-EVZKZF32.js → chunk-5V524MHX.js} +195 -78
  27. package/{chunk-CKOJQDKR.js → chunk-7JJCGV7N.js} +146 -3
  28. package/{chunk-NEM67FX7.js → chunk-ARSC56DC.js} +1 -1
  29. package/{chunk-AFON4QUU.js → chunk-AS3ZQ3O2.js} +19 -28
  30. package/{chunk-4SOKXIW4.js → chunk-B4KT7RN2.js} +10 -13
  31. package/chunk-BYXBJQAS.js +0 -0
  32. package/{chunk-PXQN7IBQ.js → chunk-C3BFP57W.js} +95 -2
  33. package/{chunk-AEZAORLG.js → chunk-CGDQDXKZ.js} +5 -5
  34. package/{chunk-MQI77IRB.js → chunk-DPFWKRHG.js} +2 -2
  35. package/{chunk-TACHTH5D.js → chunk-EIMX5ER5.js} +18 -18
  36. package/{chunk-5MOUAAMK.js → chunk-FSUZIGIG.js} +197 -2578
  37. package/{chunk-FXXSGWAJ.js → chunk-H5Y2H2N6.js} +1 -1
  38. package/chunk-IKXL2HZ3.js +70 -0
  39. package/{chunk-QNMFBBZK.js → chunk-IVAOVLM7.js} +1 -1
  40. package/chunk-JFANOO7I.js +2274 -0
  41. package/{chunk-YPRZSPF3.js → chunk-JKWWVF2I.js} +1 -1
  42. package/{chunk-3NSIQZZ6.js → chunk-JU7J7EAV.js} +45 -45
  43. package/{chunk-X2S7JTIG.js → chunk-KWBH4RAL.js} +1280 -137
  44. package/{chunk-OUI3ZHYD.js → chunk-LUKQQJFL.js} +39 -2
  45. package/{chunk-BX6U3ETE.js → chunk-MG6BVV3T.js} +320 -102
  46. package/{chunk-L53FGHA4.js → chunk-MQRZ5QUH.js} +1 -1
  47. package/{chunk-2W2VYVI5.js → chunk-MZHSAPZP.js} +675 -177
  48. package/{chunk-YOCHZD7D.js → chunk-NCGFB7NN.js} +5 -3
  49. package/{chunk-DWGAEFJL.js → chunk-O4FOPRCP.js} +1 -1
  50. package/chunk-OGGHETUE.js +4900 -0
  51. package/{chunk-PNEW2Z3T.js → chunk-OHEKYYJF.js} +7 -7
  52. package/chunk-OOIN7HSO.js +146 -0
  53. package/{chunk-SV5MWASH.js → chunk-OPM2DE2J.js} +12 -12
  54. package/{chunk-5OIFWVX7.js → chunk-QJSTNKJY.js} +1 -1
  55. package/{chunk-C4FTUXVF.js → chunk-QLUFR47U.js} +11 -1
  56. package/{chunk-LAX2JSTX.js → chunk-QUHUVG6Y.js} +20 -2
  57. package/{chunk-D6OQHXVG.js → chunk-RQSOAMPJ.js} +22 -6
  58. package/{chunk-ZEYDOXHF.js → chunk-RUGEW4P7.js} +1515 -884
  59. package/{chunk-GBDSZATH.js → chunk-RWO5DGXI.js} +3 -3
  60. package/{chunk-S3GS2PRL.js → chunk-TA7VKOHU.js} +613 -70
  61. package/{chunk-XYZA7S7V.js → chunk-TQYYGE6G.js} +6 -6
  62. package/{chunk-YTBMA7NO.js → chunk-TYPHUVK5.js} +70 -8
  63. package/{chunk-4ZDM73SD.js → chunk-V2J635L5.js} +1 -1
  64. package/{chunk-C2MDQQ4O.js → chunk-VBSWHE5W.js} +1 -1
  65. package/{chunk-O26GI2JP.js → chunk-VKG4HXYV.js} +39 -8
  66. package/{chunk-IPYUUY4E.js → chunk-WPHL6ALY.js} +1 -1
  67. package/{chunk-7D3JY6C2.js → chunk-WVTBAALN.js} +64 -5
  68. package/{chunk-XFOLQLDN.js → chunk-XHQWJUW4.js} +2 -2
  69. package/{chunk-Q3UKJVU4.js → chunk-Y5P3ZRGC.js} +10 -10
  70. package/{chunk-KQQVGRA3.js → chunk-YUMYYXPI.js} +53 -183
  71. package/cliEnvHelpers-VYC2OPTB.js +30 -0
  72. package/{createAgentAutomationAction-LTI5QU35.js → createAgentAutomationAction-4NY4JLOK.js} +26 -26
  73. package/{createDialogAction-OJJ7L3L3.js → createDialogAction-I5WUWFJ6.js} +26 -26
  74. package/{createPageAction-5MXWVRGY.js → createPageAction-HFTIQ7TW.js} +26 -26
  75. package/{dbSlice-RQFQQVHT.js → dbSlice-J4PUZ6Y5.js} +6 -7
  76. package/{deleteFile-7XP5BGC7.js → deleteFile-M7UNIUOO.js} +4 -4
  77. package/{dialogCommands-JTJ3RPPW.js → dialogCommands-SVXRJFZS.js} +34 -23
  78. package/{dialogSlice-OWROKURJ.js → dialogSlice-35LA3ZRG.js} +26 -26
  79. package/{docCreateCommands-WJBEW2V7.js → docCreateCommands-Z7RIAYKQ.js} +34 -23
  80. package/{docDeleteCommands-BVEHJOY5.js → docDeleteCommands-NEYHUVZF.js} +35 -25
  81. package/{docReadCommands-NEWOZIJV.js → docReadCommands-I4US2SDE.js} +34 -23
  82. package/{docStore-3DXRYBMD.js → docStore-3CP2IO6M.js} +25 -25
  83. package/{docUpdateCommands-C7WHT7UU.js → docUpdateCommands-UU5HQBRP.js} +34 -23
  84. package/fetchMessages-KTNM7QAR.js +1 -1
  85. package/{getPricing-3E6UNPKL.js → getPricing-UGDJHI7M.js} +7 -3
  86. package/{handleSendMessageAction-B5PRR7BE.js → handleSendMessageAction-FWTLQGOZ.js} +30 -30
  87. package/index.js +77 -76
  88. package/{localDialogRead-YSKFFRTT.js → localDialogRead-2VRI24F4.js} +1 -1
  89. package/{machineCommands-IIIREAEK.js → machineCommands-STHZKBDJ.js} +64 -61
  90. package/{machineWsRunDispatch-3SIU6ILW.js → machineWsRunDispatch-7YHT4TPT.js} +56 -53
  91. package/{memoryCommands-O4MIPIWQ.js → memoryCommands-AFMES3LN.js} +5 -5
  92. package/{models-4OPOOLFS.js → models-LSCRJJ6P.js} +2 -2
  93. package/package.json +1 -1
  94. package/{read-QJNKRROM.js → read-2MIMRBZ2.js} +4 -4
  95. package/{readDocTool-H6X6KO6X.js → readDocTool-QHVGQHUJ.js} +1 -1
  96. package/{readlineWorkspace-HGP3I3OC.js → readlineWorkspace-OMRWYMB6.js} +1279 -716
  97. package/{removeDialogAgentAction-TCT35SOF.js → removeDialogAgentAction-XUZYQBV4.js} +13 -13
  98. package/{runAgentClientLoop-EFM4PTVI.js → runAgentClientLoop-FP2K33ZO.js} +47 -46
  99. package/{runtimeDoctorCommands-ID43Z7VX.js → runtimeDoctorCommands-QNF3J3UV.js} +6 -6
  100. package/{setDialogExtraReferencesAction-CGYLZMFH.js → setDialogExtraReferencesAction-PTAIFKGM.js} +9 -10
  101. package/{setPrimaryDialogAgentAction-F6BFQDJU.js → setPrimaryDialogAgentAction-HRFTDB44.js} +13 -13
  102. package/{settingSlice-2I5HMG47.js → settingSlice-VGRJUSE5.js} +7 -8
  103. package/{skillDiscovery-UGSQGX2U.js → skillDiscovery-6M2BZUFN.js} +3 -3
  104. package/{spaceCommands-MT7BWCIL.js → spaceCommands-GN73BCOB.js} +38 -29
  105. package/{spaceSlice-BS5TSW3W.js → spaceSlice-WTFNKOVA.js} +30 -26
  106. package/{streamAgentChatTurn-I3VBFNR3.js → streamAgentChatTurn-HBAQQVNK.js} +442 -130
  107. package/{toolApiClient-C7P7YSE4.js → toolApiClient-QI3YBNWB.js} +2 -2
  108. package/{tools-XSD2BOEN.js → tools-TPQYTLQZ.js} +34 -33
  109. package/{tuiSummaryLlmCaller-32NRHTT2.js → tuiSummaryLlmCaller-XDC7WG4K.js} +11 -7
  110. package/{updateCommands-VOSPKXFF.js → updateCommands-XZDOOYFH.js} +13 -5
  111. package/{updateDialogTitleAction-7FYNJOGP.js → updateDialogTitleAction-AWXNPUQJ.js} +30 -29
  112. package/chunk-AZPCASRE.js +0 -36
  113. package/chunk-BBYVOSU2.js +0 -792
  114. package/chunk-DCOA4QSN.js +0 -105
  115. package/chunk-UAD2WT54.js +0 -64
  116. package/{chunk-JK7VW2FN.js → chunk-5MIDPSSK.js} +3 -3
  117. package/{chunk-5CS33IBL.js → chunk-PDL2AV3E.js} +3 -3
  118. package/{chunk-5MMZUWSG.js → chunk-TOILAPLH.js} +5 -5
  119. package/{chunk-OOM6SJNR.js → chunk-TSUJOM6N.js} +6 -6
  120. package/{db-6QED3ZVO.js → db-HCJ5PRB5.js} +3 -3
  121. package/{offlineMarxistsAgentCommand-BCPJITJL.js → offlineMarxistsAgentCommand-5OOWZLJI.js} +3 -3
  122. package/{tableCommands-M3DJUETS.js → tableCommands-E4SQWDOX.js} +6 -6
  123. package/{understanding-ZOESBLF3.js → understanding-3CUQQ6SV.js} +3 -3
@@ -3,7 +3,7 @@ import {
3
3
  refreshAntigravityOAuthToken,
4
4
  refreshOpenAiCodexToken,
5
5
  refreshXaiOAuthToken
6
- } from "./chunk-5MMZUWSG.js";
6
+ } from "./chunk-TOILAPLH.js";
7
7
  import {
8
8
  CliProviderQuotaError,
9
9
  executeCli
@@ -12,7 +12,7 @@ import {
12
12
  buildLocalAgentLookupKeys,
13
13
  normalizeAgentHandle,
14
14
  shouldReadAgentKeyRemotely
15
- } from "./chunk-C2MDQQ4O.js";
15
+ } from "./chunk-VBSWHE5W.js";
16
16
  import {
17
17
  LOCAL_CODEX_AGENT_ID,
18
18
  LOCAL_CODEX_AGENT_KEY,
@@ -21,45 +21,57 @@ import {
21
21
  } from "./chunk-VHBWHNVT.js";
22
22
  import {
23
23
  inferCaptureIntent
24
- } from "./chunk-5OIFWVX7.js";
24
+ } from "./chunk-QJSTNKJY.js";
25
25
  import {
26
26
  buildCliPrompt
27
27
  } from "./chunk-ATNTHIZI.js";
28
28
  import {
29
+ inlineImageUrlsForCustomProvider,
29
30
  prepareTools
30
- } from "./chunk-PXQN7IBQ.js";
31
+ } from "./chunk-C3BFP57W.js";
31
32
  import {
32
33
  getAntigravityUserAgent,
33
34
  isAntigravityOAuthAgent,
34
35
  readAntigravityProjectId,
35
36
  resolveAntigravityCloudCodeBaseUrl
36
- } from "./chunk-FXXSGWAJ.js";
37
+ } from "./chunk-H5Y2H2N6.js";
37
38
  import {
38
39
  FORCED_TOOLS,
39
40
  addDefaultLightWebToolsForConfiguredAgents,
41
+ appendEnabledPackPromptPatches,
40
42
  applyDisabledTools,
41
43
  expandEnabledPacks,
44
+ formatListRunsCard,
45
+ formatNotFoundRunCard,
46
+ formatStartRunCard,
47
+ formatStatusRunCard,
48
+ formatStopRunCard,
42
49
  readXPostFunc,
43
50
  readXPostFunctionSchema,
44
51
  readXhsProfileFunc,
45
52
  readXhsProfileFunctionSchema
46
- } from "./chunk-2W2VYVI5.js";
53
+ } from "./chunk-MZHSAPZP.js";
47
54
  import {
48
- CORE_DRAIN_REASON
49
- } from "./chunk-D6OQHXVG.js";
55
+ createDrainExhaustedResponse,
56
+ isCoreDrainingBody,
57
+ normalizeNonNegativeMs,
58
+ parseRetryAfterHeaderMs
59
+ } from "./chunk-RQSOAMPJ.js";
50
60
  import {
51
61
  normalizeDialogTitle
52
62
  } from "./chunk-OWOHNGCN.js";
63
+ import {
64
+ prepareTokenUsageData
65
+ } from "./chunk-FSUZIGIG.js";
53
66
  import {
54
67
  BUILTIN_TITLE_LLM_CONFIG
55
- } from "./chunk-4ZDM73SD.js";
68
+ } from "./chunk-V2J635L5.js";
56
69
  import {
57
70
  fetchServerSyncedCredential
58
- } from "./chunk-Q3UKJVU4.js";
71
+ } from "./chunk-Y5P3ZRGC.js";
59
72
  import {
60
73
  buildAgentRuntimeDialogWritePlan,
61
74
  buildLocalWorkspaceOpenAiTools,
62
- buildLocalWorkspacePolicyToolNames,
63
75
  buildLocalWorkspaceToolset,
64
76
  createHybridRecordStore,
65
77
  createLocalWorkspaceToolExecutors,
@@ -69,32 +81,32 @@ import {
69
81
  parseSseDataLineJson,
70
82
  readOpenAiCompatibleSseCompletion,
71
83
  resolveOpenAiCompatibleProviderConfig
72
- } from "./chunk-BX6U3ETE.js";
84
+ } from "./chunk-MG6BVV3T.js";
73
85
  import {
74
86
  buildPlatformChatCompletionRequest,
75
87
  canUsePlatformChatProvider,
76
88
  parsePlatformChatCompletionData,
77
89
  parsePlatformChatCompletionResponse,
78
90
  readSseDataValues,
91
+ resolveLegacyDeepSeekProxyChatFallback,
79
92
  resolvePlatformChatProviderConfig,
80
93
  shouldUsePlatformChatProvider
81
- } from "./chunk-ZPRK73XY.js";
94
+ } from "./chunk-5S4SWV5G.js";
82
95
  import {
83
96
  resolveAgentRuntimeConfigFromRecord
84
- } from "./chunk-YOCHZD7D.js";
97
+ } from "./chunk-NCGFB7NN.js";
85
98
  import {
86
99
  parseToolArgumentsJson,
87
100
  summarizeToolArguments
88
- } from "./chunk-S3GS2PRL.js";
101
+ } from "./chunk-TA7VKOHU.js";
89
102
  import {
90
103
  buildLoadSkillExecutor,
91
104
  buildNoloWorkspaceCliToolExecutors,
92
105
  buildNoloWorkspaceOpenAiTools,
93
106
  canonicalizeToolNames,
94
- filterNoloWorkspaceToolNames,
95
107
  parseNoloWorkspaceToolArguments,
96
108
  resolveRuntimeToolSurfaceForAgent
97
- } from "./chunk-4SOKXIW4.js";
109
+ } from "./chunk-B4KT7RN2.js";
98
110
  import {
99
111
  clipCompactText
100
112
  } from "./chunk-5MMAK75Q.js";
@@ -103,45 +115,42 @@ import {
103
115
  resolveCurrentRunRuntimeToolPolicy,
104
116
  resolveLocalWorkspaceExecutorOptionsFromPolicy,
105
117
  resolveRequestedRuntimeToolNames
106
- } from "./chunk-5CS33IBL.js";
118
+ } from "./chunk-PDL2AV3E.js";
107
119
  import {
108
120
  createOAuthTokenStore,
109
121
  isTokenExpired,
110
122
  readOAuthCredential,
111
123
  resolveFreshAccessToken
112
124
  } from "./chunk-JZPBVBIY.js";
113
- import {
114
- asRecordOrEmpty
115
- } from "./chunk-KX6YBIHG.js";
116
- import {
117
- dialogMessageRange
118
- } from "./chunk-O4BU24WZ.js";
119
- import {
120
- asTrimmedNonEmptyStringArray
121
- } from "./chunk-I42VC5KR.js";
122
- import {
123
- asOptionalFiniteNumber
124
- } from "./chunk-WWC7I6TA.js";
125
125
  import {
126
126
  checkStaleRun,
127
127
  finalizeRunRecord,
128
128
  findRunRecord,
129
129
  listRunRecords,
130
130
  spawnLocalBackgroundRun
131
- } from "./chunk-2FTTDCD4.js";
132
- import {
133
- isCompiledBinary,
134
- parseUserIdFromAuthToken
135
- } from "./chunk-ISNCLGUZ.js";
136
- import {
137
- DEFAULT_NOLO_SERVER_URL
138
- } from "./chunk-OLZBQWZU.js";
131
+ } from "./chunk-4ON5AV72.js";
139
132
  import {
140
133
  toErrorMessage
141
134
  } from "./chunk-HNMXYYJR.js";
142
135
  import {
143
136
  getDefaultCliLocalRuntimeDb
144
137
  } from "./chunk-H33743XH.js";
138
+ import {
139
+ compactWhitespace
140
+ } from "./chunk-DWLEOOGR.js";
141
+ import {
142
+ asRecordOrEmpty
143
+ } from "./chunk-KX6YBIHG.js";
144
+ import {
145
+ createTokenKey,
146
+ dialogMessageRange
147
+ } from "./chunk-O4BU24WZ.js";
148
+ import {
149
+ asTrimmedNonEmptyStringArray
150
+ } from "./chunk-I42VC5KR.js";
151
+ import {
152
+ asOptionalFiniteNumber
153
+ } from "./chunk-WWC7I6TA.js";
145
154
  import {
146
155
  BUILTIN_NOLO_AGENT_KEY,
147
156
  PUBLIC_DEEPSEEK_V4_FLASH_AGENT_KEY,
@@ -149,19 +158,26 @@ import {
149
158
  PUBLIC_GLM_52_AGENT_KEY,
150
159
  PUBLIC_KIMI_K26_IMAGE_AGENT_KEY,
151
160
  PUBLIC_KIMI_K27_CODING_AGENT_KEY
152
- } from "./chunk-XFOLQLDN.js";
161
+ } from "./chunk-XHQWJUW4.js";
162
+ import {
163
+ isRecord
164
+ } from "./chunk-KUG52IAP.js";
153
165
  import {
154
166
  asTrimmedString
155
167
  } from "./chunk-3EUW3WEO.js";
156
168
  import {
157
- isRecord
158
- } from "./chunk-KUG52IAP.js";
169
+ isCompiledBinary,
170
+ parseUserIdFromAuthToken
171
+ } from "./chunk-5NBHQD4D.js";
159
172
  import {
160
- isLoopbackHostname
161
- } from "./chunk-4SN6J65J.js";
173
+ DEFAULT_NOLO_SERVER_URL
174
+ } from "./chunk-OLZBQWZU.js";
162
175
  import {
163
176
  NOLO_CLUSTER_SERVERS
164
177
  } from "./chunk-LCBAMY2M.js";
178
+ import {
179
+ isLoopbackHostname
180
+ } from "./chunk-4SN6J65J.js";
165
181
  import {
166
182
  normalizeServerOrigin
167
183
  } from "./chunk-CF7PE763.js";
@@ -169,6 +185,718 @@ import {
169
185
  asOptionalTrimmedString
170
186
  } from "./chunk-G3SUCT4W.js";
171
187
 
188
+ // packages/cli/tui/i18n.ts
189
+ var ZH_PATTERNS = /^zh/i;
190
+ function parseCliLocale(raw) {
191
+ const normalized = raw?.trim().toLowerCase();
192
+ if (!normalized) return null;
193
+ if (ZH_PATTERNS.test(normalized)) return "zh";
194
+ if (normalized === "en" || normalized.startsWith("en")) return "en";
195
+ return null;
196
+ }
197
+ function detectLocaleFromEnv(env) {
198
+ const explicit = parseCliLocale(env.NOLO_LANG);
199
+ if (explicit) return explicit;
200
+ const candidates = [env.LC_ALL, env.LC_CTYPE, env.LANG].filter(Boolean);
201
+ for (const candidate of candidates) {
202
+ if (ZH_PATTERNS.test(candidate)) return "zh";
203
+ if (candidate && !candidate.startsWith("C.") && !candidate.startsWith("POSIX")) {
204
+ return "en";
205
+ }
206
+ }
207
+ return null;
208
+ }
209
+ function detectLocale(env) {
210
+ return detectLocaleFromEnv(env) ?? "zh";
211
+ }
212
+ var currentLocale = detectLocale(process.env);
213
+ function getCliLocale() {
214
+ return currentLocale;
215
+ }
216
+ function setCliLocale(locale) {
217
+ currentLocale = locale;
218
+ }
219
+ function initCliLocale(env = process.env) {
220
+ currentLocale = detectLocale(env);
221
+ }
222
+ function newlineHint(platform = process.platform) {
223
+ return platform === "win32" ? "Ctrl+J" : "Shift+Enter";
224
+ }
225
+ var STRINGS = {
226
+ welcomeHint: {
227
+ en: `Tell nolo what you want. Use /help for commands. ${newlineHint()} for newline.`,
228
+ zh: `\u544A\u8BC9 nolo \u4F60\u60F3\u8981\u4EC0\u4E48\u3002\u8F93\u5165 /help \u67E5\u770B\u547D\u4EE4\u3002${newlineHint()} \u6362\u884C\u3002`
229
+ },
230
+ promptLabel: {
231
+ en: "\u276F ",
232
+ zh: "\u276F "
233
+ },
234
+ continueLabel: {
235
+ en: "\u2502 ",
236
+ zh: "\u2502 "
237
+ },
238
+ placeholder: {
239
+ en: "Type a message or / for commands...",
240
+ zh: "\u8F93\u5165\u6D88\u606F\uFF0C\u6216\u7528 / \u67E5\u770B\u547D\u4EE4\u2026"
241
+ },
242
+ newDialog: {
243
+ en: "new dialog",
244
+ zh: "\u65B0\u5BF9\u8BDD"
245
+ },
246
+ startedFreshDialog: {
247
+ en: "Started a fresh dialog.",
248
+ zh: "\u5DF2\u5F00\u59CB\u65B0\u5BF9\u8BDD\u3002"
249
+ },
250
+ bye: {
251
+ en: "Bye.",
252
+ zh: "\u518D\u89C1\u3002"
253
+ },
254
+ resumedDialogPrefix: {
255
+ en: "Resumed dialog",
256
+ zh: "\u5DF2\u6062\u590D\u5BF9\u8BDD"
257
+ },
258
+ resumeInvalidId: {
259
+ en: "does not look like a dialog id. Use /history to pick one.",
260
+ zh: "\u770B\u8D77\u6765\u4E0D\u662F dialog id\u3002\u7528 /history \u4ECE\u5217\u8868\u91CC\u9009\u4E00\u4E2A\u3002"
261
+ },
262
+ dialogResumeCancelled: {
263
+ en: "Dialog resume cancelled.",
264
+ zh: "\u5DF2\u53D6\u6D88\u6062\u590D\u5BF9\u8BDD\u3002"
265
+ },
266
+ agentSwitchCancelled: {
267
+ en: "Agent switch cancelled.",
268
+ zh: "\u5DF2\u53D6\u6D88\u5207\u6362 agent\u3002"
269
+ },
270
+ historyPickerTitle: {
271
+ en: "Resume dialog (\u2191\u2193 Enter Esc)",
272
+ zh: "\u6062\u590D\u5BF9\u8BDD\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
273
+ },
274
+ noDialogsYet: {
275
+ en: "No dialogs yet.",
276
+ zh: "\u8FD8\u6CA1\u6709\u5386\u53F2\u5BF9\u8BDD\u3002"
277
+ },
278
+ langUsage: {
279
+ en: "Usage: /lang <zh|en>",
280
+ zh: "\u7528\u6CD5\uFF1A/lang <zh|en>"
281
+ },
282
+ stopHint: {
283
+ en: "Esc to stop",
284
+ zh: "Esc \u505C\u6B62\u56DE\u590D"
285
+ },
286
+ queuedHint: {
287
+ en: "queued",
288
+ zh: "\u6392\u961F"
289
+ },
290
+ turnStopped: {
291
+ en: "Stopped this reply.",
292
+ zh: "\u5DF2\u505C\u6B62\u672C\u6B21\u56DE\u590D\u3002"
293
+ },
294
+ turnStoppedToolPending: {
295
+ en: "Stopped waiting. {0} may still be finishing in the background \u2014 its result won't be added to this conversation.",
296
+ 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"
297
+ },
298
+ turnStopping: {
299
+ en: "Stopping\u2026 press Esc again to force",
300
+ zh: "\u6B63\u5728\u505C\u6B62\u2026\u518D\u6309\u4E00\u6B21 Esc \u5F3A\u5236\u505C\u6B62"
301
+ },
302
+ forceStopped: {
303
+ en: "Force stopped. Background tasks may still be finishing.",
304
+ zh: "\u5DF2\u5F3A\u5236\u505C\u6B62\uFF0C\u540E\u53F0\u4EFB\u52A1\u53EF\u80FD\u4ECD\u5728\u6536\u5C3E\u3002"
305
+ },
306
+ turnFailed: {
307
+ en: "This reply failed. Queued messages are kept \u2014 press Enter to resend.",
308
+ 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"
309
+ },
310
+ quotaExhaustedHint: {
311
+ en: "[nolo] 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.",
312
+ zh: "[nolo] \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"
313
+ },
314
+ balanceExhaustedHint: {
315
+ en: '[nolo] Insufficient balance. Your message is saved in this dialog \u2014 top up, then send again or say "continue".',
316
+ zh: "[nolo] \u4F59\u989D\u4E0D\u8DB3\u3002\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\uFF0C\u4E0D\u4F1A\u4E22\u4E0A\u4E0B\u6587\u3002"
317
+ },
318
+ dialogPreservedHint: {
319
+ en: '[nolo] This turn failed, but the dialog is kept. Send another message (or say "continue") to keep going in the same conversation.',
320
+ zh: "[nolo] \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"
321
+ },
322
+ dialogNotSavedHint: {
323
+ en: "[nolo] This turn did not create a dialog. Your next message will start a new conversation \u2014 restate what you need.",
324
+ zh: "[nolo] \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"
325
+ },
326
+ copiedLastReply: {
327
+ en: "Copied the last reply to the clipboard.",
328
+ zh: "\u5DF2\u590D\u5236\u6700\u540E\u4E00\u6761\u56DE\u590D\u5230\u526A\u8D34\u677F\u3002"
329
+ },
330
+ copyNothing: {
331
+ en: "Nothing to copy yet.",
332
+ zh: "\u8FD8\u6CA1\u6709\u53EF\u590D\u5236\u7684\u5185\u5BB9\u3002"
333
+ },
334
+ copyFailed: {
335
+ en: "Copy failed",
336
+ zh: "\u590D\u5236\u5931\u8D25"
337
+ },
338
+ copyUnavailable: {
339
+ en: "Clipboard is unavailable in this environment. The last reply was printed above for manual copy.",
340
+ 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"
341
+ },
342
+ copyUsage: {
343
+ en: "Usage: /copy or /copy view",
344
+ zh: "\u7528\u6CD5\uFF1A/copy \u6216 /copy view"
345
+ },
346
+ copyViewTitle: {
347
+ en: "Copy view \u2014 latest AI reply",
348
+ zh: "\u590D\u5236\u89C6\u56FE \u2014 \u6700\u65B0 AI \u56DE\u590D"
349
+ },
350
+ copyViewHint: {
351
+ en: "Drag to select; edge scrolling uses native terminal scrollback. Press Esc or Enter to return.",
352
+ zh: "\u76F4\u63A5\u62D6\u9009\uFF0C\u62D6\u5230\u8FB9\u7F18\u53EF\u7528\u7EC8\u7AEF\u539F\u751F\u56DE\u6EDA\u8DE8\u5C4F\u9009\u62E9\u3002\u6309 Esc \u6216 Enter \u8FD4\u56DE\u3002"
353
+ },
354
+ historyNoToken: {
355
+ en: "History requires an auth token. Run `nolo login` or set AUTH_TOKEN.",
356
+ 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"
357
+ },
358
+ historyBadToken: {
359
+ en: "Could not read a user id from AUTH_TOKEN. Run `nolo login` again.",
360
+ zh: "\u65E0\u6CD5\u4ECE AUTH_TOKEN \u89E3\u6790\u51FA\u7528\u6237 id\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C `nolo login`\u3002"
361
+ },
362
+ mouseOn: {
363
+ en: "Mouse mode on: wheel scrolls the transcript; hold Shift (or Option/Fn) to select text.",
364
+ 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"
365
+ },
366
+ mouseOff: {
367
+ en: "Mouse mode off: drag to select/copy freely; scroll with PageUp/PageDown.",
368
+ 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"
369
+ },
370
+ mouseUsage: {
371
+ en: "Usage: /mouse <on|off>",
372
+ zh: "\u7528\u6CD5\uFF1A/mouse <on|off>"
373
+ },
374
+ altscreenOn: {
375
+ en: "Alternate screen on: the TUI uses a private buffer so the terminal wheel no longer fights its own scroll state.",
376
+ 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"
377
+ },
378
+ altscreenOff: {
379
+ en: "Alternate screen off: the TUI shares the shell scrollback (wheel may desync the viewport).",
380
+ 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"
381
+ },
382
+ altscreenUsage: {
383
+ en: "Usage: /altscreen <on|off>",
384
+ zh: "\u7528\u6CD5\uFF1A/altscreen <on|off>"
385
+ },
386
+ langSwitched: {
387
+ en: "Language switched to English.",
388
+ zh: "\u5DF2\u5207\u6362\u4E3A\u4E2D\u6587\u3002"
389
+ },
390
+ // --- Tool trace copy ------------------------------------------------------
391
+ // The compact trace shows only status, never timing or output size: a line
392
+ // count told the user nothing actionable and the ms figure read as noise.
393
+ toolNeedsAction: {
394
+ en: "needs action",
395
+ zh: "\u5F85\u786E\u8BA4"
396
+ },
397
+ toolTimedOut: {
398
+ en: "timed out",
399
+ zh: "\u5DF2\u8D85\u65F6"
400
+ },
401
+ toolExitCode: {
402
+ en: "exit",
403
+ zh: "\u9000\u51FA\u7801"
404
+ },
405
+ toolFailed: {
406
+ en: "failed",
407
+ zh: "\u5931\u8D25"
408
+ },
409
+ usedSkillLabel: {
410
+ en: "Used Skill",
411
+ zh: "\u5DF2\u52A0\u8F7D\u6280\u80FD"
412
+ },
413
+ // --- Agent-run orchestration cards (injected into packages/ai helpers) ---
414
+ runStatusLabel: {
415
+ en: "Run status",
416
+ zh: "\u8FD0\u884C\u72B6\u6001"
417
+ },
418
+ runStartedLabel: {
419
+ en: "Run started",
420
+ zh: "\u8FD0\u884C\u5DF2\u542F\u52A8"
421
+ },
422
+ runStoppedLabel: {
423
+ en: "Run stopped",
424
+ zh: "\u8FD0\u884C\u5DF2\u505C\u6B62"
425
+ },
426
+ runLogTailLabel: {
427
+ en: "Log tail:",
428
+ zh: "\u65E5\u5FD7\u5C3E\u90E8\uFF1A"
429
+ },
430
+ runsListLabel: {
431
+ en: "Runs ({0})",
432
+ zh: "\u8FD0\u884C ({0})"
433
+ },
434
+ // --- Dialog (picker / confirm) copy --------------------------------------
435
+ // Key-hint wording is unified across select / multi-select / confirm so the
436
+ // three dialogs read as one family: "<Label> <↑↓ move · Enter choose ·
437
+ // Esc cancel> <count>". Connectors are "·" between keys, two spaces between
438
+ // the label, hint, and count. zh uses full-width parentheses to match the
439
+ // existing historyPickerTitle; en uses ASCII parentheses.
440
+ dialogSelectLabel: {
441
+ en: "Select",
442
+ zh: "\u9009\u62E9"
443
+ },
444
+ dialogSelectHint: {
445
+ en: "(\u2191\u2193 move \xB7 Enter choose \xB7 Esc cancel)",
446
+ zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
447
+ },
448
+ dialogMultiSelectLabel: {
449
+ en: "Select",
450
+ zh: "\u9009\u62E9"
451
+ },
452
+ dialogMultiSelectHint: {
453
+ en: "(\u2191\u2193 move \xB7 Space toggle \xB7 Enter submit \xB7 Esc cancel)",
454
+ zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Space \u5207\u6362 \xB7 Enter \u63D0\u4EA4 \xB7 Esc \u53D6\u6D88\uFF09"
455
+ },
456
+ dialogMultiSelectSelected: {
457
+ en: "selected",
458
+ zh: "\u5DF2\u9009"
459
+ },
460
+ dialogConfirmHint: {
461
+ en: "(\u2191\u2193 move \xB7 Enter choose \xB7 Esc cancel)",
462
+ zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
463
+ },
464
+ dialogConfirmTitle: {
465
+ en: "Confirm destructive shell command",
466
+ zh: "\u786E\u8BA4\u6267\u884C\u7834\u574F\u6027 shell \u547D\u4EE4"
467
+ },
468
+ dialogConfirmBody: {
469
+ en: "This command may delete or reset user content and needs explicit confirmation before it runs.",
470
+ 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"
471
+ },
472
+ dialogConfirmExternalFileTitle: {
473
+ en: "Confirm reading a file outside the workspace",
474
+ zh: "\u786E\u8BA4\u8BFB\u53D6\u5DE5\u4F5C\u533A\u5916\u90E8\u6587\u4EF6"
475
+ },
476
+ dialogConfirmExternalFileBody: {
477
+ en: "This path is outside the current workspace. Allow this one-time access, or deny it.",
478
+ 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"
479
+ },
480
+ dialogConfirmCommandTruncated: {
481
+ en: "(truncated)",
482
+ zh: "\uFF08\u5DF2\u622A\u65AD\uFF09"
483
+ },
484
+ dialogConfirmAllowLabel: {
485
+ en: "Allow",
486
+ zh: "\u5141\u8BB8"
487
+ },
488
+ dialogConfirmAllowDetail: {
489
+ en: "execute this time",
490
+ zh: "\u672C\u6B21\u6267\u884C"
491
+ },
492
+ dialogConfirmCancelLabel: {
493
+ en: "Cancel",
494
+ zh: "\u53D6\u6D88"
495
+ },
496
+ dialogConfirmCancelDetail: {
497
+ en: "abort the operation",
498
+ zh: "\u4E2D\u6B62\u64CD\u4F5C"
499
+ },
500
+ // --- Ask choice (ui_ask_choice) ------------------------------------------
501
+ askChoiceTitle: {
502
+ en: "question",
503
+ zh: "\u95EE\u9898"
504
+ },
505
+ askChoiceSubmit: {
506
+ en: "Submit",
507
+ zh: "\u63D0\u4EA4"
508
+ },
509
+ askChoiceOtherLabel: {
510
+ en: "Other",
511
+ zh: "\u5176\u4ED6"
512
+ },
513
+ askChoiceHintSingle: {
514
+ en: "Type your answer, then press Enter to save.",
515
+ zh: "\u8F93\u5165\u56DE\u7B54\u540E\u6309 Enter \u4FDD\u5B58\u3002"
516
+ },
517
+ askChoiceHintMulti: {
518
+ en: "Space to toggle, Enter to confirm selection.",
519
+ zh: "\u7A7A\u683C\u5207\u6362\u9009\u4E2D\uFF0CEnter \u786E\u8BA4\u63D0\u4EA4\u3002"
520
+ },
521
+ askChoiceFooterSingle: {
522
+ en: "\u21B5 pick/submit \xB7 tab switch \xB7 esc cancel",
523
+ zh: "\u21B5 \u9009\u62E9/\u63D0\u4EA4 \xB7 tab \u5207\u6362 \xB7 esc \u53D6\u6D88"
524
+ },
525
+ askChoiceFooterMulti: {
526
+ en: "\u21B5 submit \xB7 space toggle \xB7 tab switch \xB7 esc cancel",
527
+ zh: "\u21B5 \u63D0\u4EA4 \xB7 space \u5207\u6362 \xB7 tab \u5207\u6362 \xB7 esc \u53D6\u6D88"
528
+ },
529
+ askChoiceHistoryHint: {
530
+ en: "Type a number to choose, or reply directly:",
531
+ zh: "\u8BF7\u8F93\u5165\u5E8F\u53F7\u9009\u62E9\uFF0C\u6216\u76F4\u63A5\u56DE\u590D\uFF1A"
532
+ },
533
+ askChoiceHistorySelected: {
534
+ en: "selected",
535
+ zh: "\u5DF2\u9009"
536
+ },
537
+ askChoiceHistoryCancelled: {
538
+ en: "cancelled",
539
+ zh: "\u5DF2\u53D6\u6D88"
540
+ },
541
+ contextTitle: {
542
+ en: "Workspace context",
543
+ zh: "\u5DE5\u4F5C\u533A\u4E0A\u4E0B\u6587"
544
+ },
545
+ contextNext: {
546
+ en: "Next:",
547
+ zh: "\u4E0B\u4E00\u6B65\uFF1A"
548
+ },
549
+ contextFieldAgent: {
550
+ en: "agent",
551
+ zh: "\u667A\u80FD\u4F53"
552
+ },
553
+ contextFieldTokens: {
554
+ en: "tokens",
555
+ zh: "\u4EE4\u724C"
556
+ },
557
+ contextFieldDialog: {
558
+ en: "dialog",
559
+ zh: "\u5BF9\u8BDD"
560
+ },
561
+ contextFieldDocs: {
562
+ en: "docs",
563
+ zh: "\u6587\u6863"
564
+ },
565
+ contextFieldSkills: {
566
+ en: "skills",
567
+ zh: "\u6280\u80FD"
568
+ },
569
+ contextFieldProfile: {
570
+ en: "profile",
571
+ zh: "\u914D\u7F6E"
572
+ },
573
+ contextFieldRuntime: {
574
+ en: "runtime",
575
+ zh: "\u8FD0\u884C\u65F6"
576
+ },
577
+ contextFieldTools: {
578
+ en: "tools",
579
+ zh: "\u5DE5\u5177"
580
+ },
581
+ contextFieldThinking: {
582
+ en: "thinking",
583
+ zh: "\u601D\u8003"
584
+ },
585
+ contextFieldServer: {
586
+ en: "server",
587
+ zh: "\u670D\u52A1\u7AEF"
588
+ },
589
+ contextNextAgents: {
590
+ en: "see specialist shortcuts",
591
+ zh: "\u67E5\u770B\u4E13\u7528\u667A\u80FD\u4F53\u5FEB\u6377\u65B9\u5F0F"
592
+ },
593
+ contextNextDoc: {
594
+ en: "add working context",
595
+ zh: "\u6DFB\u52A0\u5DE5\u4F5C\u4E0A\u4E0B\u6587"
596
+ },
597
+ contextNextSkill: {
598
+ en: "attach a skill to this workspace",
599
+ zh: "\u4E3A\u8BE5\u5DE5\u4F5C\u533A\u6302\u8F7D\u6280\u80FD"
600
+ },
601
+ contextNextNew: {
602
+ en: "start a clean dialog",
603
+ zh: "\u5F00\u59CB\u4E00\u4E2A\u5E72\u51C0\u7684\u5BF9\u8BDD"
604
+ },
605
+ agentsTitle: {
606
+ en: "Agents:",
607
+ zh: "\u667A\u80FD\u4F53\uFF1A"
608
+ },
609
+ agentsTip: {
610
+ en: "Tip: run /switch for the full picker, or /switch list for your private agents too.",
611
+ 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"
612
+ },
613
+ helpText: {
614
+ en: [
615
+ "Commands:",
616
+ " /help Show this help",
617
+ " /new Clear screen and start a fresh dialog",
618
+ " /compact Compact current dialog and fork a new one",
619
+ " /context Show workspace context and next actions",
620
+ " /runtime <mode> Use auto, local, or server runtime",
621
+ " /tools <mode> Control tool trace: hide, compact, verbose",
622
+ " /thinking <mode> Control thinking output: hide, marker, show",
623
+ " /switch Pick an agent interactively (\u2191\u2193, Enter)",
624
+ " /switch list List agents as text",
625
+ " /switch <name> Switch directly by name, alias, or key (alias: /agent)",
626
+ " /agents List platform agent shortcuts",
627
+ " /history Pick a recent dialog to resume (\u2191\u2193, Enter)",
628
+ " /resume <dialogId> Resume a dialog directly by id",
629
+ " /lang <zh|en> Switch interface language",
630
+ " /copy Copy the last reply to the clipboard",
631
+ " /copy view Open native scrollback for partial selection (Ctrl+O)",
632
+ " /mouse <on|off> Toggle mouse mode (off = drag to select text)",
633
+ " /altscreen <on|off> Toggle the terminal alternate screen (default on; off shares shell scrollback)",
634
+ " /doc List attached docs",
635
+ " /doc attach <doc> Attach a doc to this workspace",
636
+ " /skill List attached skills",
637
+ " /skill attach <ref> Attach a skill (dbKey, name, or SKILL.md path)",
638
+ " /skill detach <ref> Detach a skill",
639
+ " /skill clear Detach all skills",
640
+ " /customize Describe how you want to tune nolo",
641
+ " /tasks List background process tasks (aliases: /jobs, /procs)",
642
+ " /stop <pid|all> Stop background process tasks",
643
+ " /login Show login/profile hint",
644
+ " /profile Show active profile",
645
+ " /update Update the nolo CLI install",
646
+ " /version Show version/update hint",
647
+ " /exit Leave the workspace",
648
+ "",
649
+ "You can also type normally. nolo routes simple read/status requests to CLI commands and sends the rest to the current agent."
650
+ ].join("\n"),
651
+ zh: [
652
+ "\u547D\u4EE4\uFF1A",
653
+ " /help \u663E\u793A\u672C\u5E2E\u52A9",
654
+ " /new \u6E05\u5C4F\u5E76\u5F00\u59CB\u65B0\u5BF9\u8BDD",
655
+ " /compact \u538B\u7F29\u5F53\u524D\u5BF9\u8BDD\u5E76\u5206\u53C9\u51FA\u65B0\u5BF9\u8BDD",
656
+ " /context \u67E5\u770B\u5DE5\u4F5C\u533A\u4E0A\u4E0B\u6587\u4E0E\u540E\u7EED\u64CD\u4F5C",
657
+ " /runtime <mode> \u5207\u6362 runtime\uFF1Aauto\u3001local\u3001server",
658
+ " /tools <mode> \u5DE5\u5177\u8F68\u8FF9\u663E\u793A\uFF1Ahide\u3001compact\u3001verbose",
659
+ " /thinking <mode> \u601D\u8003\u8FC7\u7A0B\u663E\u793A\uFF1Ahide\u3001marker\u3001show",
660
+ " /switch \u4EA4\u4E92\u5F0F\u9009\u62E9 agent\uFF08\u2191\u2193 \u79FB\u52A8\uFF0CEnter \u786E\u8BA4\uFF09",
661
+ " /switch list \u4EE5\u6587\u672C\u5217\u51FA\u5168\u90E8 agent",
662
+ " /switch <name> \u6309\u540D\u79F0\u3001\u522B\u540D\u6216 key \u76F4\u63A5\u5207\u6362\uFF08\u522B\u540D\uFF1A/agent\uFF09",
663
+ " /agents \u5217\u51FA\u5E73\u53F0 agent \u5FEB\u6377\u65B9\u5F0F",
664
+ " /history \u4ECE\u6700\u8FD1\u5BF9\u8BDD\u4E2D\u9009\u62E9\u5E76\u6062\u590D\uFF08\u2191\u2193\uFF0CEnter\uFF09",
665
+ " /resume <dialogId> \u6309 id \u76F4\u63A5\u6062\u590D\u5BF9\u8BDD",
666
+ " /lang <zh|en> \u5207\u6362\u754C\u9762\u8BED\u8A00",
667
+ " /copy \u590D\u5236\u6700\u540E\u4E00\u6761\u56DE\u590D\u5230\u526A\u8D34\u677F",
668
+ " /copy view \u6253\u5F00\u539F\u751F\u56DE\u6EDA\u8FDB\u884C\u8DE8\u5C4F\u62D6\u9009\uFF08Ctrl+O\uFF09",
669
+ " /mouse <on|off> \u5207\u6362\u9F20\u6807\u6A21\u5F0F\uFF08off \u540E\u53EF\u76F4\u63A5\u62D6\u9009\u6587\u672C\uFF09",
670
+ " /altscreen <on|off> \u5207\u6362\u7EC8\u7AEF\u5907\u7528\u5C4F\uFF08\u9ED8\u8BA4 on\uFF1Boff \u6539\u4E3A\u4E0E shell \u5171\u7528\u56DE\u6EDA\uFF09",
671
+ " /doc \u5217\u51FA\u5DF2\u6302\u8F7D\u7684\u6587\u6863",
672
+ " /doc attach <doc> \u6302\u8F7D\u6587\u6863\u5230\u5F53\u524D\u5DE5\u4F5C\u533A",
673
+ " /skill \u5217\u51FA\u5DF2\u6302\u8F7D\u7684\u6280\u80FD",
674
+ " /skill attach <ref> \u6302\u8F7D\u6280\u80FD\uFF08dbKey\u3001\u540D\u79F0\u6216 SKILL.md \u8DEF\u5F84\uFF09",
675
+ " /skill detach <ref> \u5378\u8F7D\u6307\u5B9A\u6280\u80FD",
676
+ " /skill clear \u5378\u8F7D\u5168\u90E8\u6280\u80FD",
677
+ " /customize \u63CF\u8FF0\u4F60\u60F3\u600E\u4E48\u8C03\u6559 nolo",
678
+ " /tasks \u5217\u51FA\u540E\u53F0\u5B50\u8FDB\u7A0B\u4EFB\u52A1\uFF08\u522B\u540D\uFF1A/jobs, /procs\uFF09",
679
+ " /stop <pid|all> \u505C\u6B62\u6307\u5B9A\u7684\u540E\u53F0\u4EFB\u52A1",
680
+ " /login \u67E5\u770B\u767B\u5F55 / \u914D\u7F6E\u63D0\u793A",
681
+ " /profile \u67E5\u770B\u5F53\u524D\u914D\u7F6E\u73AF\u5883",
682
+ " /update \u66F4\u65B0 nolo CLI",
683
+ " /version \u67E5\u770B\u7248\u672C\u4E0E\u66F4\u65B0\u63D0\u793A",
684
+ " /exit \u9000\u51FA\u5DE5\u4F5C\u533A",
685
+ "",
686
+ "\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"
687
+ ].join("\n")
688
+ },
689
+ // --- Slash-command output ---------------------------------------------
690
+ // Command results that used to be hardcoded English. Usage lines keep the
691
+ // command literal untouched; only the surrounding words are translated.
692
+ unknownCommand: {
693
+ en: "Unknown command: {0}\n\n",
694
+ zh: "\u672A\u77E5\u547D\u4EE4\uFF1A{0}\n\n"
695
+ },
696
+ runtimeUsage: { en: "Usage: /runtime <auto|local|server>", zh: "\u7528\u6CD5\uFF1A/runtime <auto|local|server>" },
697
+ runtimeSet: { en: "Runtime: {0}", zh: "\u8FD0\u884C\u6A21\u5F0F\uFF1A{0}" },
698
+ toolsCurrent: {
699
+ en: "Tool display: {0} (hide | compact | verbose)",
700
+ zh: "\u5DE5\u5177\u663E\u793A\uFF1A{0}\uFF08hide | compact | verbose\uFF09"
701
+ },
702
+ toolsUsage: { en: "Usage: /tools <hide|compact|verbose>", zh: "\u7528\u6CD5\uFF1A/tools <hide|compact|verbose>" },
703
+ toolsSet: { en: "Tool display: {0}", zh: "\u5DE5\u5177\u663E\u793A\uFF1A{0}" },
704
+ thinkingCurrent: {
705
+ en: "Thinking display: {0} (hide | marker | show)",
706
+ zh: "\u601D\u8003\u663E\u793A\uFF1A{0}\uFF08hide | marker | show\uFF09"
707
+ },
708
+ thinkingUsage: { en: "Usage: /thinking <hide|marker|show>", zh: "\u7528\u6CD5\uFF1A/thinking <hide|marker|show>" },
709
+ thinkingSet: { en: "Thinking display: {0}", zh: "\u601D\u8003\u663E\u793A\uFF1A{0}" },
710
+ tasksRunning: { en: "Running processes ({0}):", zh: "\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\uFF08{0}\uFF09\uFF1A" },
711
+ tasksStopped: { en: "Stopped/exited ({0}):", zh: "\u5DF2\u505C\u6B62/\u5DF2\u9000\u51FA\uFF08{0}\uFF09\uFF1A" },
712
+ tasksNone: { en: "No processes.", zh: "\u6CA1\u6709\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\u3002" },
713
+ stopUsage: { en: "Usage: /stop <pid|label|all>", zh: "\u7528\u6CD5\uFF1A/stop <pid|label|all>" },
714
+ stopAllDone: { en: "Stopped {0} processes", zh: "\u5DF2\u505C\u6B62 {0} \u4E2A\u8FDB\u7A0B" },
715
+ stopNoPid: { en: "No running process with pid {0}", zh: "\u6CA1\u6709 pid \u4E3A {0} \u7684\u8FD0\u884C\u4E2D\u8FDB\u7A0B" },
716
+ stopPidDone: { en: "Stopped pid {0} ({1})", zh: "\u5DF2\u505C\u6B62 pid {0}\uFF08{1}\uFF09" },
717
+ stopNoLabel: { en: "No running process labeled '{0}'", zh: "\u6CA1\u6709\u540D\u4E3A\u201C{0}\u201D\u7684\u8FD0\u884C\u4E2D\u8FDB\u7A0B" },
718
+ stopLabelsDone: { en: "Stopped {0}", zh: "\u5DF2\u505C\u6B62 {0}" },
719
+ compactNothing: {
720
+ en: "Current dialog: new (nothing to compact yet)",
721
+ zh: "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u662F\u65B0\u7684\uFF08\u8FD8\u6CA1\u6709\u53EF\u538B\u7F29\u7684\u5185\u5BB9\uFF09"
722
+ },
723
+ compactDone: {
724
+ en: "Compacted dialog {0} \u2192 {1}.",
725
+ zh: "\u5DF2\u538B\u7F29\u5BF9\u8BDD {0} \u2192 {1}\u3002"
726
+ },
727
+ compactDoneNoSummary: {
728
+ en: "Forked dialog {0} \u2192 {1} (no summary needed).",
729
+ zh: "\u5DF2\u5206\u53C9\u5BF9\u8BDD {0} \u2192 {1}\uFF08\u65E0\u9700\u538B\u7F29\uFF09\u3002"
730
+ },
731
+ agentCurrent: { en: "Current agent: {0} ({1})", zh: "\u5F53\u524D agent\uFF1A{0}\uFF08{1}\uFF09" },
732
+ agentUnknown: {
733
+ en: `I don't know agent "{0}" yet.
734
+ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`,
735
+ 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"
736
+ },
737
+ themeCurrent: { en: "Current theme: {0} \xB7 {1}", zh: "\u5F53\u524D\u4E3B\u9898\uFF1A{0} \xB7 {1}" },
738
+ themeUsage: {
739
+ en: "Usage: /theme <name> | /theme light | /theme dark",
740
+ zh: "\u7528\u6CD5\uFF1A/theme <name> | /theme light | /theme dark"
741
+ },
742
+ themeAvailable: { en: "Available themes: {0}", zh: "\u53EF\u7528\u4E3B\u9898\uFF1A{0}" },
743
+ themeBrightnessSwitched: { en: "Switched to {0} background colors.", zh: "\u5DF2\u5207\u6362\u5230 {0} \u80CC\u666F\u8272\u3002" },
744
+ themeBrightnessAuto: {
745
+ en: "Background colors follow terminal detection (now: {0}).",
746
+ zh: "\u80CC\u666F\u8272\u8DDF\u968F\u7EC8\u7AEF\u81EA\u52A8\u68C0\u6D4B\uFF08\u5F53\u524D\uFF1A{0}\uFF09\u3002"
747
+ },
748
+ themeSwitched: { en: "Switched to theme: {0}", zh: "\u5DF2\u5207\u6362\u5230\u4E3B\u9898\uFF1A{0}" },
749
+ themeUnknown: { en: "Unknown theme: {0}. Available themes: {1}", zh: "\u672A\u77E5\u4E3B\u9898\uFF1A{0}\u3002\u53EF\u7528\u4E3B\u9898\uFF1A{1}" },
750
+ densityCurrent: {
751
+ en: "Current density: {0}\nUsage: /density <cozy|spacious>",
752
+ zh: "\u5F53\u524D\u5BC6\u5EA6\uFF1A{0}\n\u7528\u6CD5\uFF1A/density <cozy|spacious>"
753
+ },
754
+ densitySwitched: { en: "Switched to layout density: {0}", zh: "\u5DF2\u5207\u6362\u5230\u5E03\u5C40\u5BC6\u5EA6\uFF1A{0}" },
755
+ densityUnknown: {
756
+ en: "Unknown density: {0}. Use 'cozy' or 'spacious'.",
757
+ zh: "\u672A\u77E5\u5BC6\u5EA6\uFF1A{0}\u3002\u8BF7\u4F7F\u7528 cozy \u6216 spacious\u3002"
758
+ },
759
+ docAttachUsage: { en: "Usage: /doc attach <doc>", zh: "\u7528\u6CD5\uFF1A/doc attach <doc>" },
760
+ docList: { en: "Attached docs: {0}", zh: "\u5DF2\u6302\u8F7D\u6587\u6863\uFF1A{0}" },
761
+ 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" },
762
+ skillAttachUsage: { en: "Usage: /skill attach <skill-ref>", zh: "\u7528\u6CD5\uFF1A/skill attach <skill-ref>" },
763
+ skillAttached: { en: "Attached skill: {0}", zh: "\u5DF2\u6302\u8F7D\u6280\u80FD\uFF1A{0}" },
764
+ skillDetachUsage: { en: "Usage: /skill detach <skill-ref>", zh: "\u7528\u6CD5\uFF1A/skill detach <skill-ref>" },
765
+ skillDetached: { en: "Detached skill: {0}", zh: "\u5DF2\u5378\u8F7D\u6280\u80FD\uFF1A{0}" },
766
+ skillNotAttached: { en: "Skill not attached: {0}", zh: "\u6280\u80FD\u672A\u6302\u8F7D\uFF1A{0}" },
767
+ skillNone: { en: "No skills attached.", zh: "\u8FD8\u6CA1\u6709\u6302\u8F7D\u6280\u80FD\u3002" },
768
+ skillCleared: { en: "Cleared {0} skill(s).", zh: "\u5DF2\u6E05\u7A7A {0} \u4E2A\u6280\u80FD\u3002" },
769
+ skillList: {
770
+ en: "Attached skills: {0}\nUsage: /skill attach <ref> | /skill detach <ref> | /skill clear",
771
+ zh: "\u5DF2\u6302\u8F7D\u6280\u80FD\uFF1A{0}\n\u7528\u6CD5\uFF1A/skill attach <ref> | /skill detach <ref> | /skill clear"
772
+ },
773
+ skillNoneHint: {
774
+ 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.",
775
+ 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"
776
+ },
777
+ customizeHint: {
778
+ en: "Tell nolo what to change, for example: /customize make my default agent more concise.",
779
+ zh: "\u544A\u8BC9 nolo \u4F60\u60F3\u6539\u4EC0\u4E48\uFF0C\u4F8B\u5982\uFF1A/customize make my default agent more concise\u3002"
780
+ },
781
+ loginHint: {
782
+ en: "MVP login uses profile/env auth. Set AUTH_TOKEN, NOLO_SERVER, or NOLO_PROFILE before starting nolo.",
783
+ 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"
784
+ },
785
+ versionInfo: {
786
+ en: "nolo {0}\nUpdate this install with: nolo update\nIf repo-local output differs, publish/install the latest npm package first.",
787
+ 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"
788
+ },
789
+ versionUnknown: { en: "unknown version", zh: "\u672A\u77E5\u7248\u672C" },
790
+ // --- Dialog list / timestamps -----------------------------------------
791
+ recentDialogs: { en: "Recent dialogs:", zh: "\u6700\u8FD1\u5BF9\u8BDD\uFF1A" },
792
+ dialogListTip: {
793
+ en: "Tip: run /history to pick one interactively, or paste an id after /resume.",
794
+ zh: "\u63D0\u793A\uFF1A\u7528 /history \u4EA4\u4E92\u5F0F\u9009\u62E9\uFF0C\u6216\u628A id \u7C98\u5230 /resume \u540E\u9762\u3002"
795
+ },
796
+ timeJustNow: { en: "just now", zh: "\u521A\u521A" },
797
+ timeMinutesAgo: { en: "{0}m ago", zh: "{0} \u5206\u949F\u524D" },
798
+ timeHoursAgo: { en: "{0}h ago", zh: "{0} \u5C0F\u65F6\u524D" },
799
+ timeDaysAgo: { en: "{0}d ago", zh: "{0} \u5929\u524D" },
800
+ // Overflow hints shared by select / multi-select / ask-choice. The arrows
801
+ // and count are part of the copy so each locale can order them naturally.
802
+ dialogMoreAbove: { en: "\u2191 {0} more", zh: "\u2191 {0} \u66F4\u591A" },
803
+ dialogMoreBelow: { en: "\u2193 {0} more", zh: "\u2193 {0} \u66F4\u591A" },
804
+ // Action gate handoff
805
+ actionGateNeeded: {
806
+ en: "Action needed in your terminal",
807
+ zh: "\u7EC8\u7AEF\u9700\u8981\u4F60\u7684\u64CD\u4F5C"
808
+ },
809
+ actionGateEnterHint: {
810
+ en: "Press Enter to run it now. Follow any prompts below, or Ctrl+C to cancel.",
811
+ zh: "\u6309 Enter \u7ACB\u5373\u6267\u884C\uFF0C\u6309\u4E0B\u65B9\u63D0\u793A\u64CD\u4F5C\uFF0C\u6216\u6309 Ctrl+C \u53D6\u6D88\u3002"
812
+ },
813
+ actionGateInteractiveTitle: {
814
+ en: "This command requires an interactive terminal.",
815
+ zh: "\u8BE5\u547D\u4EE4\u9700\u8981\u4EA4\u4E92\u5F0F\u7EC8\u7AEF"
816
+ },
817
+ actionGateInteractiveBody: {
818
+ en: "Complete it in the terminal, then nolo will continue.",
819
+ zh: "\u5728\u7EC8\u7AEF\u4E2D\u5B8C\u6210\u64CD\u4F5C\u540E\uFF0Cnolo \u5C06\u7EE7\u7EED\u3002"
820
+ },
821
+ // Agent catalog sources
822
+ agentSourcePlatform: {
823
+ en: "Platform",
824
+ zh: "\u5E73\u53F0"
825
+ },
826
+ agentSourceSubscription: {
827
+ en: "Subscription",
828
+ zh: "\u8BA2\u9605"
829
+ },
830
+ agentSourceApi: {
831
+ en: "API",
832
+ zh: "API"
833
+ }
834
+ };
835
+ function t(key, ...params) {
836
+ const text = STRINGS[key][currentLocale];
837
+ if (params.length === 0) return text;
838
+ return text.replace(/\{(\d+)\}/g, (match, index) => {
839
+ const replacement = params[Number(index)];
840
+ return replacement === void 0 ? match : replacement;
841
+ });
842
+ }
843
+ var TOOL_LABELS = {
844
+ // Local workspace tools (packages/agent-runtime/localWorkspaceTools.ts)
845
+ readFile: { en: "Read", zh: "\u8BFB\u53D6" },
846
+ writeFile: { en: "Write", zh: "\u5199\u5165" },
847
+ editFile: { en: "Edit", zh: "\u7F16\u8F91" },
848
+ listFiles: { en: "List", zh: "\u5217\u51FA" },
849
+ searchFiles: { en: "Search", zh: "\u641C\u7D22" },
850
+ globFiles: { en: "Glob", zh: "\u5339\u914D" },
851
+ execShell: { en: "Run", zh: "\u6267\u884C" },
852
+ runCommand: { en: "Run", zh: "\u6267\u884C" },
853
+ captureVisualState: { en: "Capture", zh: "\u622A\u5C4F" },
854
+ // Workspace / diagnostics
855
+ searchWorkspace: { en: "Search workspace", zh: "\u641C\u7D22\u5DE5\u4F5C\u533A" },
856
+ cliDoctor: { en: "Doctor", zh: "\u81EA\u68C0" },
857
+ cliWhoami: { en: "Whoami", zh: "\u67E5\u770B\u8EAB\u4EFD" },
858
+ checkEnv: { en: "Check env", zh: "\u68C0\u67E5\u73AF\u5883" },
859
+ configure: { en: "Configure", zh: "\u914D\u7F6E" },
860
+ notifyUser: { en: "Notify", zh: "\u901A\u77E5" },
861
+ // Docs / dialogs / spaces
862
+ readDoc: { en: "Read doc", zh: "\u8BFB\u53D6\u6587\u6863" },
863
+ createDoc: { en: "Create doc", zh: "\u65B0\u5EFA\u6587\u6863" },
864
+ updateDoc: { en: "Update doc", zh: "\u66F4\u65B0\u6587\u6863" },
865
+ readDialog: { en: "Read dialog", zh: "\u8BFB\u53D6\u5BF9\u8BDD" },
866
+ listDialogs: { en: "List dialogs", zh: "\u5217\u51FA\u5BF9\u8BDD" },
867
+ queryDialogsBySubjectRef: { en: "Query dialogs", zh: "\u67E5\u8BE2\u5BF9\u8BDD" },
868
+ searchDialogMessages: { en: "Search messages", zh: "\u641C\u7D22\u6D88\u606F" },
869
+ listSpaces: { en: "List spaces", zh: "\u5217\u51FA\u7A7A\u95F4" },
870
+ readSpace: { en: "Read space", zh: "\u8BFB\u53D6\u7A7A\u95F4" },
871
+ // Tables
872
+ createTable: { en: "Create table", zh: "\u521B\u5EFA\u8868" },
873
+ queryTableRows: { en: "Query rows", zh: "\u67E5\u8BE2\u8868\u884C" },
874
+ addTableRow: { en: "Add row", zh: "\u65B0\u589E\u8868\u884C" },
875
+ addTableRows: { en: "Add rows", zh: "\u65B0\u589E\u8868\u884C" },
876
+ updateTableRow: { en: "Update row", zh: "\u66F4\u65B0\u8868\u884C" },
877
+ deleteTableRow: { en: "Delete row", zh: "\u5220\u9664\u8868\u884C" },
878
+ // Web
879
+ // Tree group header uses the same short category noun as Read/Search/Run
880
+ // ("Fetch" / "抓取网页"), not a longer "Fetch page" phrase.
881
+ fetchWebpage: { en: "Fetch", zh: "\u6293\u53D6\u7F51\u9875" },
882
+ readPage: { en: "Read page", zh: "\u8BFB\u53D6\u7F51\u9875" },
883
+ exaSearch: { en: "Web search", zh: "\u8054\u7F51\u641C\u7D22" },
884
+ // Skill loading
885
+ loadSkill: { en: "Used Skill", zh: "\u4F7F\u7528\u6280\u80FD" }
886
+ };
887
+ function toolLabel(name) {
888
+ return TOOL_LABELS[name]?.[currentLocale] ?? name;
889
+ }
890
+ function agentRunCardLabels() {
891
+ return {
892
+ runStatus: t("runStatusLabel"),
893
+ runStarted: t("runStartedLabel"),
894
+ runStopped: t("runStoppedLabel"),
895
+ logTail: t("runLogTailLabel"),
896
+ runs: (count) => t("runsListLabel", String(count))
897
+ };
898
+ }
899
+
172
900
  // packages/cli/client/localRuntimeAdapter.ts
173
901
  import { dirname, extname, join } from "node:path";
174
902
  import { fileURLToPath } from "node:url";
@@ -216,19 +944,19 @@ async function defaultSleep(ms) {
216
944
  function transientFetchRetryDelayMs(attempt) {
217
945
  return Math.min(attempt * TRANSIENT_FETCH_RETRY_BASE_DELAY_MS, 2e3);
218
946
  }
947
+ var MAX_RETRY_DELAY_MS = 1e4;
219
948
  async function resolveRetryAfterMs(response, attempt) {
220
- const header = response.headers.get("retry-after");
221
- if (header) {
222
- const seconds = Number(header.trim());
223
- if (Number.isFinite(seconds) && seconds >= 0) {
224
- return Math.min(seconds * 1e3, 1e4);
225
- }
949
+ const headerMs = parseRetryAfterHeaderMs(
950
+ response.headers.get("retry-after")
951
+ );
952
+ if (headerMs !== null) {
953
+ return Math.min(headerMs, MAX_RETRY_DELAY_MS);
226
954
  }
227
955
  try {
228
956
  const body = await response.clone().text();
229
957
  const parsed = JSON.parse(body);
230
- const ms = Number(parsed?.retryAfterMs);
231
- if (Number.isFinite(ms) && ms >= 0) return Math.min(ms, 1e4);
958
+ const ms = normalizeNonNegativeMs(parsed?.retryAfterMs, 0);
959
+ if (ms > 0) return Math.min(ms, MAX_RETRY_DELAY_MS);
232
960
  } catch {
233
961
  }
234
962
  return transientFetchRetryDelayMs(attempt);
@@ -297,7 +1025,7 @@ async function isCoreDrainingResponse(response) {
297
1025
  if (response.status !== 503) return false;
298
1026
  try {
299
1027
  const body = await response.clone().json();
300
- return body?.reason === CORE_DRAIN_REASON;
1028
+ return isCoreDrainingBody(body);
301
1029
  } catch {
302
1030
  return false;
303
1031
  }
@@ -324,6 +1052,9 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
324
1052
  await (options.sleep ?? defaultSleep)(delayMs);
325
1053
  continue;
326
1054
  }
1055
+ if (coreDraining) {
1056
+ return createDrainExhaustedResponse(response);
1057
+ }
327
1058
  }
328
1059
  return response;
329
1060
  } catch (error) {
@@ -743,14 +1474,14 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
743
1474
  [PUBLIC_KIMI_K26_IMAGE_AGENT_KEY]: {
744
1475
  key: PUBLIC_KIMI_K26_IMAGE_AGENT_KEY,
745
1476
  name: "Kimi K2.6",
746
- provider: "ollama-cloud",
1477
+ provider: "nolo",
747
1478
  model: "kimi-k2.6",
748
1479
  apiSource: "platform",
749
1480
  useServerProxy: true,
750
1481
  rawRecord: {
751
1482
  dbKey: PUBLIC_KIMI_K26_IMAGE_AGENT_KEY,
752
1483
  isPublic: true,
753
- provider: "ollama-cloud",
1484
+ provider: "nolo",
754
1485
  model: "kimi-k2.6",
755
1486
  apiSource: "platform",
756
1487
  useServerProxy: true
@@ -759,14 +1490,14 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
759
1490
  [PUBLIC_KIMI_K27_CODING_AGENT_KEY]: {
760
1491
  key: PUBLIC_KIMI_K27_CODING_AGENT_KEY,
761
1492
  name: "Kimi K2.7 Coding",
762
- provider: "ollama-cloud",
1493
+ provider: "nolo",
763
1494
  model: "kimi-k2.7-code",
764
1495
  apiSource: "platform",
765
1496
  useServerProxy: true,
766
1497
  rawRecord: {
767
1498
  dbKey: PUBLIC_KIMI_K27_CODING_AGENT_KEY,
768
1499
  isPublic: true,
769
- provider: "ollama-cloud",
1500
+ provider: "nolo",
770
1501
  model: "kimi-k2.7-code",
771
1502
  apiSource: "platform",
772
1503
  useServerProxy: true
@@ -1071,12 +1802,110 @@ var LOCAL_SERVER_WEB_TOOL_NAMES = ["fetchWebpage", "exa_search"];
1071
1802
  var LOCAL_SERVER_WEB_TOOL_NAME_SET = new Set(
1072
1803
  LOCAL_SERVER_WEB_TOOL_NAMES
1073
1804
  );
1074
- var REGISTRY_INJECTED_TOOL_NAMES = /* @__PURE__ */ new Set([
1075
- "callAgent",
1076
- "ui_ask_choice",
1077
- "read_x_post",
1078
- "read_xhs_profile"
1079
- ]);
1805
+
1806
+ // packages/core/fetchWebpageShaping.ts
1807
+ var FETCH_WEBPAGE_PREVIEW_LENGTH = 1200;
1808
+ var FETCH_WEBPAGE_MAX_CONTENT_LENGTH = 12 * 1024;
1809
+ var FETCH_WEBPAGE_REQUEST_HEADERS = {
1810
+ Accept: "text/markdown, text/html, application/xhtml+xml, */*",
1811
+ "User-Agent": "NoloBot/1.0 (AI Agent; +https://nolo.ai)"
1812
+ };
1813
+ function cleanHtmlForAI(html) {
1814
+ return compactWhitespace(
1815
+ html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, "").replace(/<[^>]*>/g, " ")
1816
+ );
1817
+ }
1818
+ function shapeFetchWebpageContent(args) {
1819
+ const cleanedContent = args.contentType.includes("text/markdown") ? args.content.trim() : cleanHtmlForAI(args.content);
1820
+ const preview = cleanedContent.length > FETCH_WEBPAGE_PREVIEW_LENGTH ? cleanedContent.substring(0, FETCH_WEBPAGE_PREVIEW_LENGTH) + "...\uFF08\u9884\u89C8\u5185\u5BB9\u5DF2\u622A\u65AD\uFF09" : cleanedContent;
1821
+ const fullContent = cleanedContent.length > FETCH_WEBPAGE_MAX_CONTENT_LENGTH ? cleanedContent.substring(0, FETCH_WEBPAGE_MAX_CONTENT_LENGTH) + "...\uFF08\u5B8C\u6574\u5185\u5BB9\u5DF2\u622A\u65AD\uFF09" : cleanedContent;
1822
+ return {
1823
+ preview,
1824
+ fullContent,
1825
+ contentType: args.contentType,
1826
+ markdownTokens: args.markdownTokens ?? null
1827
+ };
1828
+ }
1829
+
1830
+ // packages/core/internalHostname.ts
1831
+ function unwrapIpv6Brackets(hostname) {
1832
+ return hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
1833
+ }
1834
+ var INTERNAL_IPV4_OR_NAME_RE = /^(localhost|127\.|10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|0\.|169\.254\.)/;
1835
+ var INTERNAL_IPV6_EXACT = /* @__PURE__ */ new Set(["::1", "::", "0:0:0:0:0:0:0:1", "0:0:0:0:0:0:0:0"]);
1836
+ var INTERNAL_IPV6_PREFIX_RE = /^(f[cd][0-9a-f]{0,2}:|fe[89ab][0-9a-f]:)/;
1837
+ function isIpv4MappedInternal(host) {
1838
+ const mapped = host.match(/^::ffff:(.+)$/);
1839
+ if (!mapped?.[1]) return false;
1840
+ const rest = mapped[1];
1841
+ if (INTERNAL_IPV4_OR_NAME_RE.test(rest)) return true;
1842
+ const hex = rest.match(/^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
1843
+ if (!hex) return false;
1844
+ const high = Number.parseInt(hex[1] ?? "", 16);
1845
+ if (!Number.isFinite(high)) return false;
1846
+ const firstOctet = high >> 8 & 255;
1847
+ const secondOctet = high & 255;
1848
+ if (firstOctet === 127 || firstOctet === 10 || firstOctet === 0) return true;
1849
+ if (firstOctet === 192 && secondOctet === 168) return true;
1850
+ if (firstOctet === 169 && secondOctet === 254) return true;
1851
+ if (firstOctet === 172 && secondOctet >= 16 && secondOctet <= 31) return true;
1852
+ return false;
1853
+ }
1854
+ function isNumericInternalIpv4(host) {
1855
+ if (!/^\d+$/.test(host)) return false;
1856
+ const value = Number(host);
1857
+ if (!Number.isInteger(value) || value < 0 || value > 4294967295) return false;
1858
+ const firstOctet = value >>> 24 & 255;
1859
+ const secondOctet = value >>> 16 & 255;
1860
+ if (firstOctet === 127 || firstOctet === 10 || firstOctet === 0) return true;
1861
+ if (firstOctet === 192 && secondOctet === 168) return true;
1862
+ if (firstOctet === 169 && secondOctet === 254) return true;
1863
+ if (firstOctet === 172 && secondOctet >= 16 && secondOctet <= 31) return true;
1864
+ return false;
1865
+ }
1866
+ function isInternalHostname(hostname) {
1867
+ const host = unwrapIpv6Brackets(hostname.trim().toLowerCase()).replace(/\.$/, "");
1868
+ if (!host) return true;
1869
+ if (INTERNAL_IPV4_OR_NAME_RE.test(host)) return true;
1870
+ if (INTERNAL_IPV6_EXACT.has(host)) return true;
1871
+ if (INTERNAL_IPV6_PREFIX_RE.test(host)) return true;
1872
+ if (isIpv4MappedInternal(host)) return true;
1873
+ if (isNumericInternalIpv4(host)) return true;
1874
+ return false;
1875
+ }
1876
+
1877
+ // packages/cli/client/fetchWebpageContent.ts
1878
+ function classifyFetchWebpageUrl(rawUrl) {
1879
+ if (!rawUrl || typeof rawUrl !== "string") {
1880
+ return { kind: "reject", error: "URL \u53C2\u6570\u662F\u5FC5\u9700\u7684" };
1881
+ }
1882
+ let parsed;
1883
+ try {
1884
+ parsed = new URL(rawUrl);
1885
+ } catch {
1886
+ return { kind: "reject", error: "\u65E0\u6548\u7684 URL \u683C\u5F0F" };
1887
+ }
1888
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
1889
+ return { kind: "reject", error: "\u4EC5\u652F\u6301 HTTP/HTTPS \u534F\u8BAE" };
1890
+ }
1891
+ if (isInternalHostname(parsed.hostname)) {
1892
+ return { kind: "local", url: rawUrl, parsed };
1893
+ }
1894
+ return { kind: "remote", url: rawUrl, parsed };
1895
+ }
1896
+ async function fetchWebpageLocally(args) {
1897
+ const response = await args.fetchImpl(args.url, {
1898
+ headers: { ...FETCH_WEBPAGE_REQUEST_HEADERS }
1899
+ });
1900
+ const contentType = response.headers.get("content-type") || "";
1901
+ const content = await response.text();
1902
+ const shaped = shapeFetchWebpageContent({
1903
+ content,
1904
+ contentType,
1905
+ markdownTokens: response.headers.get("x-markdown-tokens")
1906
+ });
1907
+ return JSON.stringify(shaped);
1908
+ }
1080
1909
 
1081
1910
  // packages/cli/client/cliServerPlatformToolExecutors.ts
1082
1911
  function buildServerPlatformToolExecutors(args) {
@@ -1146,8 +1975,39 @@ function buildServerPlatformToolExecutors(args) {
1146
1975
  toolName,
1147
1976
  async (call) => {
1148
1977
  const parsed = parseNoloWorkspaceToolArguments(call.arguments);
1149
- const path = toolName === "fetchWebpage" ? "/api/fetch-webpage" : "/api/exa-search";
1150
- const body = toolName === "fetchWebpage" ? { url: parsed.url } : {
1978
+ if (toolName === "fetchWebpage") {
1979
+ const route = classifyFetchWebpageUrl(parsed.url);
1980
+ if (route.kind === "reject") {
1981
+ throw new Error(route.error);
1982
+ }
1983
+ if (route.kind === "local") {
1984
+ const content3 = await fetchWebpageLocally({
1985
+ url: route.url,
1986
+ fetchImpl: args.fetchImpl
1987
+ });
1988
+ return {
1989
+ content: content3,
1990
+ metadata: {
1991
+ serverPlatformTool: true,
1992
+ webTool: toolName,
1993
+ url: parsed.url,
1994
+ localFetch: true
1995
+ }
1996
+ };
1997
+ }
1998
+ const content2 = await postServer("/api/fetch-webpage", {
1999
+ url: route.url
2000
+ });
2001
+ return {
2002
+ content: content2,
2003
+ metadata: {
2004
+ serverPlatformTool: true,
2005
+ webTool: toolName,
2006
+ url: parsed.url
2007
+ }
2008
+ };
2009
+ }
2010
+ const body = {
1151
2011
  query: parsed.query,
1152
2012
  numResults: parsed.numResults ?? 5,
1153
2013
  useAutoprompt: parsed.useAutoprompt ?? true,
@@ -1157,13 +2017,12 @@ function buildServerPlatformToolExecutors(args) {
1157
2017
  // conversion so CLI proxy results match web behavior.
1158
2018
  contents: parsed.includeContent !== false ? { text: true } : void 0
1159
2019
  };
1160
- const content = await postServer(path, body);
2020
+ const content = await postServer("/api/exa-search", body);
1161
2021
  return {
1162
2022
  content,
1163
2023
  metadata: {
1164
2024
  serverPlatformTool: true,
1165
- webTool: toolName,
1166
- ...toolName === "fetchWebpage" || toolName === "fetch_webpage" ? { url: parsed.url } : {}
2025
+ webTool: toolName
1167
2026
  }
1168
2027
  };
1169
2028
  }
@@ -1207,22 +2066,30 @@ function createCliStartAgentRunExecutor(deps = {}) {
1207
2066
  --- \u9644\u52A0\u8F93\u5165 ---
1208
2067
  ${JSON.stringify(args.input)}`;
1209
2068
  const rawArgs = ["--agent", agentKey, "--msg-file", "PLACEHOLDER", "--bg"];
1210
- const { runId, pid } = await spawnLocalBackgroundRun(
2069
+ const agentName = typeof args.agentName === "string" && args.agentName.trim() ? args.agentName.trim() : typeof args.name === "string" && args.name.trim() ? args.name.trim() : void 0;
2070
+ const { runId } = await spawnLocalBackgroundRun(
1211
2071
  {
1212
2072
  rawArgs,
1213
2073
  commandPath: ["agent", "run"],
1214
2074
  cliEntrypointPath: deps.cliEntrypoint,
1215
2075
  agentKey,
2076
+ ...agentName ? { agentName } : {},
1216
2077
  cwd: deps.cwd ?? process.cwd(),
1217
2078
  message,
1218
2079
  output: noopOutput
1219
2080
  },
1220
2081
  deps
1221
2082
  );
2083
+ const displayName = agentName ?? "agent";
2084
+ const labels = agentRunCardLabels();
1222
2085
  return {
1223
- content: JSON.stringify({ runId, status: "running" }),
2086
+ content: JSON.stringify({
2087
+ runId,
2088
+ status: "running",
2089
+ ...agentName ? { agentName } : {}
2090
+ }),
1224
2091
  metadata: {
1225
- displayData: `\u23F3 \u540E\u53F0 run \u5DF2\u542F\u52A8\uFF0CrunId: ${runId}\uFF08pid ${pid ?? "-"}\uFF09\u3002\u7528 controlAgentRun(action:"status", runId:"${runId}") \u67E5\u8FDB\u5EA6\u3002`
2092
+ displayData: formatStartRunCard(displayName, "running", labels)
1226
2093
  }
1227
2094
  };
1228
2095
  };
@@ -1233,18 +2100,23 @@ function createCliControlAgentRunExecutor(deps = {}) {
1233
2100
  const action = typeof args.action === "string" ? args.action : "";
1234
2101
  const tailLines = typeof args.tailLines === "number" ? args.tailLines : 0;
1235
2102
  if (action === "list") {
1236
- const runs = listRunRecords(deps).map((record2) => ({
1237
- runId: record2.runId,
1238
- status: record2.status,
1239
- agentKey: record2.agentKey,
1240
- pid: record2.pid ?? null,
1241
- startedAt: record2.startedAt
1242
- }));
2103
+ const records = listRunRecords(deps);
2104
+ const runs = records.map((record2) => {
2105
+ const reconciled = checkStaleRun(record2.runId, deps) ?? record2;
2106
+ return {
2107
+ runId: reconciled.runId,
2108
+ status: reconciled.status,
2109
+ agentKey: reconciled.agentKey,
2110
+ ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
2111
+ pid: reconciled.pid ?? null,
2112
+ startedAt: reconciled.startedAt
2113
+ };
2114
+ });
2115
+ const labels2 = agentRunCardLabels();
1243
2116
  return {
1244
2117
  content: JSON.stringify({ runs, count: runs.length }),
1245
2118
  metadata: {
1246
- displayData: runs.length > 0 ? `\u{1F4CB} \u627E\u5230 ${runs.length} \u4E2A run\uFF1A
1247
- ${runs.map((r) => `${r.runId} [${r.status}] ${r.agentKey}`).join("\n")}` : "\u{1F4CB} \u6CA1\u6709\u627E\u5230 run\u3002"
2119
+ displayData: formatListRunsCard(runs, labels2)
1248
2120
  }
1249
2121
  };
1250
2122
  }
@@ -1254,14 +2126,18 @@ ${runs.map((r) => `${r.runId} [${r.status}] ${r.agentKey}`).join("\n")}` : "\u{1
1254
2126
  if (!args.runId) throw new Error(`controlAgentRun(action:"${action}"): \u7F3A\u5C11 runId\u3002`);
1255
2127
  const record = findRunRecord(String(args.runId), deps);
1256
2128
  if (!record) {
2129
+ const labels2 = agentRunCardLabels();
1257
2130
  return {
1258
2131
  content: JSON.stringify({ runId: args.runId, found: false }),
1259
- metadata: { displayData: `\u2753 run ${args.runId} \u672A\u627E\u5230\u3002\u53EF\u80FD\u5DF2\u5B8C\u6210\u5E76\u88AB\u6E05\u7406\uFF0C\u6216 ID \u9519\u8BEF\u3002` }
2132
+ metadata: { displayData: formatNotFoundRunCard(labels2) }
1260
2133
  };
1261
2134
  }
1262
2135
  if (action === "status") {
1263
2136
  const reconciled = checkStaleRun(record.runId, deps) ?? record;
1264
2137
  const logTail = tailLines > 0 ? tailFile(record.logPath, tailLines, resolveFs(deps)) : void 0;
2138
+ const name = reconciled.agentName || "agent";
2139
+ const logLines = logTail ? logTail.split("\n") : void 0;
2140
+ const labels2 = agentRunCardLabels();
1265
2141
  return {
1266
2142
  content: JSON.stringify({
1267
2143
  runId: reconciled.runId,
@@ -1269,15 +2145,15 @@ ${runs.map((r) => `${r.runId} [${r.status}] ${r.agentKey}`).join("\n")}` : "\u{1
1269
2145
  status: reconciled.status,
1270
2146
  pid: reconciled.pid ?? null,
1271
2147
  agentKey: reconciled.agentKey,
2148
+ ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
1272
2149
  startedAt: reconciled.startedAt,
1273
2150
  endedAt: reconciled.endedAt ?? null,
1274
2151
  exitCode: reconciled.exitCode ?? null,
1275
- ...logTail !== void 0 ? { logTail } : {}
2152
+ ...logTail !== void 0 ? { logTail } : {},
2153
+ ...logLines ? { logLines } : {}
1276
2154
  }),
1277
2155
  metadata: {
1278
- displayData: `\u{1F4CC} run ${reconciled.runId} status=${reconciled.status}` + (logTail ? `
1279
- --- \u65E5\u5FD7\uFF08\u672B ${tailLines} \u884C\uFF09---
1280
- ${logTail}` : "")
2156
+ displayData: formatStatusRunCard(name, reconciled.status, { logLines, labels: labels2 })
1281
2157
  }
1282
2158
  };
1283
2159
  }
@@ -1291,14 +2167,65 @@ ${logTail}` : "")
1291
2167
  }
1292
2168
  }
1293
2169
  finalizeRunRecord(record.runId, { status: "killed" }, deps);
2170
+ const labels = agentRunCardLabels();
1294
2171
  return {
1295
2172
  content: JSON.stringify({ runId: record.runId, found: true, status: "killed" }),
1296
- metadata: { displayData: `\u{1F6D1} run ${record.runId} \u5DF2\u505C\u6B62\uFF08killed\uFF09\u3002` }
2173
+ metadata: { displayData: formatStopRunCard("killed", labels) }
1297
2174
  };
1298
2175
  };
1299
2176
  }
1300
2177
 
1301
2178
  // packages/cli/client/cliLocalToolExecutors.ts
2179
+ var MAX_PASTED_TEXT_LINES_PER_READ = 200;
2180
+ function createReadPastedTextExecutor(store) {
2181
+ return async (call) => {
2182
+ let parsed = {};
2183
+ try {
2184
+ const value = JSON.parse(call.arguments || "{}");
2185
+ if (value && typeof value === "object") parsed = value;
2186
+ } catch {
2187
+ return {
2188
+ content: "readPastedText requires a JSON object with pasteId.",
2189
+ metadata: { error: true, code: "invalid_arguments" }
2190
+ };
2191
+ }
2192
+ const pasteId = Number(parsed.pasteId);
2193
+ if (!Number.isInteger(pasteId) || pasteId < 1) {
2194
+ return {
2195
+ content: "readPastedText requires a positive integer pasteId.",
2196
+ metadata: { error: true, code: "invalid_paste_id" }
2197
+ };
2198
+ }
2199
+ const text = store.items.get(pasteId);
2200
+ if (text === void 0) {
2201
+ return {
2202
+ content: `pasted text #${pasteId} is no longer available in this TUI turn.`,
2203
+ metadata: { error: true, code: "paste_not_found", pasteId }
2204
+ };
2205
+ }
2206
+ const lines = text.split("\n");
2207
+ const requestedStart = Number(parsed.startLine);
2208
+ const requestedEnd = Number(parsed.endLine);
2209
+ const startLine = Number.isInteger(requestedStart) && requestedStart > 0 ? Math.min(requestedStart, lines.length) : 1;
2210
+ const endLine = Math.min(
2211
+ lines.length,
2212
+ Number.isInteger(requestedEnd) && requestedEnd >= startLine ? requestedEnd : startLine + MAX_PASTED_TEXT_LINES_PER_READ - 1,
2213
+ startLine + MAX_PASTED_TEXT_LINES_PER_READ - 1
2214
+ );
2215
+ return {
2216
+ content: lines.slice(startLine - 1, endLine).join("\n"),
2217
+ metadata: {
2218
+ pasteId,
2219
+ startLine,
2220
+ endLine,
2221
+ totalLines: lines.length,
2222
+ totalChars: text.length,
2223
+ truncated: endLine < lines.length,
2224
+ source: "tui-paste-store"
2225
+ }
2226
+ };
2227
+ };
2228
+ }
1302
2229
  function buildCliWorkspaceToolExecutors(args) {
1303
2230
  return buildNoloWorkspaceCliToolExecutors({
1304
2231
  cliEntrypoint: args.cliEntrypoint ?? process.argv[1] ?? "",
@@ -1462,6 +2389,7 @@ function buildLocalToolExecutors(args) {
1462
2389
  controlAgentRun: createCliControlAgentRunExecutor({
1463
2390
  env: args.env
1464
2391
  }),
2392
+ ...args.pastedTextStore ? { readPastedText: createReadPastedTextExecutor(args.pastedTextStore) } : {},
1465
2393
  ...args.localToolExecutors ?? {}
1466
2394
  };
1467
2395
  }
@@ -4066,11 +4994,11 @@ function unescapeBytesDefaultValue(str) {
4066
4994
  case "6":
4067
4995
  case "7": {
4068
4996
  const s = input.c;
4069
- const t = input.take(2);
4070
- if (t === false) {
4997
+ const t2 = input.take(2);
4998
+ if (t2 === false) {
4071
4999
  return false;
4072
5000
  }
4073
- const n = parseInt(s + t, 8);
5001
+ const n = parseInt(s + t2, 8);
4074
5002
  if (Number.isNaN(n)) {
4075
5003
  return false;
4076
5004
  }
@@ -4079,11 +5007,11 @@ function unescapeBytesDefaultValue(str) {
4079
5007
  }
4080
5008
  case "x": {
4081
5009
  const s = input.c;
4082
- const t = input.take(2);
4083
- if (t === false) {
5010
+ const t2 = input.take(2);
5011
+ if (t2 === false) {
4084
5012
  return false;
4085
5013
  }
4086
- const n = parseInt(s + t, 16);
5014
+ const n = parseInt(s + t2, 16);
4087
5015
  if (Number.isNaN(n)) {
4088
5016
  return false;
4089
5017
  }
@@ -4092,11 +5020,11 @@ function unescapeBytesDefaultValue(str) {
4092
5020
  }
4093
5021
  case "u": {
4094
5022
  const s = input.c;
4095
- const t = input.take(4);
4096
- if (t === false) {
5023
+ const t2 = input.take(4);
5024
+ if (t2 === false) {
4097
5025
  return false;
4098
5026
  }
4099
- const n = parseInt(s + t, 16);
5027
+ const n = parseInt(s + t2, 16);
4100
5028
  if (Number.isNaN(n)) {
4101
5029
  return false;
4102
5030
  }
@@ -4108,11 +5036,11 @@ function unescapeBytesDefaultValue(str) {
4108
5036
  }
4109
5037
  case "U": {
4110
5038
  const s = input.c;
4111
- const t = input.take(8);
4112
- if (t === false) {
5039
+ const t2 = input.take(8);
5040
+ if (t2 === false) {
4113
5041
  return false;
4114
5042
  }
4115
- const tc = protoInt64.uEnc(s + t);
5043
+ const tc = protoInt64.uEnc(s + t2);
4116
5044
  const chunk = new Uint8Array(8);
4117
5045
  const view = new DataView(chunk.buffer);
4118
5046
  view.setInt32(0, tc.lo, true);
@@ -4251,24 +5179,24 @@ function createBaseRegistry() {
4251
5179
  return files.get(fileName);
4252
5180
  },
4253
5181
  getMessage(typeName) {
4254
- const t = types.get(typeName);
4255
- return (t === null || t === void 0 ? void 0 : t.kind) == "message" ? t : void 0;
5182
+ const t2 = types.get(typeName);
5183
+ return (t2 === null || t2 === void 0 ? void 0 : t2.kind) == "message" ? t2 : void 0;
4256
5184
  },
4257
5185
  getEnum(typeName) {
4258
- const t = types.get(typeName);
4259
- return (t === null || t === void 0 ? void 0 : t.kind) == "enum" ? t : void 0;
5186
+ const t2 = types.get(typeName);
5187
+ return (t2 === null || t2 === void 0 ? void 0 : t2.kind) == "enum" ? t2 : void 0;
4260
5188
  },
4261
5189
  getExtension(typeName) {
4262
- const t = types.get(typeName);
4263
- return (t === null || t === void 0 ? void 0 : t.kind) == "extension" ? t : void 0;
5190
+ const t2 = types.get(typeName);
5191
+ return (t2 === null || t2 === void 0 ? void 0 : t2.kind) == "extension" ? t2 : void 0;
4264
5192
  },
4265
5193
  getExtensionFor(extendee, no) {
4266
5194
  var _a;
4267
5195
  return (_a = extendees.get(extendee.typeName)) === null || _a === void 0 ? void 0 : _a.get(no);
4268
5196
  },
4269
5197
  getService(typeName) {
4270
- const t = types.get(typeName);
4271
- return (t === null || t === void 0 ? void 0 : t.kind) == "service" ? t : void 0;
5198
+ const t2 = types.get(typeName);
5199
+ return (t2 === null || t2 === void 0 ? void 0 : t2.kind) == "service" ? t2 : void 0;
4272
5200
  }
4273
5201
  };
4274
5202
  }
@@ -8235,9 +9163,41 @@ function buildOpenAiTools(args) {
8235
9163
  const toolNameSet = new Set(args.toolNames ?? []);
8236
9164
  const callAgentTools = toolNameSet.has("callAgent") ? prepareTools(["callAgent"]) : [];
8237
9165
  const uiAskChoiceTools = toolNameSet.has("ui_ask_choice") ? prepareTools(["ui_ask_choice"]) : [];
9166
+ const readPastedTextTools = toolNameSet.has("readPastedText") ? [
9167
+ {
9168
+ type: "function",
9169
+ function: {
9170
+ name: "readPastedText",
9171
+ description: "Read a chunk of a large TUI paste by pasteId. Use startLine and endLine to page through the full content.",
9172
+ parameters: {
9173
+ type: "object",
9174
+ properties: {
9175
+ pasteId: {
9176
+ type: "integer",
9177
+ minimum: 1,
9178
+ description: "The paste id from the user message reference."
9179
+ },
9180
+ startLine: {
9181
+ type: "integer",
9182
+ minimum: 1,
9183
+ description: "First 1-based line to return; defaults to 1."
9184
+ },
9185
+ endLine: {
9186
+ type: "integer",
9187
+ minimum: 1,
9188
+ description: "Last 1-based line to return; each call is bounded to a 200-line chunk."
9189
+ }
9190
+ },
9191
+ required: ["pasteId"],
9192
+ additionalProperties: false
9193
+ }
9194
+ }
9195
+ }
9196
+ ] : [];
8238
9197
  return [
8239
9198
  ...callAgentTools,
8240
9199
  ...uiAskChoiceTools,
9200
+ ...readPastedTextTools,
8241
9201
  ...buildLocalWorkspaceOpenAiTools({
8242
9202
  toolNames: toolset.toolNames,
8243
9203
  exposeShellTools: toolset.exposeShellTools,
@@ -8279,6 +9239,22 @@ function resolveCliEffectiveEnabledPacks(args) {
8279
9239
  const withOrchestration = base.includes("agent-orchestration") ? base : [...base, "agent-orchestration"];
8280
9240
  return withOrchestration.includes("skills") ? withOrchestration : [...withOrchestration, "skills"];
8281
9241
  }
9242
+ function withRuntimeEnabledPacksAndPrompt(config) {
9243
+ const rawRecord = config.rawRecord ?? {};
9244
+ const enabledPacks = config.enabledPacks ?? rawRecord.enabledPacks;
9245
+ const prompt = appendEnabledPackPromptPatches(
9246
+ config.prompt,
9247
+ enabledPacks
9248
+ );
9249
+ if (prompt === config.prompt && !enabledPacks?.length) {
9250
+ return config;
9251
+ }
9252
+ return {
9253
+ ...config,
9254
+ ...enabledPacks?.length ? { enabledPacks } : {},
9255
+ ...prompt ? { prompt } : {}
9256
+ };
9257
+ }
8282
9258
  function resolveCliRequestedToolNames(agentConfig, env) {
8283
9259
  const declaredOnly = shouldUseDeclaredOnlyLocalWorkspaceTools(env);
8284
9260
  return applyDisabledTools(
@@ -8304,8 +9280,13 @@ function resolveCliRequestedToolNames(agentConfig, env) {
8304
9280
  agentConfig?.disabledTools
8305
9281
  );
8306
9282
  }
8307
- function resolveProviderOpenAiToolBundle(agentConfig, env, buildTools = buildOpenAiTools) {
8308
- const requestedToolNames = resolveCliRequestedToolNames(agentConfig, env);
9283
+ function resolveProviderOpenAiToolBundle(agentConfig, env, buildTools = buildOpenAiTools, additionalToolNames = []) {
9284
+ const requestedToolNames = [
9285
+ .../* @__PURE__ */ new Set([
9286
+ ...resolveCliRequestedToolNames(agentConfig, env),
9287
+ ...additionalToolNames
9288
+ ])
9289
+ ];
8309
9290
  const tools = buildTools({
8310
9291
  agentKey: agentConfig.key,
8311
9292
  toolNames: requestedToolNames,
@@ -8324,25 +9305,17 @@ function buildLocalWorkspaceToolsetForEnv(args) {
8324
9305
  return toolset;
8325
9306
  }
8326
9307
  function buildLocalPolicyToolNames(args) {
9308
+ const buildTools = args.buildTools ?? buildOpenAiTools;
8327
9309
  return [
8328
- ...buildLocalWorkspacePolicyToolNames({
8329
- declaredToolNames: args.toolNames,
8330
- exposeShellTools: true,
8331
- useDeclaredToolNamesOnly: shouldUseDeclaredOnlyLocalWorkspaceTools(
8332
- args.env
9310
+ ...new Set(
9311
+ summarizeOpenAiToolNames(
9312
+ buildTools({
9313
+ agentKey: args.agentKey,
9314
+ toolNames: args.toolNames,
9315
+ env: args.env
9316
+ })
8333
9317
  )
8334
- }),
8335
- ...(() => {
8336
- const extra = [];
8337
- const names = args.toolNames ?? [];
8338
- for (const name of names) {
8339
- if (REGISTRY_INJECTED_TOOL_NAMES.has(name)) extra.push(name);
8340
- if (LOCAL_SERVER_TABLE_TOOL_NAME_SET.has(name)) extra.push(name);
8341
- if (LOCAL_SERVER_WEB_TOOL_NAME_SET.has(name)) extra.push(name);
8342
- }
8343
- return extra;
8344
- })(),
8345
- ...filterNoloWorkspaceToolNames(args.toolNames)
9318
+ )
8346
9319
  ];
8347
9320
  }
8348
9321
  function buildServerPlatformOpenAiTools(args) {
@@ -8592,6 +9565,33 @@ function createLocalDialogTitleGenerator(deps, ctx) {
8592
9565
  return result.source === "llm" ? result.title : null;
8593
9566
  };
8594
9567
  }
9568
+ async function writeLocalTokenRecord(args) {
9569
+ const rawUsage = args.input.result.usage;
9570
+ if (!rawUsage || typeof rawUsage !== "object" || Object.keys(rawUsage).length === 0) {
9571
+ return;
9572
+ }
9573
+ const timestamp = args.now();
9574
+ const prepared = prepareTokenUsageData({
9575
+ rawUsage,
9576
+ agentConfig: {
9577
+ model: args.input.result.model || "unknown",
9578
+ provider: args.input.result.provider,
9579
+ apiSource: "cli"
9580
+ },
9581
+ userId: args.userId,
9582
+ agentId: args.input.agentKey,
9583
+ dialogId: args.dialogId,
9584
+ timestamp,
9585
+ entry_path: "cli-local"
9586
+ });
9587
+ const recordKey = createTokenKey.record(args.userId, timestamp);
9588
+ const tokenRecord = {
9589
+ id: args.createId(),
9590
+ type: "token",
9591
+ ...prepared.tokenData
9592
+ };
9593
+ await args.store.write(recordKey, tokenRecord);
9594
+ }
8595
9595
  async function writeDialog(args) {
8596
9596
  let existingDialog = null;
8597
9597
  if (args.input.continueDialogId) {
@@ -8625,6 +9625,22 @@ async function writeDialog(args) {
8625
9625
  ...titleOverride ? { titleOverride } : {}
8626
9626
  });
8627
9627
  await args.store.batch(plan.ops);
9628
+ try {
9629
+ await writeLocalTokenRecord({
9630
+ store: args.store,
9631
+ input: args.input,
9632
+ userId: args.userId,
9633
+ dialogId: plan.dialogId,
9634
+ now: args.now,
9635
+ createId: args.createId,
9636
+ output: args.output
9637
+ });
9638
+ } catch (error) {
9639
+ args.output?.write(
9640
+ `[nolo] Token usage record write failed (non-fatal): ${toErrorMessage(error)}
9641
+ `
9642
+ );
9643
+ }
8628
9644
  const hasSubjectRefs = localTurnHasSubjectRefs(args.input);
8629
9645
  const isLocalUser = args.userId === "local";
8630
9646
  if (!isLocalUser) {
@@ -8658,6 +9674,42 @@ async function writeDialog(args) {
8658
9674
  }
8659
9675
  return { dialogId: plan.dialogId };
8660
9676
  }
9677
+ function resolveCliDialogRecordKey(userId, dialogId) {
9678
+ if (dialogId.startsWith("dialog-") && !dialogId.includes("-msg-")) {
9679
+ return dialogId;
9680
+ }
9681
+ return `dialog-${userId}-${dialogId}`;
9682
+ }
9683
+ async function loadCliDialogSummary(args) {
9684
+ const dialogKey = resolveCliDialogRecordKey(args.userId, args.dialogId);
9685
+ const record = await args.store.read(dialogKey);
9686
+ if (!record || typeof record !== "object") return null;
9687
+ const summary = typeof record.summary === "string" ? record.summary.trim() : "";
9688
+ if (!summary) return null;
9689
+ const summarizedBeforeId = record.summarizedBeforeId;
9690
+ return {
9691
+ summary,
9692
+ ...typeof summarizedBeforeId === "string" && summarizedBeforeId ? { summarizedBeforeId } : {}
9693
+ };
9694
+ }
9695
+ async function saveCliDialogSummary(args) {
9696
+ const dialogKey = resolveCliDialogRecordKey(args.userId, args.dialogId);
9697
+ const existing = await args.store.read(dialogKey) ?? {};
9698
+ const bareId = typeof existing.id === "string" && existing.id ? existing.id : args.dialogId.startsWith("dialog-") ? args.dialogId.slice(args.dialogId.lastIndexOf("-") + 1) : args.dialogId;
9699
+ const compressionCount = typeof existing.compressionCount === "number" ? existing.compressionCount + 1 : 1;
9700
+ await args.store.write(dialogKey, {
9701
+ ...existing,
9702
+ id: bareId,
9703
+ dbKey: dialogKey,
9704
+ type: "dialog",
9705
+ userId: args.userId,
9706
+ summary: args.summary,
9707
+ ...args.summarizedBeforeId !== void 0 ? { summarizedBeforeId: args.summarizedBeforeId } : {},
9708
+ compressionCount,
9709
+ summaryPending: false,
9710
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
9711
+ });
9712
+ }
8661
9713
  function createCliLocalRuntimeAdapter(deps) {
8662
9714
  const now = deps.now ?? Date.now;
8663
9715
  const createId = deps.createId ?? createFallbackId;
@@ -8667,6 +9719,7 @@ function createCliLocalRuntimeAdapter(deps) {
8667
9719
  const localToolBudgets = parseLocalToolBudgets(deps.env);
8668
9720
  const localToolUsage = /* @__PURE__ */ new Map();
8669
9721
  const buildProviderOpenAiTools = deps.buildProviderOpenAiTools ?? buildOpenAiTools;
9722
+ const additionalToolNames = deps.pastedTextStore ? ["readPastedText"] : [];
8670
9723
  let activeAgentToolNames = [];
8671
9724
  const workspaceRoot = deps.cwd ?? process.cwd();
8672
9725
  let runtimeToolExecutionLimits = {};
@@ -8680,6 +9733,7 @@ function createCliLocalRuntimeAdapter(deps) {
8680
9733
  cliEntrypoint: CLI_ENTRYPOINT,
8681
9734
  ...deps.confirmDestructiveAction ? { confirmDestructiveAction: deps.confirmDestructiveAction } : {},
8682
9735
  ...deps.requestUserChoice ? { requestUserChoice: deps.requestUserChoice } : {},
9736
+ ...deps.pastedTextStore ? { pastedTextStore: deps.pastedTextStore } : {},
8683
9737
  ...runtimeToolExecutionLimits
8684
9738
  });
8685
9739
  return {
@@ -8696,7 +9750,7 @@ function createCliLocalRuntimeAdapter(deps) {
8696
9750
  agentRef,
8697
9751
  cwd: normalizeRuntimeCacheCwd(workspaceRoot)
8698
9752
  });
8699
- const cached = preparedAgentRuntimeCache.get(cacheKey);
9753
+ const cached = deps.pastedTextStore ? void 0 : preparedAgentRuntimeCache.get(cacheKey);
8700
9754
  if (cached) {
8701
9755
  activeAgentToolNames = cached.activeAgentToolNames;
8702
9756
  runtimeToolExecutionLimits = cached.runtimeToolExecutionLimits;
@@ -8709,13 +9763,15 @@ function createCliLocalRuntimeAdapter(deps) {
8709
9763
  userId
8710
9764
  });
8711
9765
  const fallbackLocalCliAgentConfig = storedAgentConfig ? null : resolveBuiltinLocalCliAgentConfig(agentRef, userId);
8712
- const agentConfig = withResolvedRuntimeToolSurface(
9766
+ const baseAgentConfig = withResolvedRuntimeToolSurface(
8713
9767
  storedAgentConfig ?? fallbackLocalCliAgentConfig,
8714
9768
  deps.env
8715
9769
  );
9770
+ const agentConfig = baseAgentConfig ? withRuntimeEnabledPacksAndPrompt(baseAgentConfig) : baseAgentConfig;
8716
9771
  const requestedToolNames = agentConfig ? resolveCliRequestedToolNames(agentConfig, deps.env) : [];
8717
9772
  activeAgentToolNames = buildLocalPolicyToolNames({
8718
- toolNames: requestedToolNames,
9773
+ agentKey: agentConfig?.key,
9774
+ toolNames: [...requestedToolNames, ...additionalToolNames],
8719
9775
  env: deps.env
8720
9776
  });
8721
9777
  runtimeToolExecutionLimits = resolveLocalWorkspaceExecutorOptionsFromPolicy(
@@ -8731,9 +9787,10 @@ function createCliLocalRuntimeAdapter(deps) {
8731
9787
  cliEntrypoint: CLI_ENTRYPOINT,
8732
9788
  ...deps.confirmDestructiveAction ? { confirmDestructiveAction: deps.confirmDestructiveAction } : {},
8733
9789
  ...deps.requestUserChoice ? { requestUserChoice: deps.requestUserChoice } : {},
9790
+ ...deps.pastedTextStore ? { pastedTextStore: deps.pastedTextStore } : {},
8734
9791
  ...runtimeToolExecutionLimits
8735
9792
  });
8736
- if (agentConfig) {
9793
+ if (agentConfig && !deps.pastedTextStore) {
8737
9794
  preparedAgentRuntimeCache.set(cacheKey, {
8738
9795
  agentConfig,
8739
9796
  activeAgentToolNames,
@@ -8747,6 +9804,18 @@ function createCliLocalRuntimeAdapter(deps) {
8747
9804
  dialogId,
8748
9805
  store: await getOrCreateSharedStore(deps)
8749
9806
  }),
9807
+ loadDialogSummary: async (dialogId) => loadCliDialogSummary({
9808
+ store: await getOrCreateSharedStore(deps),
9809
+ userId,
9810
+ dialogId
9811
+ }),
9812
+ saveDialogSummary: async (input) => saveCliDialogSummary({
9813
+ store: await getOrCreateSharedStore(deps),
9814
+ userId,
9815
+ dialogId: input.dialogId,
9816
+ summary: input.summary,
9817
+ summarizedBeforeId: input.summarizedBeforeId
9818
+ }),
8750
9819
  saveTurn: async (input) => writeDialog({
8751
9820
  store: await getOrCreateSharedStore(deps),
8752
9821
  input,
@@ -8826,7 +9895,8 @@ function createCliLocalRuntimeAdapter(deps) {
8826
9895
  const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
8827
9896
  agentConfig,
8828
9897
  deps.env,
8829
- buildProviderOpenAiTools
9898
+ buildProviderOpenAiTools,
9899
+ additionalToolNames
8830
9900
  );
8831
9901
  logLocalRuntimeDiagnostic("provider.selected", {
8832
9902
  agentKey: agentConfig.key,
@@ -8906,7 +9976,8 @@ function createCliLocalRuntimeAdapter(deps) {
8906
9976
  const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
8907
9977
  agentConfig,
8908
9978
  deps.env,
8909
- buildProviderOpenAiTools
9979
+ buildProviderOpenAiTools,
9980
+ additionalToolNames
8910
9981
  );
8911
9982
  logLocalRuntimeDiagnostic("provider.selected", {
8912
9983
  agentKey: agentConfig.key,
@@ -8971,7 +10042,8 @@ function createCliLocalRuntimeAdapter(deps) {
8971
10042
  const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
8972
10043
  agentConfig,
8973
10044
  deps.env,
8974
- buildProviderOpenAiTools
10045
+ buildProviderOpenAiTools,
10046
+ additionalToolNames
8975
10047
  );
8976
10048
  logLocalRuntimeDiagnostic("provider.selected", {
8977
10049
  agentKey: agentConfig.key,
@@ -9053,7 +10125,8 @@ function createCliLocalRuntimeAdapter(deps) {
9053
10125
  const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
9054
10126
  agentConfig,
9055
10127
  deps.env,
9056
- buildProviderOpenAiTools
10128
+ buildProviderOpenAiTools,
10129
+ additionalToolNames
9057
10130
  );
9058
10131
  return {
9059
10132
  model: providerConfig2.model,
@@ -9078,7 +10151,7 @@ function createCliLocalRuntimeAdapter(deps) {
9078
10151
  openAiToolNames: summarizeOpenAiToolNames(tools2),
9079
10152
  stream
9080
10153
  });
9081
- const res = await fetchWithTransientRetry(
10154
+ let res = await fetchWithTransientRetry(
9082
10155
  fetchImpl,
9083
10156
  request.url,
9084
10157
  {
@@ -9089,8 +10162,44 @@ function createCliLocalRuntimeAdapter(deps) {
9089
10162
  loopbackRequest
9090
10163
  }
9091
10164
  );
10165
+ let responseProviderConfig = providerConfig2;
10166
+ let firstErrorRaw;
9092
10167
  if (!res.ok) {
9093
- const raw2 = await res.text().catch(() => "");
10168
+ firstErrorRaw = await res.text().catch(() => "");
10169
+ const fallbackProviderConfig = resolveLegacyDeepSeekProxyChatFallback({
10170
+ providerConfig: providerConfig2,
10171
+ status: res.status,
10172
+ raw: firstErrorRaw
10173
+ });
10174
+ if (fallbackProviderConfig) {
10175
+ responseProviderConfig = fallbackProviderConfig;
10176
+ const fallbackRequest = buildPlatformChatCompletionRequest({
10177
+ providerConfig: fallbackProviderConfig,
10178
+ messages,
10179
+ tools: tools2,
10180
+ stream: false
10181
+ });
10182
+ logLocalRuntimeDiagnostic("provider.request.compatibility-fallback", {
10183
+ agentKey: agentConfig.key,
10184
+ provider: providerConfig2.provider,
10185
+ fromEndpoint: summarizeEndpoint(providerConfig2.endpoint) ?? null,
10186
+ toEndpoint: summarizeEndpoint(fallbackProviderConfig.endpoint) ?? null,
10187
+ reason: "legacy-proxy-responses-schema"
10188
+ });
10189
+ res = await fetchWithTransientRetry(
10190
+ fetchImpl,
10191
+ fallbackRequest.url,
10192
+ { ...fallbackRequest.init },
10193
+ {
10194
+ sleep: deps.sleep,
10195
+ loopbackRequest
10196
+ }
10197
+ );
10198
+ firstErrorRaw = void 0;
10199
+ }
10200
+ }
10201
+ if (!res.ok) {
10202
+ const raw2 = firstErrorRaw ?? await res.text().catch(() => "");
9094
10203
  const data2 = parsePlatformChatCompletionData(raw2);
9095
10204
  const rawPreview = raw2.length > 200 ? `${raw2.slice(0, 200)}\u2026(${raw2.length}b)` : raw2;
9096
10205
  const gatewayHeaders = [
@@ -9141,7 +10250,7 @@ function createCliLocalRuntimeAdapter(deps) {
9141
10250
  });
9142
10251
  const data = parsePlatformChatCompletionData(raw);
9143
10252
  return parsePlatformChatCompletionResponse({
9144
- providerConfig: providerConfig2,
10253
+ providerConfig: responseProviderConfig,
9145
10254
  data,
9146
10255
  trace: messages
9147
10256
  });
@@ -9172,12 +10281,39 @@ function createCliLocalRuntimeAdapter(deps) {
9172
10281
  const { requestedToolNames, tools } = resolveProviderOpenAiToolBundle(
9173
10282
  agentConfig,
9174
10283
  deps.env,
9175
- buildProviderOpenAiTools
10284
+ buildProviderOpenAiTools,
10285
+ additionalToolNames
9176
10286
  );
9177
10287
  return {
9178
10288
  model: providerConfig.model,
9179
10289
  complete: async (messages, options) => {
9180
10290
  const stream = Boolean(options?.onTextDelta);
10291
+ const inlinedMessages = (await inlineImageUrlsForCustomProvider(
10292
+ { messages },
10293
+ {
10294
+ shouldInline: true,
10295
+ isAllowedImageUrl: (url) => {
10296
+ try {
10297
+ return new URL(url).origin === new URL(serverUrl).origin;
10298
+ } catch {
10299
+ return false;
10300
+ }
10301
+ },
10302
+ fetchImage: async (url) => {
10303
+ const response = await fetchImpl(url, {
10304
+ headers: authToken ? { Authorization: `Bearer ${authToken}` } : void 0
10305
+ });
10306
+ if (!response.ok) {
10307
+ return { ok: false, error: `HTTP ${response.status}` };
10308
+ }
10309
+ return {
10310
+ ok: true,
10311
+ mimeType: response.headers.get("content-type") ?? "application/octet-stream",
10312
+ bytes: new Uint8Array(await response.arrayBuffer())
10313
+ };
10314
+ }
10315
+ }
10316
+ )).messages;
9181
10317
  logLocalRuntimeDiagnostic("provider.request.start", {
9182
10318
  agentKey: agentConfig.key,
9183
10319
  transport: "direct-openai-compatible",
@@ -9191,7 +10327,7 @@ function createCliLocalRuntimeAdapter(deps) {
9191
10327
  });
9192
10328
  const result = await executeOpenAiCompatibleChatCompletion({
9193
10329
  providerConfig,
9194
- messages,
10330
+ messages: inlinedMessages,
9195
10331
  tools,
9196
10332
  fetchImpl: (url, init) => fetchWithTransientRetry(fetchImpl, url, init, {
9197
10333
  sleep: deps.sleep,
@@ -9243,6 +10379,13 @@ function createCliLocalRuntimeAdapter(deps) {
9243
10379
  export {
9244
10380
  summarizeEndpoint,
9245
10381
  isBuiltinNoloAgentRef,
10382
+ parseCliLocale,
10383
+ getCliLocale,
10384
+ setCliLocale,
10385
+ initCliLocale,
10386
+ t,
10387
+ toolLabel,
10388
+ agentRunCardLabels,
9246
10389
  clearCliLocalRuntimePreparedAgentCache,
9247
10390
  createCliCallAgentToolExecutor,
9248
10391
  createCliLocalRuntimeAdapter