nolo-cli 0.10.0 → 0.12.0-alpha.1

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 (125) hide show
  1. package/{_executeModel-YAXYAUOK.js → _executeModel-MWAY74HA.js} +47 -44
  2. package/{action-TLI3V62L.js → action-RAXNQQKC.js} +9 -10
  3. package/{addContentAction-PLWJSCOZ.js → addContentAction-ZHI7TVV3.js} +8 -10
  4. package/{addDialogAgentAction-BJ6SB76X.js → addDialogAgentAction-JWXPKXNC.js} +7 -8
  5. package/{agentDeleteCommand-2VYX73U5.js → agentDeleteCommand-LXR5A5FV.js} +36 -26
  6. package/{agentEmailCommands-3GDZIX64.js → agentEmailCommands-DXRAP7BB.js} +63 -58
  7. package/{agentListCommands-UWVBT3LH.js → agentListCommands-ZFMS5ZLY.js} +132 -35
  8. package/{agentMachineCommands-WOKMUG2Y.js → agentMachineCommands-ZJLYVV52.js} +40 -29
  9. package/{agentPullCommand-O2MTUAFR.js → agentPullCommand-KRBRIFIY.js} +6 -6
  10. package/{agentRecordCommands-MVNZRH3U.js → agentRecordCommands-DFS626TB.js} +55 -50
  11. package/{agentRunCommand-K7THIJLA.js → agentRunCommand-GWBIE2TS.js} +60 -56
  12. package/{agentRunControl-K4VKNEHF.js → agentRunControl-IX4F5W2C.js} +3 -3
  13. package/{agentRuntimeLocal-WJIGU24U.js → agentRuntimeLocal-YNZSHMZC.js} +29 -14
  14. package/{agentSlice-LL5TKZEO.js → agentSlice-T2PXOEPQ.js} +9 -10
  15. package/{authCommand-TC2SW2CQ.js → authCommand-DMW336GT.js} +13 -13
  16. package/{authCommands-XPEHTKSM.js → authCommands-GH5T6RYV.js} +6 -6
  17. package/{chunk-5JGGZCZL.js → chunk-3HHTVM6G.js} +64 -5
  18. package/chunk-3QKO4EHV.js +112 -0
  19. package/{chunk-AUQ747NZ.js → chunk-43UD5ZP7.js} +76 -15
  20. package/{chunk-6SLCD4RB.js → chunk-4BTHUYMY.js} +596 -67
  21. package/{chunk-T7R3NGUU.js → chunk-4EH7AR52.js} +13 -13
  22. package/{chunk-C3RUNRHT.js → chunk-4GBNEA5B.js} +1 -1
  23. package/{chunk-4IJYA27C.js → chunk-4LG74DRG.js} +1 -1
  24. package/{chunk-2FTTDCD4.js → chunk-4ON5AV72.js} +2 -1
  25. package/{chunk-IWX4UW2E.js → chunk-524BDL33.js} +89 -8
  26. package/{chunk-EXXFGKF7.js → chunk-5ITRDSHY.js} +1400 -119
  27. package/{chunk-ISNCLGUZ.js → chunk-5NBHQD4D.js} +4 -3
  28. package/{chunk-7KNKFIRO.js → chunk-6LMFFG3K.js} +3 -3
  29. package/{chunk-PAKN26FP.js → chunk-6OVCRC72.js} +1 -1
  30. package/{chunk-CKOJQDKR.js → chunk-7JJCGV7N.js} +146 -3
  31. package/{chunk-KBKYAONQ.js → chunk-7MYHLZ3F.js} +2 -2
  32. package/{chunk-PIVFPOW6.js → chunk-AM53Q2SD.js} +175 -2541
  33. package/chunk-BYXBJQAS.js +0 -0
  34. package/{chunk-CL3IOKGK.js → chunk-DE5BA4O6.js} +20 -2
  35. package/{chunk-6KUOUWMP.js → chunk-DRMGJFGQ.js} +300 -89
  36. package/{chunk-QAALPJS7.js → chunk-EBH7G34M.js} +20 -7
  37. package/{chunk-HJGEVL7C.js → chunk-G3B356GF.js} +15 -17
  38. package/{chunk-OZMMKDBI.js → chunk-GDBCUWQ3.js} +26 -20
  39. package/{chunk-I5URP43I.js → chunk-GPZM7QH6.js} +9 -9
  40. package/chunk-IKXL2HZ3.js +70 -0
  41. package/{chunk-AS4PVWA4.js → chunk-IVAOVLM7.js} +1 -1
  42. package/{chunk-TNPIMII7.js → chunk-JUN3HFMN.js} +221 -81
  43. package/{chunk-HFASY3WO.js → chunk-JZDIW766.js} +1 -1
  44. package/{chunk-6JJWFVZ6.js → chunk-LHSJMY5V.js} +17 -17
  45. package/chunk-LTRXGFMS.js +83 -0
  46. package/{chunk-YIHFXH5Q.js → chunk-MEVCDATU.js} +3 -3
  47. package/{chunk-TILFE6LV.js → chunk-NCGFB7NN.js} +5 -3
  48. package/{chunk-BE2OOJ5P.js → chunk-NITP2JDG.js} +42 -11
  49. package/{chunk-YPRZSPF3.js → chunk-OCDEWRE2.js} +1 -1
  50. package/{chunk-VVX233PH.js → chunk-OHEKYYJF.js} +9 -9
  51. package/chunk-OOIN7HSO.js +146 -0
  52. package/{chunk-WPE4F4Z6.js → chunk-OPKKB25T.js} +1 -1
  53. package/{chunk-OR2XR25C.js → chunk-QCA3EPYK.js} +8 -8
  54. package/{chunk-SL35K7AH.js → chunk-QLUFR47U.js} +13 -83
  55. package/{chunk-CDTLMEB3.js → chunk-RNQ5BLR2.js} +1 -1
  56. package/{chunk-AVMKZHBC.js → chunk-RSEUHW6T.js} +3 -2
  57. package/{chunk-TYSCFY6S.js → chunk-RZ735TLX.js} +762 -167
  58. package/chunk-S3UTETIC.js +4885 -0
  59. package/chunk-S73OEOHH.js +2286 -0
  60. package/{chunk-JRKKFRAV.js → chunk-TSKWE74T.js} +58 -8
  61. package/{chunk-A67QFHAA.js → chunk-UG3WOFU6.js} +1 -1
  62. package/{chunk-4ZDM73SD.js → chunk-V2J635L5.js} +1 -1
  63. package/chunk-VC6OZXO5.js +298 -0
  64. package/{chunk-7U44LYTR.js → chunk-WPHL6ALY.js} +1 -1
  65. package/{chunk-4SIMLBEU.js → chunk-WTYKCU4W.js} +9 -9
  66. package/{chunk-NPVBXJY2.js → chunk-WWU275LU.js} +9 -9
  67. package/{chunk-ZQ2UM4KG.js → chunk-WZSRQNQG.js} +1 -292
  68. package/{chunk-DSZUWUYB.js → chunk-XHQWJUW4.js} +2 -2
  69. package/{chunk-GAKEBQD6.js → chunk-YDCZVUFP.js} +4 -0
  70. package/{chunk-2O4IZNTG.js → chunk-YTQLJYLB.js} +2 -2
  71. package/{chunk-3Y3HW5PX.js → chunk-ZPFRLGIZ.js} +1512 -935
  72. package/{chunk-5KLGBAAR.js → chunk-ZR4VHQ5D.js} +14 -13
  73. package/cliEnvHelpers-VYC2OPTB.js +30 -0
  74. package/{cliExecutor-DNE7TCC4.js → cliExecutor-K3F7DMRO.js} +2 -2
  75. package/{createAgentAutomationAction-CCE7CWGQ.js → createAgentAutomationAction-G32GKDGV.js} +22 -23
  76. package/{createDialogAction-QTRR4AT7.js → createDialogAction-TISANRZK.js} +25 -25
  77. package/{createPageAction-Y4KQOAJE.js → createPageAction-O7KOYNV4.js} +27 -27
  78. package/{dbSlice-WWNV2SGX.js → dbSlice-WDP2ZZHK.js} +7 -8
  79. package/{deleteFile-OW53A6BX.js → deleteFile-M7UNIUOO.js} +5 -5
  80. package/{dialogCommands-SMKIAC3Y.js → dialogCommands-6JPB3YQY.js} +33 -23
  81. package/{dialogSlice-PT7YBWNE.js → dialogSlice-PRHHYSP5.js} +21 -22
  82. package/{docCreateCommands-RFNA4HNM.js → docCreateCommands-75E6TZNN.js} +36 -25
  83. package/{docDeleteCommands-4YZ325M6.js → docDeleteCommands-EJHLN7LW.js} +37 -27
  84. package/{docReadCommands-RT6VAFFG.js → docReadCommands-RJYBC4FS.js} +36 -25
  85. package/{docStore-QUQZAFZF.js → docStore-H5VWKT5D.js} +22 -23
  86. package/{docUpdateCommands-EKKKNYPW.js → docUpdateCommands-MG4CNISV.js} +36 -25
  87. package/fetchMessages-KTNM7QAR.js +1 -1
  88. package/{getPricing-3E6UNPKL.js → getPricing-6TOZXPAU.js} +7 -3
  89. package/{handleSendMessageAction-5NSYAS53.js → handleSendMessageAction-QTUGICSZ.js} +22 -23
  90. package/index.js +77 -76
  91. package/{machineCommands-DOOSIUKG.js → machineCommands-MAV7M3TK.js} +67 -60
  92. package/{machineWsRunDispatch-PIOIQRBW.js → machineWsRunDispatch-ZOEGTKHC.js} +54 -49
  93. package/{memoryCommands-O4MIPIWQ.js → memoryCommands-AFMES3LN.js} +5 -5
  94. package/{models-4OPOOLFS.js → models-LSCRJJ6P.js} +2 -2
  95. package/package.json +1 -1
  96. package/{read-GW7ZEI23.js → read-2MIMRBZ2.js} +5 -5
  97. package/{readDocTool-HUFU6OCT.js → readDocTool-QHVGQHUJ.js} +1 -1
  98. package/{readlineWorkspace-QEAOH5EP.js → readlineWorkspace-SWQKC7ZS.js} +1126 -678
  99. package/{removeDialogAgentAction-OHMCNSSD.js → removeDialogAgentAction-GTX5AN54.js} +11 -11
  100. package/{runAgentClientLoop-AIGLXC3R.js → runAgentClientLoop-P25HACXX.js} +42 -40
  101. package/{runtimeDoctorCommands-LRHLPDRC.js → runtimeDoctorCommands-QNF3J3UV.js} +6 -6
  102. package/{setDialogExtraReferencesAction-YJUM5BWQ.js → setDialogExtraReferencesAction-WFQ63KYO.js} +7 -8
  103. package/{setPrimaryDialogAgentAction-EBAREZDM.js → setPrimaryDialogAgentAction-P57FXTSU.js} +11 -11
  104. package/{settingSlice-UW4IUI5L.js → settingSlice-CK5YZGNI.js} +8 -9
  105. package/skillDiscovery-ZYHSX7VD.js +16 -0
  106. package/{spaceCommands-BKHSPR73.js → spaceCommands-6O5EFEM5.js} +41 -33
  107. package/{spaceSlice-TYNWE3OC.js → spaceSlice-4EXTYXS4.js} +25 -24
  108. package/{streamAgentChatTurn-HRMFFA7E.js → streamAgentChatTurn-Q3FJAHG2.js} +205 -107
  109. package/{tableCommands-O7O2LBEG.js → tableCommands-E4SQWDOX.js} +10 -10
  110. package/{tools-3JNDS3WH.js → tools-AHNQE4GP.js} +33 -31
  111. package/{tuiSummaryLlmCaller-RV3THLZF.js → tuiSummaryLlmCaller-TXLF4MEI.js} +8 -6
  112. package/{updateCommands-VOSPKXFF.js → updateCommands-XZDOOYFH.js} +13 -5
  113. package/{updateDialogTitleAction-OCETSKCP.js → updateDialogTitleAction-XZDVLKVX.js} +25 -25
  114. package/chunk-5MMAK75Q.js +0 -15
  115. package/chunk-AZPCASRE.js +0 -36
  116. package/chunk-BBYVOSU2.js +0 -792
  117. package/chunk-DCOA4QSN.js +0 -105
  118. package/chunk-UAD2WT54.js +0 -64
  119. package/{chunk-DZ3XJVET.js → chunk-3QAF2LTL.js} +3 -3
  120. package/{chunk-X7W4TNB4.js → chunk-CMKUBIGW.js} +3 -3
  121. package/{chunk-4CQLVGRV.js → chunk-ID4G2MAR.js} +3 -3
  122. package/{chunk-5CS33IBL.js → chunk-PDL2AV3E.js} +3 -3
  123. package/{chunk-EHLHSX7R.js → chunk-TOILAPLH.js} +3 -3
  124. package/{chunk-UTLZINAP.js → chunk-TSUJOM6N.js} +10 -10
  125. package/{offlineMarxistsAgentCommand-BCPJITJL.js → offlineMarxistsAgentCommand-5OOWZLJI.js} +3 -3
@@ -3,12 +3,16 @@ import {
3
3
  refreshAntigravityOAuthToken,
4
4
  refreshOpenAiCodexToken,
5
5
  refreshXaiOAuthToken
6
- } from "./chunk-EHLHSX7R.js";
6
+ } from "./chunk-TOILAPLH.js";
7
+ import {
8
+ CliProviderQuotaError,
9
+ executeCli
10
+ } from "./chunk-CMKUBIGW.js";
7
11
  import {
8
12
  buildLocalAgentLookupKeys,
9
13
  normalizeAgentHandle,
10
14
  shouldReadAgentKeyRemotely
11
- } from "./chunk-CDTLMEB3.js";
15
+ } from "./chunk-RNQ5BLR2.js";
12
16
  import {
13
17
  LOCAL_CODEX_AGENT_ID,
14
18
  LOCAL_CODEX_AGENT_KEY,
@@ -17,53 +21,55 @@ import {
17
21
  } from "./chunk-VHBWHNVT.js";
18
22
  import {
19
23
  inferCaptureIntent
20
- } from "./chunk-A67QFHAA.js";
21
- import {
22
- CliProviderQuotaError,
23
- executeCli
24
- } from "./chunk-X7W4TNB4.js";
24
+ } from "./chunk-UG3WOFU6.js";
25
25
  import {
26
26
  buildCliPrompt
27
27
  } from "./chunk-ATNTHIZI.js";
28
28
  import {
29
29
  prepareTools
30
- } from "./chunk-2O4IZNTG.js";
30
+ } from "./chunk-YTQLJYLB.js";
31
31
  import {
32
32
  getAntigravityUserAgent,
33
33
  isAntigravityOAuthAgent,
34
34
  readAntigravityProjectId,
35
35
  resolveAntigravityCloudCodeBaseUrl
36
- } from "./chunk-C3RUNRHT.js";
36
+ } from "./chunk-4GBNEA5B.js";
37
37
  import {
38
38
  FORCED_TOOLS,
39
39
  addDefaultLightWebToolsForConfiguredAgents,
40
+ appendEnabledPackPromptPatches,
40
41
  applyDisabledTools,
41
42
  expandEnabledPacks,
43
+ formatListRunsCard,
44
+ formatNotFoundRunCard,
45
+ formatStartRunCard,
46
+ formatStatusRunCard,
47
+ formatStopRunCard,
42
48
  readXPostFunc,
43
49
  readXPostFunctionSchema,
44
50
  readXhsProfileFunc,
45
51
  readXhsProfileFunctionSchema
46
- } from "./chunk-TYSCFY6S.js";
52
+ } from "./chunk-RZ735TLX.js";
53
+ import {
54
+ CORE_DRAIN_REASON,
55
+ normalizeNonNegativeMs,
56
+ parseRetryAfterHeaderMs
57
+ } from "./chunk-YDCZVUFP.js";
47
58
  import {
48
59
  normalizeDialogTitle
49
60
  } from "./chunk-OWOHNGCN.js";
61
+ import {
62
+ prepareTokenUsageData
63
+ } from "./chunk-AM53Q2SD.js";
50
64
  import {
51
65
  BUILTIN_TITLE_LLM_CONFIG
52
- } from "./chunk-4ZDM73SD.js";
66
+ } from "./chunk-V2J635L5.js";
53
67
  import {
54
68
  fetchServerSyncedCredential
55
- } from "./chunk-I5URP43I.js";
56
- import {
57
- isCompiledBinary,
58
- parseUserIdFromAuthToken
59
- } from "./chunk-ISNCLGUZ.js";
60
- import {
61
- DEFAULT_NOLO_SERVER_URL
62
- } from "./chunk-OLZBQWZU.js";
69
+ } from "./chunk-GPZM7QH6.js";
63
70
  import {
64
71
  buildAgentRuntimeDialogWritePlan,
65
72
  buildLocalWorkspaceOpenAiTools,
66
- buildLocalWorkspacePolicyToolNames,
67
73
  buildLocalWorkspaceToolset,
68
74
  createHybridRecordStore,
69
75
  createLocalWorkspaceToolExecutors,
@@ -73,56 +79,68 @@ import {
73
79
  parseSseDataLineJson,
74
80
  readOpenAiCompatibleSseCompletion,
75
81
  resolveOpenAiCompatibleProviderConfig
76
- } from "./chunk-6KUOUWMP.js";
82
+ } from "./chunk-DRMGJFGQ.js";
77
83
  import {
78
84
  buildPlatformChatCompletionRequest,
79
85
  canUsePlatformChatProvider,
80
86
  parsePlatformChatCompletionData,
81
87
  parsePlatformChatCompletionResponse,
82
88
  readSseDataValues,
89
+ resolveLegacyDeepSeekProxyChatFallback,
83
90
  resolvePlatformChatProviderConfig,
84
91
  shouldUsePlatformChatProvider
85
- } from "./chunk-5KLGBAAR.js";
92
+ } from "./chunk-ZR4VHQ5D.js";
86
93
  import {
87
94
  resolveAgentRuntimeConfigFromRecord
88
- } from "./chunk-TILFE6LV.js";
95
+ } from "./chunk-NCGFB7NN.js";
89
96
  import {
90
97
  parseToolArgumentsJson,
91
98
  summarizeToolArguments
92
- } from "./chunk-6SLCD4RB.js";
99
+ } from "./chunk-4BTHUYMY.js";
93
100
  import {
101
+ buildLoadSkillExecutor,
94
102
  buildNoloWorkspaceCliToolExecutors,
95
103
  buildNoloWorkspaceOpenAiTools,
96
104
  canonicalizeToolNames,
97
- filterNoloWorkspaceToolNames,
98
105
  parseNoloWorkspaceToolArguments,
99
106
  resolveRuntimeToolSurfaceForAgent
100
- } from "./chunk-AUQ747NZ.js";
107
+ } from "./chunk-43UD5ZP7.js";
101
108
  import {
102
109
  clipCompactText
103
- } from "./chunk-5MMAK75Q.js";
110
+ } from "./chunk-S73OEOHH.js";
104
111
  import {
105
112
  createFileCredentialBroker,
106
113
  resolveCurrentRunRuntimeToolPolicy,
107
114
  resolveLocalWorkspaceExecutorOptionsFromPolicy,
108
115
  resolveRequestedRuntimeToolNames
109
- } from "./chunk-5CS33IBL.js";
116
+ } from "./chunk-PDL2AV3E.js";
110
117
  import {
111
118
  createOAuthTokenStore,
112
119
  isTokenExpired,
113
120
  readOAuthCredential,
114
121
  resolveFreshAccessToken
115
122
  } from "./chunk-JZPBVBIY.js";
123
+ import {
124
+ checkStaleRun,
125
+ finalizeRunRecord,
126
+ findRunRecord,
127
+ listRunRecords,
128
+ spawnLocalBackgroundRun
129
+ } from "./chunk-4ON5AV72.js";
116
130
  import {
117
131
  toErrorMessage
118
132
  } from "./chunk-HNMXYYJR.js";
119
133
  import {
120
134
  getDefaultCliLocalRuntimeDb
121
135
  } from "./chunk-H33743XH.js";
136
+ import {
137
+ compactWhitespace
138
+ } from "./chunk-DWLEOOGR.js";
122
139
  import {
123
140
  asRecordOrEmpty
124
141
  } from "./chunk-KX6YBIHG.js";
125
142
  import {
143
+ createTokenKey,
126
144
  dialogMessageRange
127
145
  } from "./chunk-O4BU24WZ.js";
128
146
  import {
@@ -138,25 +156,736 @@ import {
138
156
  PUBLIC_GLM_52_AGENT_KEY,
139
157
  PUBLIC_KIMI_K26_IMAGE_AGENT_KEY,
140
158
  PUBLIC_KIMI_K27_CODING_AGENT_KEY
141
- } from "./chunk-DSZUWUYB.js";
159
+ } from "./chunk-XHQWJUW4.js";
142
160
  import {
143
- isLoopbackHostname
144
- } from "./chunk-4SN6J65J.js";
161
+ isRecord
162
+ } from "./chunk-KUG52IAP.js";
163
+ import {
164
+ asTrimmedString
165
+ } from "./chunk-3EUW3WEO.js";
166
+ import {
167
+ isCompiledBinary,
168
+ parseUserIdFromAuthToken
169
+ } from "./chunk-5NBHQD4D.js";
170
+ import {
171
+ DEFAULT_NOLO_SERVER_URL
172
+ } from "./chunk-OLZBQWZU.js";
145
173
  import {
146
174
  NOLO_CLUSTER_SERVERS
147
175
  } from "./chunk-LCBAMY2M.js";
148
176
  import {
149
- asTrimmedString
150
- } from "./chunk-3EUW3WEO.js";
177
+ isLoopbackHostname
178
+ } from "./chunk-4SN6J65J.js";
151
179
  import {
152
180
  normalizeServerOrigin
153
181
  } from "./chunk-CF7PE763.js";
154
182
  import {
155
183
  asOptionalTrimmedString
156
184
  } from "./chunk-G3SUCT4W.js";
157
- import {
158
- isRecord
159
- } from "./chunk-KUG52IAP.js";
185
+
186
+ // packages/cli/tui/i18n.ts
187
+ var ZH_PATTERNS = /^zh/i;
188
+ function parseCliLocale(raw) {
189
+ const normalized = raw?.trim().toLowerCase();
190
+ if (!normalized) return null;
191
+ if (ZH_PATTERNS.test(normalized)) return "zh";
192
+ if (normalized === "en" || normalized.startsWith("en")) return "en";
193
+ return null;
194
+ }
195
+ function detectLocaleFromEnv(env) {
196
+ const explicit = parseCliLocale(env.NOLO_LANG);
197
+ if (explicit) return explicit;
198
+ const candidates = [env.LC_ALL, env.LC_CTYPE, env.LANG].filter(Boolean);
199
+ for (const candidate of candidates) {
200
+ if (ZH_PATTERNS.test(candidate)) return "zh";
201
+ if (candidate && !candidate.startsWith("C.") && !candidate.startsWith("POSIX")) {
202
+ return "en";
203
+ }
204
+ }
205
+ return null;
206
+ }
207
+ function detectLocale(env) {
208
+ return detectLocaleFromEnv(env) ?? "zh";
209
+ }
210
+ var currentLocale = detectLocale(process.env);
211
+ function getCliLocale() {
212
+ return currentLocale;
213
+ }
214
+ function setCliLocale(locale) {
215
+ currentLocale = locale;
216
+ }
217
+ function initCliLocale(env = process.env) {
218
+ currentLocale = detectLocale(env);
219
+ }
220
+ function newlineHint(platform = process.platform) {
221
+ return platform === "win32" ? "Ctrl+J" : "Shift+Enter";
222
+ }
223
+ var STRINGS = {
224
+ welcomeHint: {
225
+ en: `Tell nolo what you want. Use /help for commands. ${newlineHint()} for newline.`,
226
+ zh: `\u544A\u8BC9 nolo \u4F60\u60F3\u8981\u4EC0\u4E48\u3002\u8F93\u5165 /help \u67E5\u770B\u547D\u4EE4\u3002${newlineHint()} \u6362\u884C\u3002`
227
+ },
228
+ promptLabel: {
229
+ en: "\u276F ",
230
+ zh: "\u276F "
231
+ },
232
+ continueLabel: {
233
+ en: "\u2502 ",
234
+ zh: "\u2502 "
235
+ },
236
+ placeholder: {
237
+ en: "Type a message or / for commands...",
238
+ zh: "\u8F93\u5165\u6D88\u606F\uFF0C\u6216\u7528 / \u67E5\u770B\u547D\u4EE4\u2026"
239
+ },
240
+ newDialog: {
241
+ en: "new dialog",
242
+ zh: "\u65B0\u5BF9\u8BDD"
243
+ },
244
+ startedFreshDialog: {
245
+ en: "Started a fresh dialog.",
246
+ zh: "\u5DF2\u5F00\u59CB\u65B0\u5BF9\u8BDD\u3002"
247
+ },
248
+ bye: {
249
+ en: "Bye.",
250
+ zh: "\u518D\u89C1\u3002"
251
+ },
252
+ resumedDialogPrefix: {
253
+ en: "Resumed dialog",
254
+ zh: "\u5DF2\u6062\u590D\u5BF9\u8BDD"
255
+ },
256
+ resumeInvalidId: {
257
+ en: "does not look like a dialog id. Use /history to pick one.",
258
+ zh: "\u770B\u8D77\u6765\u4E0D\u662F dialog id\u3002\u7528 /history \u4ECE\u5217\u8868\u91CC\u9009\u4E00\u4E2A\u3002"
259
+ },
260
+ dialogResumeCancelled: {
261
+ en: "Dialog resume cancelled.",
262
+ zh: "\u5DF2\u53D6\u6D88\u6062\u590D\u5BF9\u8BDD\u3002"
263
+ },
264
+ agentSwitchCancelled: {
265
+ en: "Agent switch cancelled.",
266
+ zh: "\u5DF2\u53D6\u6D88\u5207\u6362 agent\u3002"
267
+ },
268
+ historyPickerTitle: {
269
+ en: "Resume dialog (\u2191\u2193 Enter Esc)",
270
+ zh: "\u6062\u590D\u5BF9\u8BDD\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
271
+ },
272
+ noDialogsYet: {
273
+ en: "No dialogs yet.",
274
+ zh: "\u8FD8\u6CA1\u6709\u5386\u53F2\u5BF9\u8BDD\u3002"
275
+ },
276
+ langUsage: {
277
+ en: "Usage: /lang <zh|en>",
278
+ zh: "\u7528\u6CD5\uFF1A/lang <zh|en>"
279
+ },
280
+ stopHint: {
281
+ en: "Esc to stop",
282
+ zh: "Esc \u505C\u6B62\u56DE\u590D"
283
+ },
284
+ queuedHint: {
285
+ en: "queued",
286
+ zh: "\u6392\u961F"
287
+ },
288
+ turnStopped: {
289
+ en: "Stopped this reply.",
290
+ zh: "\u5DF2\u505C\u6B62\u672C\u6B21\u56DE\u590D\u3002"
291
+ },
292
+ turnStoppedToolPending: {
293
+ en: "Stopped waiting. {0} may still be finishing in the background \u2014 its result won't be added to this conversation.",
294
+ 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"
295
+ },
296
+ turnStopping: {
297
+ en: "Stopping\u2026 press Esc again to force",
298
+ zh: "\u6B63\u5728\u505C\u6B62\u2026\u518D\u6309\u4E00\u6B21 Esc \u5F3A\u5236\u505C\u6B62"
299
+ },
300
+ forceStopped: {
301
+ en: "Force stopped. Background tasks may still be finishing.",
302
+ zh: "\u5DF2\u5F3A\u5236\u505C\u6B62\uFF0C\u540E\u53F0\u4EFB\u52A1\u53EF\u80FD\u4ECD\u5728\u6536\u5C3E\u3002"
303
+ },
304
+ turnFailed: {
305
+ en: "This reply failed. Queued messages are kept \u2014 press Enter to resend.",
306
+ 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"
307
+ },
308
+ quotaExhaustedHint: {
309
+ 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.",
310
+ 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"
311
+ },
312
+ balanceExhaustedHint: {
313
+ en: '[nolo] Insufficient balance. Your message is saved in this dialog \u2014 top up, then send again or say "continue".',
314
+ 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"
315
+ },
316
+ dialogPreservedHint: {
317
+ en: '[nolo] This turn failed, but the dialog is kept. Send another message (or say "continue") to keep going in the same conversation.',
318
+ 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"
319
+ },
320
+ dialogNotSavedHint: {
321
+ en: "[nolo] This turn did not create a dialog. Your next message will start a new conversation \u2014 restate what you need.",
322
+ 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"
323
+ },
324
+ copiedLastReply: {
325
+ en: "Copied the last reply to the clipboard.",
326
+ zh: "\u5DF2\u590D\u5236\u6700\u540E\u4E00\u6761\u56DE\u590D\u5230\u526A\u8D34\u677F\u3002"
327
+ },
328
+ copyNothing: {
329
+ en: "Nothing to copy yet.",
330
+ zh: "\u8FD8\u6CA1\u6709\u53EF\u590D\u5236\u7684\u5185\u5BB9\u3002"
331
+ },
332
+ copyFailed: {
333
+ en: "Copy failed",
334
+ zh: "\u590D\u5236\u5931\u8D25"
335
+ },
336
+ copyUnavailable: {
337
+ en: "Clipboard is unavailable in this environment. The last reply was printed above for manual copy.",
338
+ 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"
339
+ },
340
+ copyUsage: {
341
+ en: "Usage: /copy or /copy view",
342
+ zh: "\u7528\u6CD5\uFF1A/copy \u6216 /copy view"
343
+ },
344
+ copyViewTitle: {
345
+ en: "Copy view \u2014 latest AI reply",
346
+ zh: "\u590D\u5236\u89C6\u56FE \u2014 \u6700\u65B0 AI \u56DE\u590D"
347
+ },
348
+ copyViewHint: {
349
+ en: "Drag to select; edge scrolling uses native terminal scrollback. Press Esc or Enter to return.",
350
+ 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"
351
+ },
352
+ historyNoToken: {
353
+ en: "History requires an auth token. Run `nolo login` or set AUTH_TOKEN.",
354
+ 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"
355
+ },
356
+ historyBadToken: {
357
+ en: "Could not read a user id from AUTH_TOKEN. Run `nolo login` again.",
358
+ zh: "\u65E0\u6CD5\u4ECE AUTH_TOKEN \u89E3\u6790\u51FA\u7528\u6237 id\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C `nolo login`\u3002"
359
+ },
360
+ mouseOn: {
361
+ en: "Mouse mode on: wheel scrolls the transcript; hold Shift (or Option/Fn) to select text.",
362
+ 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"
363
+ },
364
+ mouseOff: {
365
+ en: "Mouse mode off: drag to select/copy freely; scroll with PageUp/PageDown.",
366
+ 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"
367
+ },
368
+ mouseUsage: {
369
+ en: "Usage: /mouse <on|off>",
370
+ zh: "\u7528\u6CD5\uFF1A/mouse <on|off>"
371
+ },
372
+ altscreenOn: {
373
+ en: "Alternate screen on: the TUI uses a private buffer so the terminal wheel no longer fights its own scroll state.",
374
+ 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"
375
+ },
376
+ altscreenOff: {
377
+ en: "Alternate screen off: the TUI shares the shell scrollback (wheel may desync the viewport).",
378
+ 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"
379
+ },
380
+ altscreenUsage: {
381
+ en: "Usage: /altscreen <on|off>",
382
+ zh: "\u7528\u6CD5\uFF1A/altscreen <on|off>"
383
+ },
384
+ langSwitched: {
385
+ en: "Language switched to English.",
386
+ zh: "\u5DF2\u5207\u6362\u4E3A\u4E2D\u6587\u3002"
387
+ },
388
+ // --- Tool trace copy ------------------------------------------------------
389
+ // The compact trace shows only status, never timing or output size: a line
390
+ // count told the user nothing actionable and the ms figure read as noise.
391
+ toolNeedsAction: {
392
+ en: "needs action",
393
+ zh: "\u5F85\u786E\u8BA4"
394
+ },
395
+ toolTimedOut: {
396
+ en: "timed out",
397
+ zh: "\u5DF2\u8D85\u65F6"
398
+ },
399
+ toolExitCode: {
400
+ en: "exit",
401
+ zh: "\u9000\u51FA\u7801"
402
+ },
403
+ toolFailed: {
404
+ en: "failed",
405
+ zh: "\u5931\u8D25"
406
+ },
407
+ usedSkillLabel: {
408
+ en: "Used Skill",
409
+ zh: "\u5DF2\u52A0\u8F7D\u6280\u80FD"
410
+ },
411
+ // --- Agent-run orchestration cards (injected into packages/ai helpers) ---
412
+ runStatusLabel: {
413
+ en: "Run status",
414
+ zh: "\u8FD0\u884C\u72B6\u6001"
415
+ },
416
+ runStartedLabel: {
417
+ en: "Run started",
418
+ zh: "\u8FD0\u884C\u5DF2\u542F\u52A8"
419
+ },
420
+ runStoppedLabel: {
421
+ en: "Run stopped",
422
+ zh: "\u8FD0\u884C\u5DF2\u505C\u6B62"
423
+ },
424
+ runLogTailLabel: {
425
+ en: "Log tail:",
426
+ zh: "\u65E5\u5FD7\u5C3E\u90E8\uFF1A"
427
+ },
428
+ runsListLabel: {
429
+ en: "Runs ({0})",
430
+ zh: "\u8FD0\u884C ({0})"
431
+ },
432
+ // --- Dialog (picker / confirm) copy --------------------------------------
433
+ // Key-hint wording is unified across select / multi-select / confirm so the
434
+ // three dialogs read as one family: "<Label> <↑↓ move · Enter choose ·
435
+ // Esc cancel> <count>". Connectors are "·" between keys, two spaces between
436
+ // the label, hint, and count. zh uses full-width parentheses to match the
437
+ // existing historyPickerTitle; en uses ASCII parentheses.
438
+ dialogSelectLabel: {
439
+ en: "Select",
440
+ zh: "\u9009\u62E9"
441
+ },
442
+ dialogSelectHint: {
443
+ en: "(\u2191\u2193 move \xB7 Enter choose \xB7 Esc cancel)",
444
+ zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
445
+ },
446
+ dialogMultiSelectLabel: {
447
+ en: "Select",
448
+ zh: "\u9009\u62E9"
449
+ },
450
+ dialogMultiSelectHint: {
451
+ en: "(\u2191\u2193 move \xB7 Space toggle \xB7 Enter submit \xB7 Esc cancel)",
452
+ zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Space \u5207\u6362 \xB7 Enter \u63D0\u4EA4 \xB7 Esc \u53D6\u6D88\uFF09"
453
+ },
454
+ dialogMultiSelectSelected: {
455
+ en: "selected",
456
+ zh: "\u5DF2\u9009"
457
+ },
458
+ dialogConfirmHint: {
459
+ en: "(\u2191\u2193 move \xB7 Enter choose \xB7 Esc cancel)",
460
+ zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
461
+ },
462
+ dialogConfirmTitle: {
463
+ en: "Confirm destructive shell command",
464
+ zh: "\u786E\u8BA4\u6267\u884C\u7834\u574F\u6027 shell \u547D\u4EE4"
465
+ },
466
+ dialogConfirmBody: {
467
+ en: "This command may delete or reset user content and needs explicit confirmation before it runs.",
468
+ 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"
469
+ },
470
+ dialogConfirmExternalFileTitle: {
471
+ en: "Confirm reading a file outside the workspace",
472
+ zh: "\u786E\u8BA4\u8BFB\u53D6\u5DE5\u4F5C\u533A\u5916\u90E8\u6587\u4EF6"
473
+ },
474
+ dialogConfirmExternalFileBody: {
475
+ en: "This path is outside the current workspace. Allow this one-time access, or deny it.",
476
+ 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"
477
+ },
478
+ dialogConfirmCommandTruncated: {
479
+ en: "(truncated)",
480
+ zh: "\uFF08\u5DF2\u622A\u65AD\uFF09"
481
+ },
482
+ dialogConfirmAllowLabel: {
483
+ en: "Allow",
484
+ zh: "\u5141\u8BB8"
485
+ },
486
+ dialogConfirmAllowDetail: {
487
+ en: "execute this time",
488
+ zh: "\u672C\u6B21\u6267\u884C"
489
+ },
490
+ dialogConfirmCancelLabel: {
491
+ en: "Cancel",
492
+ zh: "\u53D6\u6D88"
493
+ },
494
+ dialogConfirmCancelDetail: {
495
+ en: "abort the operation",
496
+ zh: "\u4E2D\u6B62\u64CD\u4F5C"
497
+ },
498
+ // --- Ask choice (ui_ask_choice) ------------------------------------------
499
+ askChoiceTitle: {
500
+ en: "question",
501
+ zh: "\u95EE\u9898"
502
+ },
503
+ askChoiceSubmit: {
504
+ en: "Submit",
505
+ zh: "\u63D0\u4EA4"
506
+ },
507
+ askChoiceOtherLabel: {
508
+ en: "Other",
509
+ zh: "\u5176\u4ED6"
510
+ },
511
+ askChoiceHintSingle: {
512
+ en: "Type your answer, then press Enter to save.",
513
+ zh: "\u8F93\u5165\u56DE\u7B54\u540E\u6309 Enter \u4FDD\u5B58\u3002"
514
+ },
515
+ askChoiceHintMulti: {
516
+ en: "Space to toggle, Enter to confirm selection.",
517
+ zh: "\u7A7A\u683C\u5207\u6362\u9009\u4E2D\uFF0CEnter \u786E\u8BA4\u63D0\u4EA4\u3002"
518
+ },
519
+ askChoiceFooterSingle: {
520
+ en: "\u21B5 pick/submit \xB7 tab switch \xB7 esc cancel",
521
+ zh: "\u21B5 \u9009\u62E9/\u63D0\u4EA4 \xB7 tab \u5207\u6362 \xB7 esc \u53D6\u6D88"
522
+ },
523
+ askChoiceFooterMulti: {
524
+ en: "\u21B5 submit \xB7 space toggle \xB7 tab switch \xB7 esc cancel",
525
+ zh: "\u21B5 \u63D0\u4EA4 \xB7 space \u5207\u6362 \xB7 tab \u5207\u6362 \xB7 esc \u53D6\u6D88"
526
+ },
527
+ askChoiceHistoryHint: {
528
+ en: "Type a number to choose, or reply directly:",
529
+ zh: "\u8BF7\u8F93\u5165\u5E8F\u53F7\u9009\u62E9\uFF0C\u6216\u76F4\u63A5\u56DE\u590D\uFF1A"
530
+ },
531
+ askChoiceHistorySelected: {
532
+ en: "selected",
533
+ zh: "\u5DF2\u9009"
534
+ },
535
+ askChoiceHistoryCancelled: {
536
+ en: "cancelled",
537
+ zh: "\u5DF2\u53D6\u6D88"
538
+ },
539
+ contextTitle: {
540
+ en: "Workspace context",
541
+ zh: "\u5DE5\u4F5C\u533A\u4E0A\u4E0B\u6587"
542
+ },
543
+ contextNext: {
544
+ en: "Next:",
545
+ zh: "\u4E0B\u4E00\u6B65\uFF1A"
546
+ },
547
+ contextFieldAgent: {
548
+ en: "agent",
549
+ zh: "\u667A\u80FD\u4F53"
550
+ },
551
+ contextFieldTokens: {
552
+ en: "tokens",
553
+ zh: "\u4EE4\u724C"
554
+ },
555
+ contextFieldDialog: {
556
+ en: "dialog",
557
+ zh: "\u5BF9\u8BDD"
558
+ },
559
+ contextFieldDocs: {
560
+ en: "docs",
561
+ zh: "\u6587\u6863"
562
+ },
563
+ contextFieldSkills: {
564
+ en: "skills",
565
+ zh: "\u6280\u80FD"
566
+ },
567
+ contextFieldProfile: {
568
+ en: "profile",
569
+ zh: "\u914D\u7F6E"
570
+ },
571
+ contextFieldRuntime: {
572
+ en: "runtime",
573
+ zh: "\u8FD0\u884C\u65F6"
574
+ },
575
+ contextFieldTools: {
576
+ en: "tools",
577
+ zh: "\u5DE5\u5177"
578
+ },
579
+ contextFieldThinking: {
580
+ en: "thinking",
581
+ zh: "\u601D\u8003"
582
+ },
583
+ contextFieldServer: {
584
+ en: "server",
585
+ zh: "\u670D\u52A1\u7AEF"
586
+ },
587
+ contextNextAgents: {
588
+ en: "see specialist shortcuts",
589
+ zh: "\u67E5\u770B\u4E13\u7528\u667A\u80FD\u4F53\u5FEB\u6377\u65B9\u5F0F"
590
+ },
591
+ contextNextDoc: {
592
+ en: "add working context",
593
+ zh: "\u6DFB\u52A0\u5DE5\u4F5C\u4E0A\u4E0B\u6587"
594
+ },
595
+ contextNextSkill: {
596
+ en: "attach a skill to this workspace",
597
+ zh: "\u4E3A\u8BE5\u5DE5\u4F5C\u533A\u6302\u8F7D\u6280\u80FD"
598
+ },
599
+ contextNextNew: {
600
+ en: "start a clean dialog",
601
+ zh: "\u5F00\u59CB\u4E00\u4E2A\u5E72\u51C0\u7684\u5BF9\u8BDD"
602
+ },
603
+ agentsTitle: {
604
+ en: "Agents:",
605
+ zh: "\u667A\u80FD\u4F53\uFF1A"
606
+ },
607
+ agentsTip: {
608
+ en: "Tip: run /switch for the full picker, or /switch list for your private agents too.",
609
+ 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"
610
+ },
611
+ helpText: {
612
+ en: [
613
+ "Commands:",
614
+ " /help Show this help",
615
+ " /new Clear screen and start a fresh dialog",
616
+ " /compact Compact current dialog and fork a new one",
617
+ " /context Show workspace context and next actions",
618
+ " /runtime <mode> Use auto, local, or server runtime",
619
+ " /tools <mode> Control tool trace: hide, compact, verbose",
620
+ " /thinking <mode> Control thinking output: hide, marker, show",
621
+ " /switch Pick an agent interactively (\u2191\u2193, Enter)",
622
+ " /switch list List agents as text",
623
+ " /switch <name> Switch directly by name, alias, or key (alias: /agent)",
624
+ " /agents List platform agent shortcuts",
625
+ " /history Pick a recent dialog to resume (\u2191\u2193, Enter)",
626
+ " /resume <dialogId> Resume a dialog directly by id",
627
+ " /lang <zh|en> Switch interface language",
628
+ " /copy Copy the last reply to the clipboard",
629
+ " /copy view Open native scrollback for partial selection (Ctrl+O)",
630
+ " /mouse <on|off> Toggle mouse mode (off = drag to select text)",
631
+ " /altscreen <on|off> Toggle the terminal alternate screen (default on; off shares shell scrollback)",
632
+ " /doc List attached docs",
633
+ " /doc attach <doc> Attach a doc to this workspace",
634
+ " /skill List attached skills",
635
+ " /skill attach <ref> Attach a skill (dbKey, name, or SKILL.md path)",
636
+ " /skill detach <ref> Detach a skill",
637
+ " /skill clear Detach all skills",
638
+ " /customize Describe how you want to tune nolo",
639
+ " /tasks List background process tasks (aliases: /jobs, /procs)",
640
+ " /stop <pid|all> Stop background process tasks",
641
+ " /login Show login/profile hint",
642
+ " /profile Show active profile",
643
+ " /update Update the nolo CLI install",
644
+ " /version Show version/update hint",
645
+ " /exit Leave the workspace",
646
+ "",
647
+ "You can also type normally. nolo routes simple read/status requests to CLI commands and sends the rest to the current agent."
648
+ ].join("\n"),
649
+ zh: [
650
+ "\u547D\u4EE4\uFF1A",
651
+ " /help \u663E\u793A\u672C\u5E2E\u52A9",
652
+ " /new \u6E05\u5C4F\u5E76\u5F00\u59CB\u65B0\u5BF9\u8BDD",
653
+ " /compact \u538B\u7F29\u5F53\u524D\u5BF9\u8BDD\u5E76\u5206\u53C9\u51FA\u65B0\u5BF9\u8BDD",
654
+ " /context \u67E5\u770B\u5DE5\u4F5C\u533A\u4E0A\u4E0B\u6587\u4E0E\u540E\u7EED\u64CD\u4F5C",
655
+ " /runtime <mode> \u5207\u6362 runtime\uFF1Aauto\u3001local\u3001server",
656
+ " /tools <mode> \u5DE5\u5177\u8F68\u8FF9\u663E\u793A\uFF1Ahide\u3001compact\u3001verbose",
657
+ " /thinking <mode> \u601D\u8003\u8FC7\u7A0B\u663E\u793A\uFF1Ahide\u3001marker\u3001show",
658
+ " /switch \u4EA4\u4E92\u5F0F\u9009\u62E9 agent\uFF08\u2191\u2193 \u79FB\u52A8\uFF0CEnter \u786E\u8BA4\uFF09",
659
+ " /switch list \u4EE5\u6587\u672C\u5217\u51FA\u5168\u90E8 agent",
660
+ " /switch <name> \u6309\u540D\u79F0\u3001\u522B\u540D\u6216 key \u76F4\u63A5\u5207\u6362\uFF08\u522B\u540D\uFF1A/agent\uFF09",
661
+ " /agents \u5217\u51FA\u5E73\u53F0 agent \u5FEB\u6377\u65B9\u5F0F",
662
+ " /history \u4ECE\u6700\u8FD1\u5BF9\u8BDD\u4E2D\u9009\u62E9\u5E76\u6062\u590D\uFF08\u2191\u2193\uFF0CEnter\uFF09",
663
+ " /resume <dialogId> \u6309 id \u76F4\u63A5\u6062\u590D\u5BF9\u8BDD",
664
+ " /lang <zh|en> \u5207\u6362\u754C\u9762\u8BED\u8A00",
665
+ " /copy \u590D\u5236\u6700\u540E\u4E00\u6761\u56DE\u590D\u5230\u526A\u8D34\u677F",
666
+ " /copy view \u6253\u5F00\u539F\u751F\u56DE\u6EDA\u8FDB\u884C\u8DE8\u5C4F\u62D6\u9009\uFF08Ctrl+O\uFF09",
667
+ " /mouse <on|off> \u5207\u6362\u9F20\u6807\u6A21\u5F0F\uFF08off \u540E\u53EF\u76F4\u63A5\u62D6\u9009\u6587\u672C\uFF09",
668
+ " /altscreen <on|off> \u5207\u6362\u7EC8\u7AEF\u5907\u7528\u5C4F\uFF08\u9ED8\u8BA4 on\uFF1Boff \u6539\u4E3A\u4E0E shell \u5171\u7528\u56DE\u6EDA\uFF09",
669
+ " /doc \u5217\u51FA\u5DF2\u6302\u8F7D\u7684\u6587\u6863",
670
+ " /doc attach <doc> \u6302\u8F7D\u6587\u6863\u5230\u5F53\u524D\u5DE5\u4F5C\u533A",
671
+ " /skill \u5217\u51FA\u5DF2\u6302\u8F7D\u7684\u6280\u80FD",
672
+ " /skill attach <ref> \u6302\u8F7D\u6280\u80FD\uFF08dbKey\u3001\u540D\u79F0\u6216 SKILL.md \u8DEF\u5F84\uFF09",
673
+ " /skill detach <ref> \u5378\u8F7D\u6307\u5B9A\u6280\u80FD",
674
+ " /skill clear \u5378\u8F7D\u5168\u90E8\u6280\u80FD",
675
+ " /customize \u63CF\u8FF0\u4F60\u60F3\u600E\u4E48\u8C03\u6559 nolo",
676
+ " /tasks \u5217\u51FA\u540E\u53F0\u5B50\u8FDB\u7A0B\u4EFB\u52A1\uFF08\u522B\u540D\uFF1A/jobs, /procs\uFF09",
677
+ " /stop <pid|all> \u505C\u6B62\u6307\u5B9A\u7684\u540E\u53F0\u4EFB\u52A1",
678
+ " /login \u67E5\u770B\u767B\u5F55 / \u914D\u7F6E\u63D0\u793A",
679
+ " /profile \u67E5\u770B\u5F53\u524D\u914D\u7F6E\u73AF\u5883",
680
+ " /update \u66F4\u65B0 nolo CLI",
681
+ " /version \u67E5\u770B\u7248\u672C\u4E0E\u66F4\u65B0\u63D0\u793A",
682
+ " /exit \u9000\u51FA\u5DE5\u4F5C\u533A",
683
+ "",
684
+ "\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"
685
+ ].join("\n")
686
+ },
687
+ // --- Slash-command output ---------------------------------------------
688
+ // Command results that used to be hardcoded English. Usage lines keep the
689
+ // command literal untouched; only the surrounding words are translated.
690
+ unknownCommand: {
691
+ en: "Unknown command: {0}\n\n",
692
+ zh: "\u672A\u77E5\u547D\u4EE4\uFF1A{0}\n\n"
693
+ },
694
+ runtimeUsage: { en: "Usage: /runtime <auto|local|server>", zh: "\u7528\u6CD5\uFF1A/runtime <auto|local|server>" },
695
+ runtimeSet: { en: "Runtime: {0}", zh: "\u8FD0\u884C\u6A21\u5F0F\uFF1A{0}" },
696
+ toolsCurrent: {
697
+ en: "Tool display: {0} (hide | compact | verbose)",
698
+ zh: "\u5DE5\u5177\u663E\u793A\uFF1A{0}\uFF08hide | compact | verbose\uFF09"
699
+ },
700
+ toolsUsage: { en: "Usage: /tools <hide|compact|verbose>", zh: "\u7528\u6CD5\uFF1A/tools <hide|compact|verbose>" },
701
+ toolsSet: { en: "Tool display: {0}", zh: "\u5DE5\u5177\u663E\u793A\uFF1A{0}" },
702
+ thinkingCurrent: {
703
+ en: "Thinking display: {0} (hide | marker | show)",
704
+ zh: "\u601D\u8003\u663E\u793A\uFF1A{0}\uFF08hide | marker | show\uFF09"
705
+ },
706
+ thinkingUsage: { en: "Usage: /thinking <hide|marker|show>", zh: "\u7528\u6CD5\uFF1A/thinking <hide|marker|show>" },
707
+ thinkingSet: { en: "Thinking display: {0}", zh: "\u601D\u8003\u663E\u793A\uFF1A{0}" },
708
+ tasksRunning: { en: "Running processes ({0}):", zh: "\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\uFF08{0}\uFF09\uFF1A" },
709
+ tasksStopped: { en: "Stopped/exited ({0}):", zh: "\u5DF2\u505C\u6B62/\u5DF2\u9000\u51FA\uFF08{0}\uFF09\uFF1A" },
710
+ tasksNone: { en: "No processes.", zh: "\u6CA1\u6709\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\u3002" },
711
+ stopUsage: { en: "Usage: /stop <pid|label|all>", zh: "\u7528\u6CD5\uFF1A/stop <pid|label|all>" },
712
+ stopAllDone: { en: "Stopped {0} processes", zh: "\u5DF2\u505C\u6B62 {0} \u4E2A\u8FDB\u7A0B" },
713
+ stopNoPid: { en: "No running process with pid {0}", zh: "\u6CA1\u6709 pid \u4E3A {0} \u7684\u8FD0\u884C\u4E2D\u8FDB\u7A0B" },
714
+ stopPidDone: { en: "Stopped pid {0} ({1})", zh: "\u5DF2\u505C\u6B62 pid {0}\uFF08{1}\uFF09" },
715
+ stopNoLabel: { en: "No running process labeled '{0}'", zh: "\u6CA1\u6709\u540D\u4E3A\u201C{0}\u201D\u7684\u8FD0\u884C\u4E2D\u8FDB\u7A0B" },
716
+ stopLabelsDone: { en: "Stopped {0}", zh: "\u5DF2\u505C\u6B62 {0}" },
717
+ compactNothing: {
718
+ en: "Current dialog: new (nothing to compact yet)",
719
+ zh: "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u662F\u65B0\u7684\uFF08\u8FD8\u6CA1\u6709\u53EF\u538B\u7F29\u7684\u5185\u5BB9\uFF09"
720
+ },
721
+ agentCurrent: { en: "Current agent: {0} ({1})", zh: "\u5F53\u524D agent\uFF1A{0}\uFF08{1}\uFF09" },
722
+ agentUnknown: {
723
+ en: `I don't know agent "{0}" yet.
724
+ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`,
725
+ 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"
726
+ },
727
+ themeCurrent: { en: "Current theme: {0} \xB7 {1}", zh: "\u5F53\u524D\u4E3B\u9898\uFF1A{0} \xB7 {1}" },
728
+ themeUsage: {
729
+ en: "Usage: /theme <name> | /theme light | /theme dark",
730
+ zh: "\u7528\u6CD5\uFF1A/theme <name> | /theme light | /theme dark"
731
+ },
732
+ themeAvailable: { en: "Available themes: {0}", zh: "\u53EF\u7528\u4E3B\u9898\uFF1A{0}" },
733
+ themeBrightnessSwitched: { en: "Switched to {0} background colors.", zh: "\u5DF2\u5207\u6362\u5230 {0} \u80CC\u666F\u8272\u3002" },
734
+ themeBrightnessAuto: {
735
+ en: "Background colors follow terminal detection (now: {0}).",
736
+ zh: "\u80CC\u666F\u8272\u8DDF\u968F\u7EC8\u7AEF\u81EA\u52A8\u68C0\u6D4B\uFF08\u5F53\u524D\uFF1A{0}\uFF09\u3002"
737
+ },
738
+ themeSwitched: { en: "Switched to theme: {0}", zh: "\u5DF2\u5207\u6362\u5230\u4E3B\u9898\uFF1A{0}" },
739
+ themeUnknown: { en: "Unknown theme: {0}. Available themes: {1}", zh: "\u672A\u77E5\u4E3B\u9898\uFF1A{0}\u3002\u53EF\u7528\u4E3B\u9898\uFF1A{1}" },
740
+ densityCurrent: {
741
+ en: "Current density: {0}\nUsage: /density <cozy|spacious>",
742
+ zh: "\u5F53\u524D\u5BC6\u5EA6\uFF1A{0}\n\u7528\u6CD5\uFF1A/density <cozy|spacious>"
743
+ },
744
+ densitySwitched: { en: "Switched to layout density: {0}", zh: "\u5DF2\u5207\u6362\u5230\u5E03\u5C40\u5BC6\u5EA6\uFF1A{0}" },
745
+ densityUnknown: {
746
+ en: "Unknown density: {0}. Use 'cozy' or 'spacious'.",
747
+ zh: "\u672A\u77E5\u5BC6\u5EA6\uFF1A{0}\u3002\u8BF7\u4F7F\u7528 cozy \u6216 spacious\u3002"
748
+ },
749
+ docAttachUsage: { en: "Usage: /doc attach <doc>", zh: "\u7528\u6CD5\uFF1A/doc attach <doc>" },
750
+ docList: { en: "Attached docs: {0}", zh: "\u5DF2\u6302\u8F7D\u6587\u6863\uFF1A{0}" },
751
+ 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" },
752
+ skillAttachUsage: { en: "Usage: /skill attach <skill-ref>", zh: "\u7528\u6CD5\uFF1A/skill attach <skill-ref>" },
753
+ skillAttached: { en: "Attached skill: {0}", zh: "\u5DF2\u6302\u8F7D\u6280\u80FD\uFF1A{0}" },
754
+ skillDetachUsage: { en: "Usage: /skill detach <skill-ref>", zh: "\u7528\u6CD5\uFF1A/skill detach <skill-ref>" },
755
+ skillDetached: { en: "Detached skill: {0}", zh: "\u5DF2\u5378\u8F7D\u6280\u80FD\uFF1A{0}" },
756
+ skillNotAttached: { en: "Skill not attached: {0}", zh: "\u6280\u80FD\u672A\u6302\u8F7D\uFF1A{0}" },
757
+ skillNone: { en: "No skills attached.", zh: "\u8FD8\u6CA1\u6709\u6302\u8F7D\u6280\u80FD\u3002" },
758
+ skillCleared: { en: "Cleared {0} skill(s).", zh: "\u5DF2\u6E05\u7A7A {0} \u4E2A\u6280\u80FD\u3002" },
759
+ skillList: {
760
+ en: "Attached skills: {0}\nUsage: /skill attach <ref> | /skill detach <ref> | /skill clear",
761
+ zh: "\u5DF2\u6302\u8F7D\u6280\u80FD\uFF1A{0}\n\u7528\u6CD5\uFF1A/skill attach <ref> | /skill detach <ref> | /skill clear"
762
+ },
763
+ skillNoneHint: {
764
+ 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/ then docs/skills/), or a direct path.",
765
+ 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/ \u4E0E docs/skills/ \u4E2D\u67E5\u627E\uFF09\u6216\u76F4\u63A5\u8DEF\u5F84\u3002"
766
+ },
767
+ customizeHint: {
768
+ en: "Tell nolo what to change, for example: /customize make my default agent more concise.",
769
+ zh: "\u544A\u8BC9 nolo \u4F60\u60F3\u6539\u4EC0\u4E48\uFF0C\u4F8B\u5982\uFF1A/customize make my default agent more concise\u3002"
770
+ },
771
+ loginHint: {
772
+ en: "MVP login uses profile/env auth. Set AUTH_TOKEN, NOLO_SERVER, or NOLO_PROFILE before starting nolo.",
773
+ 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"
774
+ },
775
+ versionInfo: {
776
+ en: "nolo {0}\nUpdate this install with: nolo update\nIf repo-local output differs, publish/install the latest npm package first.",
777
+ 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"
778
+ },
779
+ versionUnknown: { en: "unknown version", zh: "\u672A\u77E5\u7248\u672C" },
780
+ // --- Dialog list / timestamps -----------------------------------------
781
+ recentDialogs: { en: "Recent dialogs:", zh: "\u6700\u8FD1\u5BF9\u8BDD\uFF1A" },
782
+ dialogListTip: {
783
+ en: "Tip: run /history to pick one interactively, or paste an id after /resume.",
784
+ zh: "\u63D0\u793A\uFF1A\u7528 /history \u4EA4\u4E92\u5F0F\u9009\u62E9\uFF0C\u6216\u628A id \u7C98\u5230 /resume \u540E\u9762\u3002"
785
+ },
786
+ timeJustNow: { en: "just now", zh: "\u521A\u521A" },
787
+ timeMinutesAgo: { en: "{0}m ago", zh: "{0} \u5206\u949F\u524D" },
788
+ timeHoursAgo: { en: "{0}h ago", zh: "{0} \u5C0F\u65F6\u524D" },
789
+ timeDaysAgo: { en: "{0}d ago", zh: "{0} \u5929\u524D" },
790
+ // Overflow hints shared by select / multi-select / ask-choice. The arrows
791
+ // and count are part of the copy so each locale can order them naturally.
792
+ dialogMoreAbove: { en: "\u2191 {0} more", zh: "\u2191 {0} \u66F4\u591A" },
793
+ dialogMoreBelow: { en: "\u2193 {0} more", zh: "\u2193 {0} \u66F4\u591A" },
794
+ // Action gate handoff
795
+ actionGateNeeded: {
796
+ en: "Action needed in your terminal",
797
+ zh: "\u7EC8\u7AEF\u9700\u8981\u4F60\u7684\u64CD\u4F5C"
798
+ },
799
+ actionGateEnterHint: {
800
+ en: "Press Enter to run it now. Follow any prompts below, or Ctrl+C to cancel.",
801
+ zh: "\u6309 Enter \u7ACB\u5373\u6267\u884C\uFF0C\u6309\u4E0B\u65B9\u63D0\u793A\u64CD\u4F5C\uFF0C\u6216\u6309 Ctrl+C \u53D6\u6D88\u3002"
802
+ },
803
+ actionGateInteractiveTitle: {
804
+ en: "This command requires an interactive terminal.",
805
+ zh: "\u8BE5\u547D\u4EE4\u9700\u8981\u4EA4\u4E92\u5F0F\u7EC8\u7AEF"
806
+ },
807
+ actionGateInteractiveBody: {
808
+ en: "Complete it in the terminal, then nolo will continue.",
809
+ zh: "\u5728\u7EC8\u7AEF\u4E2D\u5B8C\u6210\u64CD\u4F5C\u540E\uFF0Cnolo \u5C06\u7EE7\u7EED\u3002"
810
+ },
811
+ // Agent catalog sources
812
+ agentSourcePlatform: {
813
+ en: "Platform",
814
+ zh: "\u5E73\u53F0"
815
+ },
816
+ agentSourceSubscription: {
817
+ en: "Subscription",
818
+ zh: "\u8BA2\u9605"
819
+ },
820
+ agentSourceApi: {
821
+ en: "API",
822
+ zh: "API"
823
+ }
824
+ };
825
+ function t(key, ...params) {
826
+ const text = STRINGS[key][currentLocale];
827
+ if (params.length === 0) return text;
828
+ return text.replace(/\{(\d+)\}/g, (match, index) => {
829
+ const replacement = params[Number(index)];
830
+ return replacement === void 0 ? match : replacement;
831
+ });
832
+ }
833
+ var TOOL_LABELS = {
834
+ // Local workspace tools (packages/agent-runtime/localWorkspaceTools.ts)
835
+ readFile: { en: "Read", zh: "\u8BFB\u53D6" },
836
+ writeFile: { en: "Write", zh: "\u5199\u5165" },
837
+ editFile: { en: "Edit", zh: "\u7F16\u8F91" },
838
+ listFiles: { en: "List", zh: "\u5217\u51FA" },
839
+ searchFiles: { en: "Search", zh: "\u641C\u7D22" },
840
+ globFiles: { en: "Glob", zh: "\u5339\u914D" },
841
+ execShell: { en: "Run", zh: "\u6267\u884C" },
842
+ runCommand: { en: "Run", zh: "\u6267\u884C" },
843
+ captureVisualState: { en: "Capture", zh: "\u622A\u5C4F" },
844
+ // Workspace / diagnostics
845
+ searchWorkspace: { en: "Search workspace", zh: "\u641C\u7D22\u5DE5\u4F5C\u533A" },
846
+ cliDoctor: { en: "Doctor", zh: "\u81EA\u68C0" },
847
+ cliWhoami: { en: "Whoami", zh: "\u67E5\u770B\u8EAB\u4EFD" },
848
+ checkEnv: { en: "Check env", zh: "\u68C0\u67E5\u73AF\u5883" },
849
+ configure: { en: "Configure", zh: "\u914D\u7F6E" },
850
+ notifyUser: { en: "Notify", zh: "\u901A\u77E5" },
851
+ // Docs / dialogs / spaces
852
+ readDoc: { en: "Read doc", zh: "\u8BFB\u53D6\u6587\u6863" },
853
+ createDoc: { en: "Create doc", zh: "\u65B0\u5EFA\u6587\u6863" },
854
+ updateDoc: { en: "Update doc", zh: "\u66F4\u65B0\u6587\u6863" },
855
+ readDialog: { en: "Read dialog", zh: "\u8BFB\u53D6\u5BF9\u8BDD" },
856
+ listDialogs: { en: "List dialogs", zh: "\u5217\u51FA\u5BF9\u8BDD" },
857
+ queryDialogsBySubjectRef: { en: "Query dialogs", zh: "\u67E5\u8BE2\u5BF9\u8BDD" },
858
+ searchDialogMessages: { en: "Search messages", zh: "\u641C\u7D22\u6D88\u606F" },
859
+ listSpaces: { en: "List spaces", zh: "\u5217\u51FA\u7A7A\u95F4" },
860
+ readSpace: { en: "Read space", zh: "\u8BFB\u53D6\u7A7A\u95F4" },
861
+ // Tables
862
+ createTable: { en: "Create table", zh: "\u521B\u5EFA\u8868" },
863
+ queryTableRows: { en: "Query rows", zh: "\u67E5\u8BE2\u8868\u884C" },
864
+ addTableRow: { en: "Add row", zh: "\u65B0\u589E\u8868\u884C" },
865
+ addTableRows: { en: "Add rows", zh: "\u65B0\u589E\u8868\u884C" },
866
+ updateTableRow: { en: "Update row", zh: "\u66F4\u65B0\u8868\u884C" },
867
+ deleteTableRow: { en: "Delete row", zh: "\u5220\u9664\u8868\u884C" },
868
+ // Web
869
+ // Tree group header uses the same short category noun as Read/Search/Run
870
+ // ("Fetch" / "抓取网页"), not a longer "Fetch page" phrase.
871
+ fetchWebpage: { en: "Fetch", zh: "\u6293\u53D6\u7F51\u9875" },
872
+ readPage: { en: "Read page", zh: "\u8BFB\u53D6\u7F51\u9875" },
873
+ exaSearch: { en: "Web search", zh: "\u8054\u7F51\u641C\u7D22" },
874
+ // Skill loading
875
+ loadSkill: { en: "Used Skill", zh: "\u4F7F\u7528\u6280\u80FD" }
876
+ };
877
+ function toolLabel(name) {
878
+ return TOOL_LABELS[name]?.[currentLocale] ?? name;
879
+ }
880
+ function agentRunCardLabels() {
881
+ return {
882
+ runStatus: t("runStatusLabel"),
883
+ runStarted: t("runStartedLabel"),
884
+ runStopped: t("runStoppedLabel"),
885
+ logTail: t("runLogTailLabel"),
886
+ runs: (count) => t("runsListLabel", String(count))
887
+ };
888
+ }
160
889
 
161
890
  // packages/cli/client/localRuntimeAdapter.ts
162
891
  import { dirname, extname, join } from "node:path";
@@ -191,6 +920,7 @@ import { request as httpRequest } from "node:http";
191
920
  import { request as httpsRequest } from "node:https";
192
921
  var TRANSIENT_FETCH_MAX_ATTEMPTS = 3;
193
922
  var TRANSIENT_FETCH_RETRY_BASE_DELAY_MS = 250;
923
+ var CORE_DRAINING_MAX_ATTEMPTS = 30;
194
924
  var RETRYABLE_HTTP_STATUSES = /* @__PURE__ */ new Set([429, 503]);
195
925
  function isTransientFetchError(error) {
196
926
  const message = toErrorMessage(error);
@@ -204,19 +934,19 @@ async function defaultSleep(ms) {
204
934
  function transientFetchRetryDelayMs(attempt) {
205
935
  return Math.min(attempt * TRANSIENT_FETCH_RETRY_BASE_DELAY_MS, 2e3);
206
936
  }
937
+ var MAX_RETRY_DELAY_MS = 1e4;
207
938
  async function resolveRetryAfterMs(response, attempt) {
208
- const header = response.headers.get("retry-after");
209
- if (header) {
210
- const seconds = Number(header.trim());
211
- if (Number.isFinite(seconds) && seconds >= 0) {
212
- return Math.min(seconds * 1e3, 1e4);
213
- }
939
+ const headerMs = parseRetryAfterHeaderMs(
940
+ response.headers.get("retry-after")
941
+ );
942
+ if (headerMs !== null) {
943
+ return Math.min(headerMs, MAX_RETRY_DELAY_MS);
214
944
  }
215
945
  try {
216
946
  const body = await response.clone().text();
217
947
  const parsed = JSON.parse(body);
218
- const ms = Number(parsed?.retryAfterMs);
219
- if (Number.isFinite(ms) && ms >= 0) return Math.min(ms, 1e4);
948
+ const ms = normalizeNonNegativeMs(parsed?.retryAfterMs, 0);
949
+ if (ms > 0) return Math.min(ms, MAX_RETRY_DELAY_MS);
220
950
  } catch {
221
951
  }
222
952
  return transientFetchRetryDelayMs(attempt);
@@ -281,26 +1011,44 @@ async function defaultLoopbackRequest(input, init) {
281
1011
  req.end();
282
1012
  });
283
1013
  }
1014
+ async function isCoreDrainingResponse(response) {
1015
+ if (response.status !== 503) return false;
1016
+ try {
1017
+ const body = await response.clone().json();
1018
+ return body?.reason === CORE_DRAIN_REASON;
1019
+ } catch {
1020
+ return false;
1021
+ }
1022
+ }
284
1023
  async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
285
1024
  const retryableStatuses = options.retryableStatuses ?? RETRYABLE_HTTP_STATUSES;
1025
+ const requestedMaxAttempts = Number(options.maxAttempts);
1026
+ const maxAttempts = Number.isFinite(requestedMaxAttempts) ? Math.min(100, Math.max(1, Math.floor(requestedMaxAttempts))) : TRANSIENT_FETCH_MAX_ATTEMPTS;
1027
+ const requestedCoreDrainingMaxAttempts = Number(options.coreDrainingMaxAttempts);
1028
+ const coreDrainingMaxAttempts = Number.isFinite(requestedCoreDrainingMaxAttempts) ? Math.min(100, Math.max(1, Math.floor(requestedCoreDrainingMaxAttempts))) : CORE_DRAINING_MAX_ATTEMPTS;
1029
+ const loopMaxAttempts = Math.max(maxAttempts, coreDrainingMaxAttempts);
286
1030
  let lastError;
287
- for (let attempt = 1; attempt <= TRANSIENT_FETCH_MAX_ATTEMPTS; attempt += 1) {
1031
+ for (let attempt = 1; attempt <= loopMaxAttempts; attempt += 1) {
288
1032
  try {
289
1033
  if (options.loopbackRequest && isLoopbackUrl(input)) {
290
1034
  return await options.loopbackRequest(input, init);
291
1035
  }
292
1036
  const response = await fetchImpl(input, init);
293
- if (retryableStatuses.has(response.status) && attempt < TRANSIENT_FETCH_MAX_ATTEMPTS && !init?.signal?.aborted) {
294
- const delayMs = await resolveRetryAfterMs(response, attempt);
295
- await (options.sleep ?? defaultSleep)(delayMs);
296
- continue;
1037
+ if (retryableStatuses.has(response.status) && !init?.signal?.aborted) {
1038
+ const coreDraining = await isCoreDrainingResponse(response);
1039
+ const attemptBudget = coreDraining ? coreDrainingMaxAttempts : maxAttempts;
1040
+ if (attempt < attemptBudget) {
1041
+ const delayMs = await resolveRetryAfterMs(response, attempt);
1042
+ await (options.sleep ?? defaultSleep)(delayMs);
1043
+ continue;
1044
+ }
297
1045
  }
298
1046
  return response;
299
1047
  } catch (error) {
300
1048
  if (init?.signal?.aborted) throw error;
301
1049
  if (!isTransientFetchError(error)) throw error;
302
1050
  lastError = error;
303
- if (attempt < TRANSIENT_FETCH_MAX_ATTEMPTS) {
1051
+ if (attempt < maxAttempts) {
304
1052
  await (options.sleep ?? defaultSleep)(transientFetchRetryDelayMs(attempt));
305
1053
  }
306
1054
  }
@@ -713,14 +1461,14 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
713
1461
  [PUBLIC_KIMI_K26_IMAGE_AGENT_KEY]: {
714
1462
  key: PUBLIC_KIMI_K26_IMAGE_AGENT_KEY,
715
1463
  name: "Kimi K2.6",
716
- provider: "ollama-cloud",
1464
+ provider: "nolo",
717
1465
  model: "kimi-k2.6",
718
1466
  apiSource: "platform",
719
1467
  useServerProxy: true,
720
1468
  rawRecord: {
721
1469
  dbKey: PUBLIC_KIMI_K26_IMAGE_AGENT_KEY,
722
1470
  isPublic: true,
723
- provider: "ollama-cloud",
1471
+ provider: "nolo",
724
1472
  model: "kimi-k2.6",
725
1473
  apiSource: "platform",
726
1474
  useServerProxy: true
@@ -729,14 +1477,14 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
729
1477
  [PUBLIC_KIMI_K27_CODING_AGENT_KEY]: {
730
1478
  key: PUBLIC_KIMI_K27_CODING_AGENT_KEY,
731
1479
  name: "Kimi K2.7 Coding",
732
- provider: "ollama-cloud",
1480
+ provider: "nolo",
733
1481
  model: "kimi-k2.7-code",
734
1482
  apiSource: "platform",
735
1483
  useServerProxy: true,
736
1484
  rawRecord: {
737
1485
  dbKey: PUBLIC_KIMI_K27_CODING_AGENT_KEY,
738
1486
  isPublic: true,
739
- provider: "ollama-cloud",
1487
+ provider: "nolo",
740
1488
  model: "kimi-k2.7-code",
741
1489
  apiSource: "platform",
742
1490
  useServerProxy: true
@@ -1041,12 +1789,110 @@ var LOCAL_SERVER_WEB_TOOL_NAMES = ["fetchWebpage", "exa_search"];
1041
1789
  var LOCAL_SERVER_WEB_TOOL_NAME_SET = new Set(
1042
1790
  LOCAL_SERVER_WEB_TOOL_NAMES
1043
1791
  );
1044
- var REGISTRY_INJECTED_TOOL_NAMES = /* @__PURE__ */ new Set([
1045
- "callAgent",
1046
- "ui_ask_choice",
1047
- "read_x_post",
1048
- "read_xhs_profile"
1049
- ]);
1792
+
1793
+ // packages/core/fetchWebpageShaping.ts
1794
+ var FETCH_WEBPAGE_PREVIEW_LENGTH = 1200;
1795
+ var FETCH_WEBPAGE_MAX_CONTENT_LENGTH = 12 * 1024;
1796
+ var FETCH_WEBPAGE_REQUEST_HEADERS = {
1797
+ Accept: "text/markdown, text/html, application/xhtml+xml, */*",
1798
+ "User-Agent": "NoloBot/1.0 (AI Agent; +https://nolo.ai)"
1799
+ };
1800
+ function cleanHtmlForAI(html) {
1801
+ return compactWhitespace(
1802
+ html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, "").replace(/<[^>]*>/g, " ")
1803
+ );
1804
+ }
1805
+ function shapeFetchWebpageContent(args) {
1806
+ const cleanedContent = args.contentType.includes("text/markdown") ? args.content.trim() : cleanHtmlForAI(args.content);
1807
+ 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;
1808
+ 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;
1809
+ return {
1810
+ preview,
1811
+ fullContent,
1812
+ contentType: args.contentType,
1813
+ markdownTokens: args.markdownTokens ?? null
1814
+ };
1815
+ }
1816
+
1817
+ // packages/core/internalHostname.ts
1818
+ function unwrapIpv6Brackets(hostname) {
1819
+ return hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
1820
+ }
1821
+ var INTERNAL_IPV4_OR_NAME_RE = /^(localhost|127\.|10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|0\.|169\.254\.)/;
1822
+ var INTERNAL_IPV6_EXACT = /* @__PURE__ */ new Set(["::1", "::", "0:0:0:0:0:0:0:1", "0:0:0:0:0:0:0:0"]);
1823
+ var INTERNAL_IPV6_PREFIX_RE = /^(f[cd][0-9a-f]{0,2}:|fe[89ab][0-9a-f]:)/;
1824
+ function isIpv4MappedInternal(host) {
1825
+ const mapped = host.match(/^::ffff:(.+)$/);
1826
+ if (!mapped?.[1]) return false;
1827
+ const rest = mapped[1];
1828
+ if (INTERNAL_IPV4_OR_NAME_RE.test(rest)) return true;
1829
+ const hex = rest.match(/^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
1830
+ if (!hex) return false;
1831
+ const high = Number.parseInt(hex[1] ?? "", 16);
1832
+ if (!Number.isFinite(high)) return false;
1833
+ const firstOctet = high >> 8 & 255;
1834
+ const secondOctet = high & 255;
1835
+ if (firstOctet === 127 || firstOctet === 10 || firstOctet === 0) return true;
1836
+ if (firstOctet === 192 && secondOctet === 168) return true;
1837
+ if (firstOctet === 169 && secondOctet === 254) return true;
1838
+ if (firstOctet === 172 && secondOctet >= 16 && secondOctet <= 31) return true;
1839
+ return false;
1840
+ }
1841
+ function isNumericInternalIpv4(host) {
1842
+ if (!/^\d+$/.test(host)) return false;
1843
+ const value = Number(host);
1844
+ if (!Number.isInteger(value) || value < 0 || value > 4294967295) return false;
1845
+ const firstOctet = value >>> 24 & 255;
1846
+ const secondOctet = value >>> 16 & 255;
1847
+ if (firstOctet === 127 || firstOctet === 10 || firstOctet === 0) return true;
1848
+ if (firstOctet === 192 && secondOctet === 168) return true;
1849
+ if (firstOctet === 169 && secondOctet === 254) return true;
1850
+ if (firstOctet === 172 && secondOctet >= 16 && secondOctet <= 31) return true;
1851
+ return false;
1852
+ }
1853
+ function isInternalHostname(hostname) {
1854
+ const host = unwrapIpv6Brackets(hostname.trim().toLowerCase()).replace(/\.$/, "");
1855
+ if (!host) return true;
1856
+ if (INTERNAL_IPV4_OR_NAME_RE.test(host)) return true;
1857
+ if (INTERNAL_IPV6_EXACT.has(host)) return true;
1858
+ if (INTERNAL_IPV6_PREFIX_RE.test(host)) return true;
1859
+ if (isIpv4MappedInternal(host)) return true;
1860
+ if (isNumericInternalIpv4(host)) return true;
1861
+ return false;
1862
+ }
1863
+
1864
+ // packages/cli/client/fetchWebpageContent.ts
1865
+ function classifyFetchWebpageUrl(rawUrl) {
1866
+ if (!rawUrl || typeof rawUrl !== "string") {
1867
+ return { kind: "reject", error: "URL \u53C2\u6570\u662F\u5FC5\u9700\u7684" };
1868
+ }
1869
+ let parsed;
1870
+ try {
1871
+ parsed = new URL(rawUrl);
1872
+ } catch {
1873
+ return { kind: "reject", error: "\u65E0\u6548\u7684 URL \u683C\u5F0F" };
1874
+ }
1875
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
1876
+ return { kind: "reject", error: "\u4EC5\u652F\u6301 HTTP/HTTPS \u534F\u8BAE" };
1877
+ }
1878
+ if (isInternalHostname(parsed.hostname)) {
1879
+ return { kind: "local", url: rawUrl, parsed };
1880
+ }
1881
+ return { kind: "remote", url: rawUrl, parsed };
1882
+ }
1883
+ async function fetchWebpageLocally(args) {
1884
+ const response = await args.fetchImpl(args.url, {
1885
+ headers: { ...FETCH_WEBPAGE_REQUEST_HEADERS }
1886
+ });
1887
+ const contentType = response.headers.get("content-type") || "";
1888
+ const content = await response.text();
1889
+ const shaped = shapeFetchWebpageContent({
1890
+ content,
1891
+ contentType,
1892
+ markdownTokens: response.headers.get("x-markdown-tokens")
1893
+ });
1894
+ return JSON.stringify(shaped);
1895
+ }
1050
1896
 
1051
1897
  // packages/cli/client/cliServerPlatformToolExecutors.ts
1052
1898
  function buildServerPlatformToolExecutors(args) {
@@ -1116,8 +1962,39 @@ function buildServerPlatformToolExecutors(args) {
1116
1962
  toolName,
1117
1963
  async (call) => {
1118
1964
  const parsed = parseNoloWorkspaceToolArguments(call.arguments);
1119
- const path = toolName === "fetchWebpage" ? "/api/fetch-webpage" : "/api/exa-search";
1120
- const body = toolName === "fetchWebpage" ? { url: parsed.url } : {
1965
+ if (toolName === "fetchWebpage") {
1966
+ const route = classifyFetchWebpageUrl(parsed.url);
1967
+ if (route.kind === "reject") {
1968
+ throw new Error(route.error);
1969
+ }
1970
+ if (route.kind === "local") {
1971
+ const content3 = await fetchWebpageLocally({
1972
+ url: route.url,
1973
+ fetchImpl: args.fetchImpl
1974
+ });
1975
+ return {
1976
+ content: content3,
1977
+ metadata: {
1978
+ serverPlatformTool: true,
1979
+ webTool: toolName,
1980
+ url: parsed.url,
1981
+ localFetch: true
1982
+ }
1983
+ };
1984
+ }
1985
+ const content2 = await postServer("/api/fetch-webpage", {
1986
+ url: route.url
1987
+ });
1988
+ return {
1989
+ content: content2,
1990
+ metadata: {
1991
+ serverPlatformTool: true,
1992
+ webTool: toolName,
1993
+ url: parsed.url
1994
+ }
1995
+ };
1996
+ }
1997
+ const body = {
1121
1998
  query: parsed.query,
1122
1999
  numResults: parsed.numResults ?? 5,
1123
2000
  useAutoprompt: parsed.useAutoprompt ?? true,
@@ -1127,13 +2004,12 @@ function buildServerPlatformToolExecutors(args) {
1127
2004
  // conversion so CLI proxy results match web behavior.
1128
2005
  contents: parsed.includeContent !== false ? { text: true } : void 0
1129
2006
  };
1130
- const content = await postServer(path, body);
2007
+ const content = await postServer("/api/exa-search", body);
1131
2008
  return {
1132
2009
  content,
1133
2010
  metadata: {
1134
2011
  serverPlatformTool: true,
1135
- webTool: toolName,
1136
- ...toolName === "fetchWebpage" || toolName === "fetch_webpage" ? { url: parsed.url } : {}
2012
+ webTool: toolName
1137
2013
  }
1138
2014
  };
1139
2015
  }
@@ -1142,7 +2018,201 @@ function buildServerPlatformToolExecutors(args) {
1142
2018
  return { ...tableExecutors, ...webExecutors };
1143
2019
  }
1144
2020
 
2021
+ // packages/cli/client/cliAgentRunToolExecutors.ts
2022
+ import { existsSync, readFileSync } from "node:fs";
2023
+ var noopOutput = { write: () => {
2024
+ } };
2025
+ var parseCallArgs = (call) => {
2026
+ try {
2027
+ return JSON.parse(call?.arguments || "{}");
2028
+ } catch {
2029
+ return {};
2030
+ }
2031
+ };
2032
+ var resolveFs = (deps) => deps.fs ?? { existsSync, readFileSync };
2033
+ var tailFile = (logPath, tailLines, fs) => {
2034
+ if (!fs.existsSync(logPath)) return void 0;
2035
+ try {
2036
+ const content = fs.readFileSync(logPath, "utf8");
2037
+ const lines = String(content).split(/\r?\n/);
2038
+ if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
2039
+ return lines.slice(Math.max(0, lines.length - tailLines)).join("\n");
2040
+ } catch {
2041
+ return void 0;
2042
+ }
2043
+ };
2044
+ function createCliStartAgentRunExecutor(deps = {}) {
2045
+ return async (call) => {
2046
+ const args = parseCallArgs(call);
2047
+ const agentKey = typeof args.agentKey === "string" ? args.agentKey.trim() : "";
2048
+ const task = typeof args.task === "string" ? args.task.trim() : "";
2049
+ if (!agentKey) throw new Error("startAgentRun: \u7F3A\u5C11 agentKey \u53C2\u6570\u3002");
2050
+ if (!task) throw new Error("startAgentRun: \u7F3A\u5C11\u6709\u6548\u7684 task \u6587\u672C\u63CF\u8FF0\u3002");
2051
+ const message = typeof args.input === "undefined" ? task : `${task}
2052
+
2053
+ --- \u9644\u52A0\u8F93\u5165 ---
2054
+ ${JSON.stringify(args.input)}`;
2055
+ const rawArgs = ["--agent", agentKey, "--msg-file", "PLACEHOLDER", "--bg"];
2056
+ const agentName = typeof args.agentName === "string" && args.agentName.trim() ? args.agentName.trim() : typeof args.name === "string" && args.name.trim() ? args.name.trim() : void 0;
2057
+ const { runId } = await spawnLocalBackgroundRun(
2058
+ {
2059
+ rawArgs,
2060
+ commandPath: ["agent", "run"],
2061
+ cliEntrypointPath: deps.cliEntrypoint,
2062
+ agentKey,
2063
+ ...agentName ? { agentName } : {},
2064
+ cwd: deps.cwd ?? process.cwd(),
2065
+ message,
2066
+ output: noopOutput
2067
+ },
2068
+ deps
2069
+ );
2070
+ const displayName = agentName ?? "agent";
2071
+ const labels = agentRunCardLabels();
2072
+ return {
2073
+ content: JSON.stringify({
2074
+ runId,
2075
+ status: "running",
2076
+ ...agentName ? { agentName } : {}
2077
+ }),
2078
+ metadata: {
2079
+ displayData: formatStartRunCard(displayName, "running", labels)
2080
+ }
2081
+ };
2082
+ };
2083
+ }
2084
+ function createCliControlAgentRunExecutor(deps = {}) {
2085
+ return async (call) => {
2086
+ const args = parseCallArgs(call);
2087
+ const action = typeof args.action === "string" ? args.action : "";
2088
+ const tailLines = typeof args.tailLines === "number" ? args.tailLines : 0;
2089
+ if (action === "list") {
2090
+ const records = listRunRecords(deps);
2091
+ const runs = records.map((record2) => {
2092
+ const reconciled = checkStaleRun(record2.runId, deps) ?? record2;
2093
+ return {
2094
+ runId: reconciled.runId,
2095
+ status: reconciled.status,
2096
+ agentKey: reconciled.agentKey,
2097
+ ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
2098
+ pid: reconciled.pid ?? null,
2099
+ startedAt: reconciled.startedAt
2100
+ };
2101
+ });
2102
+ const labels2 = agentRunCardLabels();
2103
+ return {
2104
+ content: JSON.stringify({ runs, count: runs.length }),
2105
+ metadata: {
2106
+ displayData: formatListRunsCard(runs, labels2)
2107
+ }
2108
+ };
2109
+ }
2110
+ if (action !== "status" && action !== "stop") {
2111
+ throw new Error(`controlAgentRun: \u672A\u77E5 action "${action}"\u3002`);
2112
+ }
2113
+ if (!args.runId) throw new Error(`controlAgentRun(action:"${action}"): \u7F3A\u5C11 runId\u3002`);
2114
+ const record = findRunRecord(String(args.runId), deps);
2115
+ if (!record) {
2116
+ const labels2 = agentRunCardLabels();
2117
+ return {
2118
+ content: JSON.stringify({ runId: args.runId, found: false }),
2119
+ metadata: { displayData: formatNotFoundRunCard(labels2) }
2120
+ };
2121
+ }
2122
+ if (action === "status") {
2123
+ const reconciled = checkStaleRun(record.runId, deps) ?? record;
2124
+ const logTail = tailLines > 0 ? tailFile(record.logPath, tailLines, resolveFs(deps)) : void 0;
2125
+ const name = reconciled.agentName || "agent";
2126
+ const logLines = logTail ? logTail.split("\n") : void 0;
2127
+ const labels2 = agentRunCardLabels();
2128
+ return {
2129
+ content: JSON.stringify({
2130
+ runId: reconciled.runId,
2131
+ found: true,
2132
+ status: reconciled.status,
2133
+ pid: reconciled.pid ?? null,
2134
+ agentKey: reconciled.agentKey,
2135
+ ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
2136
+ startedAt: reconciled.startedAt,
2137
+ endedAt: reconciled.endedAt ?? null,
2138
+ exitCode: reconciled.exitCode ?? null,
2139
+ ...logTail !== void 0 ? { logTail } : {},
2140
+ ...logLines ? { logLines } : {}
2141
+ }),
2142
+ metadata: {
2143
+ displayData: formatStatusRunCard(name, reconciled.status, { logLines, labels: labels2 })
2144
+ }
2145
+ };
2146
+ }
2147
+ if (typeof record.pid === "number") {
2148
+ try {
2149
+ (deps.kill ?? ((pid, signal) => process.kill(pid, signal)))(
2150
+ record.pid,
2151
+ "SIGTERM"
2152
+ );
2153
+ } catch {
2154
+ }
2155
+ }
2156
+ finalizeRunRecord(record.runId, { status: "killed" }, deps);
2157
+ const labels = agentRunCardLabels();
2158
+ return {
2159
+ content: JSON.stringify({ runId: record.runId, found: true, status: "killed" }),
2160
+ metadata: { displayData: formatStopRunCard("killed", labels) }
2161
+ };
2162
+ };
2163
+ }
2164
+
1145
2165
  // packages/cli/client/cliLocalToolExecutors.ts
2166
+ var MAX_PASTED_TEXT_LINES_PER_READ = 200;
2167
+ function createReadPastedTextExecutor(store) {
2168
+ return async (call) => {
2169
+ let parsed = {};
2170
+ try {
2171
+ const value = JSON.parse(call.arguments || "{}");
2172
+ if (value && typeof value === "object") parsed = value;
2173
+ } catch {
2174
+ return {
2175
+ content: "readPastedText requires a JSON object with pasteId.",
2176
+ metadata: { error: true, code: "invalid_arguments" }
2177
+ };
2178
+ }
2179
+ const pasteId = Number(parsed.pasteId);
2180
+ if (!Number.isInteger(pasteId) || pasteId < 1) {
2181
+ return {
2182
+ content: "readPastedText requires a positive integer pasteId.",
2183
+ metadata: { error: true, code: "invalid_paste_id" }
2184
+ };
2185
+ }
2186
+ const text = store.items.get(pasteId);
2187
+ if (text === void 0) {
2188
+ return {
2189
+ content: `pasted text #${pasteId} is no longer available in this TUI turn.`,
2190
+ metadata: { error: true, code: "paste_not_found", pasteId }
2191
+ };
2192
+ }
2193
+ const lines = text.split("\n");
2194
+ const requestedStart = Number(parsed.startLine);
2195
+ const requestedEnd = Number(parsed.endLine);
2196
+ const startLine = Number.isInteger(requestedStart) && requestedStart > 0 ? Math.min(requestedStart, lines.length) : 1;
2197
+ const endLine = Math.min(
2198
+ lines.length,
2199
+ Number.isInteger(requestedEnd) && requestedEnd >= startLine ? requestedEnd : startLine + MAX_PASTED_TEXT_LINES_PER_READ - 1,
2200
+ startLine + MAX_PASTED_TEXT_LINES_PER_READ - 1
2201
+ );
2202
+ return {
2203
+ content: lines.slice(startLine - 1, endLine).join("\n"),
2204
+ metadata: {
2205
+ pasteId,
2206
+ startLine,
2207
+ endLine,
2208
+ totalLines: lines.length,
2209
+ totalChars: text.length,
2210
+ truncated: endLine < lines.length,
2211
+ source: "tui-paste-store"
2212
+ }
2213
+ };
2214
+ };
2215
+ }
1146
2216
  function buildCliWorkspaceToolExecutors(args) {
1147
2217
  return buildNoloWorkspaceCliToolExecutors({
1148
2218
  cliEntrypoint: args.cliEntrypoint ?? process.argv[1] ?? "",
@@ -1166,6 +2236,10 @@ function buildLocalToolExecutors(args) {
1166
2236
  env: args.env,
1167
2237
  cliEntrypoint: args.cliEntrypoint
1168
2238
  }),
2239
+ // loadSkill resolves SKILL.md from the agent's workspace root (local-fs,
2240
+ // no `nolo` CLI subcommand), so it is wired here instead of inside
2241
+ // buildCliWorkspaceToolExecutors.
2242
+ loadSkill: buildLoadSkillExecutor({ cwd: args.workspaceRoot }),
1169
2243
  read_x_post: async (call) => {
1170
2244
  const parsedArgs = (() => {
1171
2245
  try {
@@ -1292,6 +2366,17 @@ function buildLocalToolExecutors(args) {
1292
2366
  metadata: { uiAskChoice: true }
1293
2367
  };
1294
2368
  },
2369
+ // agent-orchestration 能力包:startAgentRun / controlAgentRun 本地 --bg 执行器
2370
+ // (复用 ~/.nolo/runs/ 注册表,MED-1 修复)。
2371
+ startAgentRun: createCliStartAgentRunExecutor({
2372
+ env: args.env,
2373
+ cliEntrypoint: args.cliEntrypoint,
2374
+ cwd: args.workspaceRoot
2375
+ }),
2376
+ controlAgentRun: createCliControlAgentRunExecutor({
2377
+ env: args.env
2378
+ }),
2379
+ ...args.pastedTextStore ? { readPastedText: createReadPastedTextExecutor(args.pastedTextStore) } : {},
1295
2380
  ...args.localToolExecutors ?? {}
1296
2381
  };
1297
2382
  }
@@ -3896,11 +4981,11 @@ function unescapeBytesDefaultValue(str) {
3896
4981
  case "6":
3897
4982
  case "7": {
3898
4983
  const s = input.c;
3899
- const t = input.take(2);
3900
- if (t === false) {
4984
+ const t2 = input.take(2);
4985
+ if (t2 === false) {
3901
4986
  return false;
3902
4987
  }
3903
- const n = parseInt(s + t, 8);
4988
+ const n = parseInt(s + t2, 8);
3904
4989
  if (Number.isNaN(n)) {
3905
4990
  return false;
3906
4991
  }
@@ -3909,11 +4994,11 @@ function unescapeBytesDefaultValue(str) {
3909
4994
  }
3910
4995
  case "x": {
3911
4996
  const s = input.c;
3912
- const t = input.take(2);
3913
- if (t === false) {
4997
+ const t2 = input.take(2);
4998
+ if (t2 === false) {
3914
4999
  return false;
3915
5000
  }
3916
- const n = parseInt(s + t, 16);
5001
+ const n = parseInt(s + t2, 16);
3917
5002
  if (Number.isNaN(n)) {
3918
5003
  return false;
3919
5004
  }
@@ -3922,11 +5007,11 @@ function unescapeBytesDefaultValue(str) {
3922
5007
  }
3923
5008
  case "u": {
3924
5009
  const s = input.c;
3925
- const t = input.take(4);
3926
- if (t === false) {
5010
+ const t2 = input.take(4);
5011
+ if (t2 === false) {
3927
5012
  return false;
3928
5013
  }
3929
- const n = parseInt(s + t, 16);
5014
+ const n = parseInt(s + t2, 16);
3930
5015
  if (Number.isNaN(n)) {
3931
5016
  return false;
3932
5017
  }
@@ -3938,11 +5023,11 @@ function unescapeBytesDefaultValue(str) {
3938
5023
  }
3939
5024
  case "U": {
3940
5025
  const s = input.c;
3941
- const t = input.take(8);
3942
- if (t === false) {
5026
+ const t2 = input.take(8);
5027
+ if (t2 === false) {
3943
5028
  return false;
3944
5029
  }
3945
- const tc = protoInt64.uEnc(s + t);
5030
+ const tc = protoInt64.uEnc(s + t2);
3946
5031
  const chunk = new Uint8Array(8);
3947
5032
  const view = new DataView(chunk.buffer);
3948
5033
  view.setInt32(0, tc.lo, true);
@@ -4081,24 +5166,24 @@ function createBaseRegistry() {
4081
5166
  return files.get(fileName);
4082
5167
  },
4083
5168
  getMessage(typeName) {
4084
- const t = types.get(typeName);
4085
- return (t === null || t === void 0 ? void 0 : t.kind) == "message" ? t : void 0;
5169
+ const t2 = types.get(typeName);
5170
+ return (t2 === null || t2 === void 0 ? void 0 : t2.kind) == "message" ? t2 : void 0;
4086
5171
  },
4087
5172
  getEnum(typeName) {
4088
- const t = types.get(typeName);
4089
- return (t === null || t === void 0 ? void 0 : t.kind) == "enum" ? t : void 0;
5173
+ const t2 = types.get(typeName);
5174
+ return (t2 === null || t2 === void 0 ? void 0 : t2.kind) == "enum" ? t2 : void 0;
4090
5175
  },
4091
5176
  getExtension(typeName) {
4092
- const t = types.get(typeName);
4093
- return (t === null || t === void 0 ? void 0 : t.kind) == "extension" ? t : void 0;
5177
+ const t2 = types.get(typeName);
5178
+ return (t2 === null || t2 === void 0 ? void 0 : t2.kind) == "extension" ? t2 : void 0;
4094
5179
  },
4095
5180
  getExtensionFor(extendee, no) {
4096
5181
  var _a;
4097
5182
  return (_a = extendees.get(extendee.typeName)) === null || _a === void 0 ? void 0 : _a.get(no);
4098
5183
  },
4099
5184
  getService(typeName) {
4100
- const t = types.get(typeName);
4101
- return (t === null || t === void 0 ? void 0 : t.kind) == "service" ? t : void 0;
5185
+ const t2 = types.get(typeName);
5186
+ return (t2 === null || t2 === void 0 ? void 0 : t2.kind) == "service" ? t2 : void 0;
4102
5187
  }
4103
5188
  };
4104
5189
  }
@@ -8065,9 +9150,41 @@ function buildOpenAiTools(args) {
8065
9150
  const toolNameSet = new Set(args.toolNames ?? []);
8066
9151
  const callAgentTools = toolNameSet.has("callAgent") ? prepareTools(["callAgent"]) : [];
8067
9152
  const uiAskChoiceTools = toolNameSet.has("ui_ask_choice") ? prepareTools(["ui_ask_choice"]) : [];
9153
+ const readPastedTextTools = toolNameSet.has("readPastedText") ? [
9154
+ {
9155
+ type: "function",
9156
+ function: {
9157
+ name: "readPastedText",
9158
+ description: "Read a chunk of a large TUI paste by pasteId. Use startLine and endLine to page through the full content.",
9159
+ parameters: {
9160
+ type: "object",
9161
+ properties: {
9162
+ pasteId: {
9163
+ type: "integer",
9164
+ minimum: 1,
9165
+ description: "The paste id from the user message reference."
9166
+ },
9167
+ startLine: {
9168
+ type: "integer",
9169
+ minimum: 1,
9170
+ description: "First 1-based line to return; defaults to 1."
9171
+ },
9172
+ endLine: {
9173
+ type: "integer",
9174
+ minimum: 1,
9175
+ description: "Last 1-based line to return; each call is bounded to a 200-line chunk."
9176
+ }
9177
+ },
9178
+ required: ["pasteId"],
9179
+ additionalProperties: false
9180
+ }
9181
+ }
9182
+ }
9183
+ ] : [];
8068
9184
  return [
8069
9185
  ...callAgentTools,
8070
9186
  ...uiAskChoiceTools,
9187
+ ...readPastedTextTools,
8071
9188
  ...buildLocalWorkspaceOpenAiTools({
8072
9189
  toolNames: toolset.toolNames,
8073
9190
  exposeShellTools: toolset.exposeShellTools,
@@ -8083,7 +9200,13 @@ function buildOpenAiTools(args) {
8083
9200
  searchFilesParameterVariant: resolveSearchFilesParameterVariant(args.env)
8084
9201
  }),
8085
9202
  ...buildServerPlatformOpenAiTools({ toolNames: args.toolNames }),
8086
- ...buildNoloWorkspaceOpenAiTools({ toolNames: args.toolNames })
9203
+ ...buildNoloWorkspaceOpenAiTools({ toolNames: args.toolNames }),
9204
+ // startAgentRun/controlAgentRun:CLI 本地 --bg 执行器已就绪(MED-1 修复,
9205
+ // cliAgentRunToolExecutors),只要 agent 声明(agent-orchestration 包展开)
9206
+ // 就注入 schema。
9207
+ ...prepareTools(
9208
+ ["startAgentRun", "controlAgentRun"].filter((name) => toolNameSet.has(name))
9209
+ )
8087
9210
  ];
8088
9211
  }
8089
9212
  var CLI_DEFAULT_TOOLS = ["exa_search", "fetchWebpage"];
@@ -8098,9 +9221,26 @@ function resolveCliEffectiveEnabledPacks(args) {
8098
9221
  }
8099
9222
  const base = args.enabledPacks ?? [];
8100
9223
  if (base.length === 0) {
8101
- return ["code"];
9224
+ return ["code", "agent-orchestration", "skills"];
8102
9225
  }
8103
- return base;
9226
+ const withOrchestration = base.includes("agent-orchestration") ? base : [...base, "agent-orchestration"];
9227
+ return withOrchestration.includes("skills") ? withOrchestration : [...withOrchestration, "skills"];
9228
+ }
9229
+ function withRuntimeEnabledPacksAndPrompt(config) {
9230
+ const rawRecord = config.rawRecord ?? {};
9231
+ const enabledPacks = config.enabledPacks ?? rawRecord.enabledPacks;
9232
+ const prompt = appendEnabledPackPromptPatches(
9233
+ config.prompt,
9234
+ enabledPacks
9235
+ );
9236
+ if (prompt === config.prompt && !enabledPacks?.length) {
9237
+ return config;
9238
+ }
9239
+ return {
9240
+ ...config,
9241
+ ...enabledPacks?.length ? { enabledPacks } : {},
9242
+ ...prompt ? { prompt } : {}
9243
+ };
8104
9244
  }
8105
9245
  function resolveCliRequestedToolNames(agentConfig, env) {
8106
9246
  const declaredOnly = shouldUseDeclaredOnlyLocalWorkspaceTools(env);
@@ -8127,8 +9267,13 @@ function resolveCliRequestedToolNames(agentConfig, env) {
8127
9267
  agentConfig?.disabledTools
8128
9268
  );
8129
9269
  }
8130
- function resolveProviderOpenAiToolBundle(agentConfig, env, buildTools = buildOpenAiTools) {
8131
- const requestedToolNames = resolveCliRequestedToolNames(agentConfig, env);
9270
+ function resolveProviderOpenAiToolBundle(agentConfig, env, buildTools = buildOpenAiTools, additionalToolNames = []) {
9271
+ const requestedToolNames = [
9272
+ .../* @__PURE__ */ new Set([
9273
+ ...resolveCliRequestedToolNames(agentConfig, env),
9274
+ ...additionalToolNames
9275
+ ])
9276
+ ];
8132
9277
  const tools = buildTools({
8133
9278
  agentKey: agentConfig.key,
8134
9279
  toolNames: requestedToolNames,
@@ -8147,25 +9292,17 @@ function buildLocalWorkspaceToolsetForEnv(args) {
8147
9292
  return toolset;
8148
9293
  }
8149
9294
  function buildLocalPolicyToolNames(args) {
9295
+ const buildTools = args.buildTools ?? buildOpenAiTools;
8150
9296
  return [
8151
- ...buildLocalWorkspacePolicyToolNames({
8152
- declaredToolNames: args.toolNames,
8153
- exposeShellTools: true,
8154
- useDeclaredToolNamesOnly: shouldUseDeclaredOnlyLocalWorkspaceTools(
8155
- args.env
9297
+ ...new Set(
9298
+ summarizeOpenAiToolNames(
9299
+ buildTools({
9300
+ agentKey: args.agentKey,
9301
+ toolNames: args.toolNames,
9302
+ env: args.env
9303
+ })
8156
9304
  )
8157
- }),
8158
- ...(() => {
8159
- const extra = [];
8160
- const names = args.toolNames ?? [];
8161
- for (const name of names) {
8162
- if (REGISTRY_INJECTED_TOOL_NAMES.has(name)) extra.push(name);
8163
- if (LOCAL_SERVER_TABLE_TOOL_NAME_SET.has(name)) extra.push(name);
8164
- if (LOCAL_SERVER_WEB_TOOL_NAME_SET.has(name)) extra.push(name);
8165
- }
8166
- return extra;
8167
- })(),
8168
- ...filterNoloWorkspaceToolNames(args.toolNames)
9305
+ )
8169
9306
  ];
8170
9307
  }
8171
9308
  function buildServerPlatformOpenAiTools(args) {
@@ -8415,6 +9552,33 @@ function createLocalDialogTitleGenerator(deps, ctx) {
8415
9552
  return result.source === "llm" ? result.title : null;
8416
9553
  };
8417
9554
  }
9555
+ async function writeLocalTokenRecord(args) {
9556
+ const rawUsage = args.input.result.usage;
9557
+ if (!rawUsage || typeof rawUsage !== "object" || Object.keys(rawUsage).length === 0) {
9558
+ return;
9559
+ }
9560
+ const timestamp = args.now();
9561
+ const prepared = prepareTokenUsageData({
9562
+ rawUsage,
9563
+ agentConfig: {
9564
+ model: args.input.result.model || "unknown",
9565
+ provider: args.input.result.provider,
9566
+ apiSource: "cli"
9567
+ },
9568
+ userId: args.userId,
9569
+ agentId: args.input.agentKey,
9570
+ dialogId: args.dialogId,
9571
+ timestamp,
9572
+ entry_path: "cli-local"
9573
+ });
9574
+ const recordKey = createTokenKey.record(args.userId, timestamp);
9575
+ const tokenRecord = {
9576
+ id: args.createId(),
9577
+ type: "token",
9578
+ ...prepared.tokenData
9579
+ };
9580
+ await args.store.write(recordKey, tokenRecord);
9581
+ }
8418
9582
  async function writeDialog(args) {
8419
9583
  let existingDialog = null;
8420
9584
  if (args.input.continueDialogId) {
@@ -8448,6 +9612,22 @@ async function writeDialog(args) {
8448
9612
  ...titleOverride ? { titleOverride } : {}
8449
9613
  });
8450
9614
  await args.store.batch(plan.ops);
9615
+ try {
9616
+ await writeLocalTokenRecord({
9617
+ store: args.store,
9618
+ input: args.input,
9619
+ userId: args.userId,
9620
+ dialogId: plan.dialogId,
9621
+ now: args.now,
9622
+ createId: args.createId,
9623
+ output: args.output
9624
+ });
9625
+ } catch (error) {
9626
+ args.output?.write(
9627
+ `[nolo] Token usage record write failed (non-fatal): ${toErrorMessage(error)}
9628
+ `
9629
+ );
9630
+ }
8451
9631
  const hasSubjectRefs = localTurnHasSubjectRefs(args.input);
8452
9632
  const isLocalUser = args.userId === "local";
8453
9633
  if (!isLocalUser) {
@@ -8481,6 +9661,42 @@ async function writeDialog(args) {
8481
9661
  }
8482
9662
  return { dialogId: plan.dialogId };
8483
9663
  }
9664
+ function resolveCliDialogRecordKey(userId, dialogId) {
9665
+ if (dialogId.startsWith("dialog-") && !dialogId.includes("-msg-")) {
9666
+ return dialogId;
9667
+ }
9668
+ return `dialog-${userId}-${dialogId}`;
9669
+ }
9670
+ async function loadCliDialogSummary(args) {
9671
+ const dialogKey = resolveCliDialogRecordKey(args.userId, args.dialogId);
9672
+ const record = await args.store.read(dialogKey);
9673
+ if (!record || typeof record !== "object") return null;
9674
+ const summary = typeof record.summary === "string" ? record.summary.trim() : "";
9675
+ if (!summary) return null;
9676
+ const summarizedBeforeId = record.summarizedBeforeId;
9677
+ return {
9678
+ summary,
9679
+ ...typeof summarizedBeforeId === "string" && summarizedBeforeId ? { summarizedBeforeId } : {}
9680
+ };
9681
+ }
9682
+ async function saveCliDialogSummary(args) {
9683
+ const dialogKey = resolveCliDialogRecordKey(args.userId, args.dialogId);
9684
+ const existing = await args.store.read(dialogKey) ?? {};
9685
+ const bareId = typeof existing.id === "string" && existing.id ? existing.id : args.dialogId.startsWith("dialog-") ? args.dialogId.slice(args.dialogId.lastIndexOf("-") + 1) : args.dialogId;
9686
+ const compressionCount = typeof existing.compressionCount === "number" ? existing.compressionCount + 1 : 1;
9687
+ await args.store.write(dialogKey, {
9688
+ ...existing,
9689
+ id: bareId,
9690
+ dbKey: dialogKey,
9691
+ type: "dialog",
9692
+ userId: args.userId,
9693
+ summary: args.summary,
9694
+ ...args.summarizedBeforeId !== void 0 ? { summarizedBeforeId: args.summarizedBeforeId } : {},
9695
+ compressionCount,
9696
+ summaryPending: false,
9697
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
9698
+ });
9699
+ }
8484
9700
  function createCliLocalRuntimeAdapter(deps) {
8485
9701
  const now = deps.now ?? Date.now;
8486
9702
  const createId = deps.createId ?? createFallbackId;
@@ -8490,6 +9706,7 @@ function createCliLocalRuntimeAdapter(deps) {
8490
9706
  const localToolBudgets = parseLocalToolBudgets(deps.env);
8491
9707
  const localToolUsage = /* @__PURE__ */ new Map();
8492
9708
  const buildProviderOpenAiTools = deps.buildProviderOpenAiTools ?? buildOpenAiTools;
9709
+ const additionalToolNames = deps.pastedTextStore ? ["readPastedText"] : [];
8493
9710
  let activeAgentToolNames = [];
8494
9711
  const workspaceRoot = deps.cwd ?? process.cwd();
8495
9712
  let runtimeToolExecutionLimits = {};
@@ -8503,6 +9720,7 @@ function createCliLocalRuntimeAdapter(deps) {
8503
9720
  cliEntrypoint: CLI_ENTRYPOINT,
8504
9721
  ...deps.confirmDestructiveAction ? { confirmDestructiveAction: deps.confirmDestructiveAction } : {},
8505
9722
  ...deps.requestUserChoice ? { requestUserChoice: deps.requestUserChoice } : {},
9723
+ ...deps.pastedTextStore ? { pastedTextStore: deps.pastedTextStore } : {},
8506
9724
  ...runtimeToolExecutionLimits
8507
9725
  });
8508
9726
  return {
@@ -8519,7 +9737,7 @@ function createCliLocalRuntimeAdapter(deps) {
8519
9737
  agentRef,
8520
9738
  cwd: normalizeRuntimeCacheCwd(workspaceRoot)
8521
9739
  });
8522
- const cached = preparedAgentRuntimeCache.get(cacheKey);
9740
+ const cached = deps.pastedTextStore ? void 0 : preparedAgentRuntimeCache.get(cacheKey);
8523
9741
  if (cached) {
8524
9742
  activeAgentToolNames = cached.activeAgentToolNames;
8525
9743
  runtimeToolExecutionLimits = cached.runtimeToolExecutionLimits;
@@ -8532,13 +9750,15 @@ function createCliLocalRuntimeAdapter(deps) {
8532
9750
  userId
8533
9751
  });
8534
9752
  const fallbackLocalCliAgentConfig = storedAgentConfig ? null : resolveBuiltinLocalCliAgentConfig(agentRef, userId);
8535
- const agentConfig = withResolvedRuntimeToolSurface(
9753
+ const baseAgentConfig = withResolvedRuntimeToolSurface(
8536
9754
  storedAgentConfig ?? fallbackLocalCliAgentConfig,
8537
9755
  deps.env
8538
9756
  );
9757
+ const agentConfig = baseAgentConfig ? withRuntimeEnabledPacksAndPrompt(baseAgentConfig) : baseAgentConfig;
8539
9758
  const requestedToolNames = agentConfig ? resolveCliRequestedToolNames(agentConfig, deps.env) : [];
8540
9759
  activeAgentToolNames = buildLocalPolicyToolNames({
8541
- toolNames: requestedToolNames,
9760
+ agentKey: agentConfig?.key,
9761
+ toolNames: [...requestedToolNames, ...additionalToolNames],
8542
9762
  env: deps.env
8543
9763
  });
8544
9764
  runtimeToolExecutionLimits = resolveLocalWorkspaceExecutorOptionsFromPolicy(
@@ -8554,9 +9774,10 @@ function createCliLocalRuntimeAdapter(deps) {
8554
9774
  cliEntrypoint: CLI_ENTRYPOINT,
8555
9775
  ...deps.confirmDestructiveAction ? { confirmDestructiveAction: deps.confirmDestructiveAction } : {},
8556
9776
  ...deps.requestUserChoice ? { requestUserChoice: deps.requestUserChoice } : {},
9777
+ ...deps.pastedTextStore ? { pastedTextStore: deps.pastedTextStore } : {},
8557
9778
  ...runtimeToolExecutionLimits
8558
9779
  });
8559
- if (agentConfig) {
9780
+ if (agentConfig && !deps.pastedTextStore) {
8560
9781
  preparedAgentRuntimeCache.set(cacheKey, {
8561
9782
  agentConfig,
8562
9783
  activeAgentToolNames,
@@ -8570,6 +9791,18 @@ function createCliLocalRuntimeAdapter(deps) {
8570
9791
  dialogId,
8571
9792
  store: await getOrCreateSharedStore(deps)
8572
9793
  }),
9794
+ loadDialogSummary: async (dialogId) => loadCliDialogSummary({
9795
+ store: await getOrCreateSharedStore(deps),
9796
+ userId,
9797
+ dialogId
9798
+ }),
9799
+ saveDialogSummary: async (input) => saveCliDialogSummary({
9800
+ store: await getOrCreateSharedStore(deps),
9801
+ userId,
9802
+ dialogId: input.dialogId,
9803
+ summary: input.summary,
9804
+ summarizedBeforeId: input.summarizedBeforeId
9805
+ }),
8573
9806
  saveTurn: async (input) => writeDialog({
8574
9807
  store: await getOrCreateSharedStore(deps),
8575
9808
  input,
@@ -8649,7 +9882,8 @@ function createCliLocalRuntimeAdapter(deps) {
8649
9882
  const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
8650
9883
  agentConfig,
8651
9884
  deps.env,
8652
- buildProviderOpenAiTools
9885
+ buildProviderOpenAiTools,
9886
+ additionalToolNames
8653
9887
  );
8654
9888
  logLocalRuntimeDiagnostic("provider.selected", {
8655
9889
  agentKey: agentConfig.key,
@@ -8729,7 +9963,8 @@ function createCliLocalRuntimeAdapter(deps) {
8729
9963
  const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
8730
9964
  agentConfig,
8731
9965
  deps.env,
8732
- buildProviderOpenAiTools
9966
+ buildProviderOpenAiTools,
9967
+ additionalToolNames
8733
9968
  );
8734
9969
  logLocalRuntimeDiagnostic("provider.selected", {
8735
9970
  agentKey: agentConfig.key,
@@ -8794,7 +10029,8 @@ function createCliLocalRuntimeAdapter(deps) {
8794
10029
  const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
8795
10030
  agentConfig,
8796
10031
  deps.env,
8797
- buildProviderOpenAiTools
10032
+ buildProviderOpenAiTools,
10033
+ additionalToolNames
8798
10034
  );
8799
10035
  logLocalRuntimeDiagnostic("provider.selected", {
8800
10036
  agentKey: agentConfig.key,
@@ -8876,7 +10112,8 @@ function createCliLocalRuntimeAdapter(deps) {
8876
10112
  const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
8877
10113
  agentConfig,
8878
10114
  deps.env,
8879
- buildProviderOpenAiTools
10115
+ buildProviderOpenAiTools,
10116
+ additionalToolNames
8880
10117
  );
8881
10118
  return {
8882
10119
  model: providerConfig2.model,
@@ -8901,7 +10138,7 @@ function createCliLocalRuntimeAdapter(deps) {
8901
10138
  openAiToolNames: summarizeOpenAiToolNames(tools2),
8902
10139
  stream
8903
10140
  });
8904
- const res = await fetchWithTransientRetry(
10141
+ let res = await fetchWithTransientRetry(
8905
10142
  fetchImpl,
8906
10143
  request.url,
8907
10144
  {
@@ -8912,8 +10149,44 @@ function createCliLocalRuntimeAdapter(deps) {
8912
10149
  loopbackRequest
8913
10150
  }
8914
10151
  );
10152
+ let responseProviderConfig = providerConfig2;
10153
+ let firstErrorRaw;
8915
10154
  if (!res.ok) {
8916
- const raw2 = await res.text().catch(() => "");
10155
+ firstErrorRaw = await res.text().catch(() => "");
10156
+ const fallbackProviderConfig = resolveLegacyDeepSeekProxyChatFallback({
10157
+ providerConfig: providerConfig2,
10158
+ status: res.status,
10159
+ raw: firstErrorRaw
10160
+ });
10161
+ if (fallbackProviderConfig) {
10162
+ responseProviderConfig = fallbackProviderConfig;
10163
+ const fallbackRequest = buildPlatformChatCompletionRequest({
10164
+ providerConfig: fallbackProviderConfig,
10165
+ messages,
10166
+ tools: tools2,
10167
+ stream: false
10168
+ });
10169
+ logLocalRuntimeDiagnostic("provider.request.compatibility-fallback", {
10170
+ agentKey: agentConfig.key,
10171
+ provider: providerConfig2.provider,
10172
+ fromEndpoint: summarizeEndpoint(providerConfig2.endpoint) ?? null,
10173
+ toEndpoint: summarizeEndpoint(fallbackProviderConfig.endpoint) ?? null,
10174
+ reason: "legacy-proxy-responses-schema"
10175
+ });
10176
+ res = await fetchWithTransientRetry(
10177
+ fetchImpl,
10178
+ fallbackRequest.url,
10179
+ { ...fallbackRequest.init },
10180
+ {
10181
+ sleep: deps.sleep,
10182
+ loopbackRequest
10183
+ }
10184
+ );
10185
+ firstErrorRaw = void 0;
10186
+ }
10187
+ }
10188
+ if (!res.ok) {
10189
+ const raw2 = firstErrorRaw ?? await res.text().catch(() => "");
8917
10190
  const data2 = parsePlatformChatCompletionData(raw2);
8918
10191
  const rawPreview = raw2.length > 200 ? `${raw2.slice(0, 200)}\u2026(${raw2.length}b)` : raw2;
8919
10192
  const gatewayHeaders = [
@@ -8964,7 +10237,7 @@ function createCliLocalRuntimeAdapter(deps) {
8964
10237
  });
8965
10238
  const data = parsePlatformChatCompletionData(raw);
8966
10239
  return parsePlatformChatCompletionResponse({
8967
- providerConfig: providerConfig2,
10240
+ providerConfig: responseProviderConfig,
8968
10241
  data,
8969
10242
  trace: messages
8970
10243
  });
@@ -8995,7 +10268,8 @@ function createCliLocalRuntimeAdapter(deps) {
8995
10268
  const { requestedToolNames, tools } = resolveProviderOpenAiToolBundle(
8996
10269
  agentConfig,
8997
10270
  deps.env,
8998
- buildProviderOpenAiTools
10271
+ buildProviderOpenAiTools,
10272
+ additionalToolNames
8999
10273
  );
9000
10274
  return {
9001
10275
  model: providerConfig.model,
@@ -9066,6 +10340,13 @@ function createCliLocalRuntimeAdapter(deps) {
9066
10340
  export {
9067
10341
  summarizeEndpoint,
9068
10342
  isBuiltinNoloAgentRef,
10343
+ parseCliLocale,
10344
+ getCliLocale,
10345
+ setCliLocale,
10346
+ initCliLocale,
10347
+ t,
10348
+ toolLabel,
10349
+ agentRunCardLabels,
9069
10350
  clearCliLocalRuntimePreparedAgentCache,
9070
10351
  createCliCallAgentToolExecutor,
9071
10352
  createCliLocalRuntimeAdapter