nolo-cli 0.54.0-alpha.2 → 0.54.0

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 (133) hide show
  1. package/{_executeModel-ANY4SIAS.js → _executeModel-OPTKYHJA.js} +48 -42
  2. package/{action-Q4W5JPI5.js → action-ORXWW2ZG.js} +8 -8
  3. package/{addContentAction-O25HFR37.js → addContentAction-53BZ34AE.js} +8 -7
  4. package/{addDialogAgentAction-GH7AUPPB.js → addDialogAgentAction-JRYUS54Y.js} +10 -9
  5. package/{agentDeleteCommand-JWIKNWWI.js → agentDeleteCommand-FJIWU2BS.js} +30 -28
  6. package/{agentEmailCommands-PL22BEU5.js → agentEmailCommands-CE32L43B.js} +57 -52
  7. package/{agentListCommands-6NR7AQEK.js → agentListCommands-VJNKULIK.js} +42 -33
  8. package/{agentMachineCommands-TASPU6OA.js → agentMachineCommands-HCJ3WQXL.js} +30 -28
  9. package/{agentRecordCommands-Z64TA63M.js → agentRecordCommands-QFWERED4.js} +55 -50
  10. package/{agentRunCommand-4QJQLPRW.js → agentRunCommand-G3GQMUNN.js} +65 -53
  11. package/{agentRunControl-4GHHSXFZ.js → agentRunControl-INKFDXDA.js} +3 -1
  12. package/{agentRuntimeLocal-PCJJ56J2.js → agentRuntimeLocal-K327ELSL.js} +30 -26
  13. package/{agentSlice-KYLDUSNN.js → agentSlice-ODKF4J6M.js} +8 -8
  14. package/{agentSuperviseCommands-VB6BUS5H.js → agentSuperviseCommands-5AR3DKNN.js} +2 -2
  15. package/{appDeleteCommands-WLHMJAVT.js → appDeleteCommands-XUXMFDI4.js} +31 -29
  16. package/{appDeployCommands-CKON7N2E.js → appDeployCommands-37F4GPCU.js} +31 -29
  17. package/{appDeployStatusCommands-PXRLDASH.js → appDeployStatusCommands-WSPU7TUK.js} +31 -29
  18. package/{appGetCommands-RAB5RM4M.js → appGetCommands-YLOBA3EM.js} +31 -29
  19. package/{appListCommands-GU57FB62.js → appListCommands-UD62R5ME.js} +31 -29
  20. package/{authCommand-QOPOEYEK.js → authCommand-OK6HLHGS.js} +13 -13
  21. package/{authCommands-SBQVTD6V.js → authCommands-2DUIUEMT.js} +2 -2
  22. package/{chatQueueReduxAdapter-5O2WLITN.js → chatQueueReduxAdapter-TV2TUOQS.js} +26 -23
  23. package/{chunk-7CH6U3FL.js → chunk-2GRGFCF6.js} +2 -4
  24. package/{chunk-T27IEBNQ.js → chunk-2QDDKFG5.js} +74 -1
  25. package/{chunk-VULELK4T.js → chunk-2WBFJHQA.js} +4 -26
  26. package/{chunk-IKTHA3JH.js → chunk-3LKZRP7E.js} +2 -2
  27. package/{chunk-INXBNYCG.js → chunk-3Y2K5O2R.js} +64 -6
  28. package/{chunk-VRZIH5JO.js → chunk-3ZTR7ZO4.js} +1 -1
  29. package/{chunk-GV35EHNA.js → chunk-5FCIPEKT.js} +262 -96
  30. package/{chunk-RTLJUGQH.js → chunk-5UAYZEXO.js} +2 -2
  31. package/{chunk-TI5BCZCH.js → chunk-6COJEAYH.js} +32 -101
  32. package/{chunk-Y7LNKP32.js → chunk-6HDYSFLO.js} +4 -6
  33. package/chunk-6IGD47IC.js +19 -0
  34. package/chunk-6YTOJY35.js +352 -0
  35. package/{chunk-6FGXGFAH.js → chunk-75MSWWUE.js} +1 -1
  36. package/{chunk-3Z3DXZBD.js → chunk-7FAS3NEF.js} +16 -16
  37. package/{chunk-AV6KQCM5.js → chunk-7NYDJAQ7.js} +19 -14
  38. package/{chunk-CVT7L2WZ.js → chunk-A65UV3M5.js} +4 -4
  39. package/{chunk-7APQB6R6.js → chunk-AUVFJGPC.js} +3 -3
  40. package/{chunk-H4RYESI6.js → chunk-BBTN4NQD.js} +4 -4
  41. package/{chunk-757BGY6Y.js → chunk-BG7J6Y5X.js} +1 -1
  42. package/chunk-BY2FF2C4.js +526 -0
  43. package/{chunk-FA4SY4F5.js → chunk-BYEJ7K2Z.js} +1 -1
  44. package/chunk-BYXBJQAS.js +0 -0
  45. package/{chunk-3AOLVADY.js → chunk-DVINR3PL.js} +1 -1
  46. package/{chunk-UITMHBVK.js → chunk-EA5OYZVD.js} +1 -1
  47. package/{chunk-4NN3EK7H.js → chunk-EICIFHVS.js} +1 -1
  48. package/chunk-EJE33XNR.js +19059 -0
  49. package/{chunk-6SZ52ORL.js → chunk-FJHMLRDQ.js} +9 -9
  50. package/{chunk-RU5D3B22.js → chunk-GRFK2XP4.js} +2 -2
  51. package/{chunk-J3UALFHL.js → chunk-HJTAGT3W.js} +1 -1
  52. package/{chunk-WL3UOGYO.js → chunk-HPW5MNDQ.js} +38 -98
  53. package/{chunk-H2G6JXTR.js → chunk-HQUORJTM.js} +1 -1
  54. package/{chunk-OYNDYVSE.js → chunk-JON2PHYT.js} +1 -1
  55. package/{chunk-7K5VMB4Q.js → chunk-JXIP6ZWH.js} +7 -7
  56. package/{chunk-KUUTWU4I.js → chunk-K4NISKOR.js} +46 -8
  57. package/{chunk-SP3DPVBH.js → chunk-KLIBF3BY.js} +2 -2
  58. package/chunk-LRGKOI5Y.js +297 -0
  59. package/{chunk-LN3OQJGG.js → chunk-MLEZPE3U.js} +2 -2
  60. package/{chunk-FGEYVPPR.js → chunk-MYMBBB6Q.js} +5 -64
  61. package/{chunk-VRJUIUIY.js → chunk-N4JKMCY3.js} +2 -2
  62. package/{chunk-U5Z7LFZF.js → chunk-NFLA6GSU.js} +4 -4
  63. package/{chunk-SVEUG45B.js → chunk-NHRQCXIQ.js} +0 -24
  64. package/{chunk-56W233KG.js → chunk-NJUQBYFJ.js} +3 -1
  65. package/{chunk-Q24S4NDF.js → chunk-Q4XZVZPN.js} +1 -1
  66. package/{chunk-UW4INMD2.js → chunk-RHMDMTDK.js} +2 -2
  67. package/{chunk-MFI4FGHX.js → chunk-SAJSBPI2.js} +1 -1
  68. package/{chunk-WHVQA7PJ.js → chunk-SSXTSPSG.js} +27 -6
  69. package/{chunk-2BWU4ORW.js → chunk-SUEIAK5N.js} +1 -1
  70. package/{chunk-3QJTD6DO.js → chunk-SVC3GGUA.js} +5 -5
  71. package/{chunk-QDHZCAH3.js → chunk-SVDMVX4G.js} +118 -2
  72. package/{chunk-GBADO3SM.js → chunk-SWJGJMTW.js} +1 -1
  73. package/{chunk-DQLYEGP7.js → chunk-SYYUU7EV.js} +2 -2
  74. package/{chunk-U2A47SVI.js → chunk-TC6P4NDR.js} +7 -7
  75. package/{chunk-V4KZGLOI.js → chunk-TR4DXUYX.js} +1983 -447
  76. package/{chunk-BANYWEYY.js → chunk-TY3ADTX5.js} +1 -1
  77. package/chunk-UAD2WT54.js +64 -0
  78. package/{chunk-PAHILFNT.js → chunk-UGBHDMHI.js} +4 -4
  79. package/{chunk-6FQ2552G.js → chunk-UOWXD4VN.js} +799 -956
  80. package/{chunk-5WADL4O7.js → chunk-UR66XPVF.js} +3 -3
  81. package/{chunk-6BYAXNH5.js → chunk-VZMUOPYG.js} +12 -2
  82. package/{chunk-LA4IDAK7.js → chunk-WQHGJHAL.js} +440 -2981
  83. package/{chunk-GLGD2JGY.js → chunk-XIJZOCSP.js} +7 -7
  84. package/{chunk-BJLYCOZK.js → chunk-YBFJQC2M.js} +93 -776
  85. package/{chunk-MRWGHF56.js → chunk-YDH3FDFQ.js} +12 -356
  86. package/{chunk-32I5RVMY.js → chunk-YLCUU3WM.js} +3 -3
  87. package/{chunk-D3JQPONH.js → chunk-YQBXOHE6.js} +1 -1
  88. package/chunk-ZJ7UHBJS.js +89 -0
  89. package/{chunk-TNPCQNGQ.js → chunk-ZVOHVJI3.js} +4 -9
  90. package/contentThunks-KNI6VXLT.js +71 -0
  91. package/{createAgentAutomationAction-UJLNFFFC.js → createAgentAutomationAction-OK4L33KF.js} +27 -23
  92. package/{createDialogAction-TJCX6GUE.js → createDialogAction-JDSMY4AY.js} +28 -24
  93. package/{createPageAction-N3IYABHV.js → createPageAction-T7RA3HCG.js} +29 -24
  94. package/{dbSlice-D5CNGWPD.js → dbSlice-TVX6SN2T.js} +6 -6
  95. package/{deleteFile-44TUM34Y.js → deleteFile-JYKRT7C3.js} +3 -3
  96. package/{dialogCommands-35M6RBAC.js → dialogCommands-UQZYWOOV.js} +32 -30
  97. package/{dialogSlice-KO7ADD7H.js → dialogSlice-TYW2G7IL.js} +26 -23
  98. package/{docCreateCommands-VXHZWQ3P.js → docCreateCommands-OA6HZBWO.js} +34 -32
  99. package/{docDeleteCommands-4WFAJR6A.js → docDeleteCommands-KBB3YQI2.js} +31 -29
  100. package/{docReadCommands-OYREEFAR.js → docReadCommands-ZLMFVC67.js} +30 -28
  101. package/{docStore-5BU76DFK.js → docStore-2URPBVCS.js} +8 -33
  102. package/{docUpdateCommands-A7QERSME.js → docUpdateCommands-HMH5KUON.js} +34 -32
  103. package/{fetchMessages-KZQVBXKY.js → fetchMessages-DRABNDPZ.js} +3 -3
  104. package/{getPricing-HAU62AFM.js → getPricing-RFOPUWHY.js} +4 -4
  105. package/{handleSendMessageAction-OSGQJQ45.js → handleSendMessageAction-GO53TY7U.js} +28 -25
  106. package/index.js +56 -56
  107. package/{localDialogRead-NQ33HBSI.js → localDialogRead-PUQKFI73.js} +1 -1
  108. package/{machineCommands-J43U3TX5.js → machineCommands-RK6L7ZWL.js} +59 -54
  109. package/{machineWsRunDispatch-Z2Z6STXZ.js → machineWsRunDispatch-3X64DW2Z.js} +54 -49
  110. package/memberThunks-THZYZFSN.js +638 -0
  111. package/{models-4QF4BJVY.js → models-JVKUEER5.js} +2 -2
  112. package/package.json +1 -1
  113. package/{read-RGNPI5H2.js → read-K4JU4MQC.js} +3 -3
  114. package/{readDocTool-6ESWKTXD.js → readDocTool-LQGR6FUN.js} +1 -1
  115. package/{readlineWorkspace-YRPV6JPN.js → readlineWorkspace-XUFJV3RS.js} +604 -263
  116. package/{removeDialogAgentAction-JYT73FU2.js → removeDialogAgentAction-ECHCFB7N.js} +12 -11
  117. package/{runAgentClientLoop-5YM5WMAY.js → runAgentClientLoop-24GQ2AW6.js} +46 -40
  118. package/{setDialogExtraReferencesAction-D564LMYQ.js → setDialogExtraReferencesAction-KCVJNGMB.js} +9 -8
  119. package/{setPrimaryDialogAgentAction-ACY3BLYA.js → setPrimaryDialogAgentAction-VDOBOMKC.js} +12 -11
  120. package/{settingSlice-MKI3MNZJ.js → settingSlice-VR2IJSXC.js} +7 -7
  121. package/{skillDiscovery-GPUDHDTZ.js → skillDiscovery-2QTZINON.js} +3 -3
  122. package/{spaceCommands-MY26V52L.js → spaceCommands-S5YJJXL7.js} +30 -28
  123. package/{streamAgentChatTurn-XV5X5TNQ.js → streamAgentChatTurn-QHKP3ABO.js} +77 -64
  124. package/{switchDialogAgentAction-CJ5H6SAR.js → switchDialogAgentAction-5L4UP7VI.js} +10 -9
  125. package/{toolApiClient-B2MFXMEG.js → toolApiClient-53U4UDFF.js} +3 -2
  126. package/{tools-MIMELA2Y.js → tools-SSXSTC3O.js} +37 -32
  127. package/{tuiSummaryLlmCaller-XJ5BKNNS.js → tuiSummaryLlmCaller-URFJHFC5.js} +17 -15
  128. package/{updateDialogTitleAction-EIZUSWHR.js → updateDialogTitleAction-YFYAEW3T.js} +28 -24
  129. package/chunk-6BGAQ3KR.js +0 -7081
  130. package/chunk-YBV6QJKM.js +0 -441
  131. package/spaceSlice-JUIXC365.js +0 -127
  132. package/{chunk-NQ4N4IGO.js → chunk-CS6TCJ7E.js} +3 -3
  133. package/{chunk-PYKV6FSC.js → chunk-XOJRZUPF.js} +3 -3
@@ -1,6 +1,6 @@
1
1
  import {
2
- generateRunReport
3
- } from "./chunk-J3UALFHL.js";
2
+ findPotentialSecrets
3
+ } from "./chunk-S7Z2HMCN.js";
4
4
  import {
5
5
  buildLocalRunEnv,
6
6
  isFullstackCodingAgentRef,
@@ -10,6 +10,9 @@ import {
10
10
  resolveServerUrl,
11
11
  writeUsage
12
12
  } from "./chunk-LYGNQHUW.js";
13
+ import {
14
+ resolveMachineId
15
+ } from "./chunk-ESHYE7WU.js";
13
16
  import {
14
17
  agentRunCardLabels,
15
18
  createCliLocalRuntimeAdapter,
@@ -19,7 +22,12 @@ import {
19
22
  parseAgentRunEvent,
20
23
  t,
21
24
  toolLabel
22
- } from "./chunk-GV35EHNA.js";
25
+ } from "./chunk-5FCIPEKT.js";
26
+ import {
27
+ readCredentialEntry,
28
+ recordCredentialProbe,
29
+ resolveCredentialKeyWithFallback
30
+ } from "./chunk-NI2BS6UD.js";
23
31
  import {
24
32
  getReadableCliDb
25
33
  } from "./chunk-43CXXVJD.js";
@@ -27,11 +35,14 @@ import {
27
35
  normalizeAgentHandle,
28
36
  readDbRecord,
29
37
  resolveAgentRecordFromHybridStore
30
- } from "./chunk-DQLYEGP7.js";
38
+ } from "./chunk-SYYUU7EV.js";
31
39
  import {
32
40
  NOLO_PROJECT_MANAGER_AGENT_KEY,
33
41
  isLocalCliAgentKey
34
42
  } from "./chunk-EKLRRZIN.js";
43
+ import {
44
+ generateRunReport
45
+ } from "./chunk-HJTAGT3W.js";
35
46
  import {
36
47
  CliProviderQuotaError
37
48
  } from "./chunk-JDSUTNYY.js";
@@ -42,17 +53,14 @@ import {
42
53
  readRunRecord,
43
54
  resolveRunQueuePath,
44
55
  spawnLocalBackgroundRun
45
- } from "./chunk-WHVQA7PJ.js";
46
- import {
47
- resolveMachineId
48
- } from "./chunk-ESHYE7WU.js";
56
+ } from "./chunk-SSXTSPSG.js";
49
57
  import {
50
58
  applyModelLayerOverride,
51
59
  buildModelLayerOverride
52
60
  } from "./chunk-LTRXGFMS.js";
53
61
  import {
54
62
  formatAgentListCard
55
- } from "./chunk-V4KZGLOI.js";
63
+ } from "./chunk-TR4DXUYX.js";
56
64
  import {
57
65
  isTransientFetchError
58
66
  } from "./chunk-5XTOKQLW.js";
@@ -66,26 +74,25 @@ import {
66
74
  formatStartRunCard,
67
75
  formatStatusRunCard,
68
76
  formatStopRunCard,
69
- isAgentRunTerminalStatus,
70
- runShowsLogTail
77
+ isAgentRunTerminalStatus
71
78
  } from "./chunk-KXKQO4Q6.js";
72
79
  import {
73
80
  buildMemorySubjectsForAgent,
74
81
  chooseMemoryOwners,
75
82
  loadMemoryCandidatesFromDb,
76
83
  resolveAgentMemoryPolicy
77
- } from "./chunk-6SZ52ORL.js";
84
+ } from "./chunk-FJHMLRDQ.js";
78
85
  import {
79
86
  API_REPORTED_COST_MULTIPLIER,
80
87
  normalizeUsage,
81
88
  parseUiAskChoiceContent
82
- } from "./chunk-BJLYCOZK.js";
89
+ } from "./chunk-YBFJQC2M.js";
83
90
  import {
84
91
  getDefaultCliLocalRuntimeDb
85
92
  } from "./chunk-IA3A5373.js";
86
93
  import {
87
94
  buildSkillDiscoveryContextLayer
88
- } from "./chunk-2BWU4ORW.js";
95
+ } from "./chunk-SUEIAK5N.js";
89
96
  import {
90
97
  parseExternalSkillMarkdown,
91
98
  parseSkillDocProtocol
@@ -93,12 +100,11 @@ import {
93
100
  import {
94
101
  LOCAL_AGENT_CONFIG_MISSING_CODE,
95
102
  LOCAL_TURN_ABORTED_CODE,
96
- readActionGate,
97
- readCommandActionGatePayload
98
- } from "./chunk-6BGAQ3KR.js";
103
+ readActionGate
104
+ } from "./chunk-EJE33XNR.js";
99
105
  import {
100
106
  resolveAgentRuntimeConfigFromRecord
101
- } from "./chunk-CVT7L2WZ.js";
107
+ } from "./chunk-A65UV3M5.js";
102
108
  import {
103
109
  createThinkParserState,
104
110
  flushThinkParser,
@@ -107,20 +113,22 @@ import {
107
113
  import {
108
114
  resolveClientVersion,
109
115
  resolvePlatformAuthToken
110
- } from "./chunk-SP3DPVBH.js";
116
+ } from "./chunk-KLIBF3BY.js";
111
117
  import {
112
- isQuotaExhaustedError
118
+ isQuotaExhaustedError,
119
+ mergeAvailabilityDeadline,
120
+ resolveCooldownGate
113
121
  } from "./chunk-IWUMSAQF.js";
114
122
  import {
115
123
  DEFAULT_CONTEXT_WINDOW,
116
124
  getModelContextWindow
117
- } from "./chunk-KUUTWU4I.js";
125
+ } from "./chunk-K4NISKOR.js";
118
126
  import {
119
127
  clipCompactText
120
- } from "./chunk-H4RYESI6.js";
128
+ } from "./chunk-BBTN4NQD.js";
121
129
  import {
122
130
  findModelConfig
123
- } from "./chunk-QDHZCAH3.js";
131
+ } from "./chunk-SVDMVX4G.js";
124
132
  import {
125
133
  compactWhitespace
126
134
  } from "./chunk-DWLEOOGR.js";
@@ -133,7 +141,7 @@ import {
133
141
  buildMemoryUseGuidanceLayer,
134
142
  partitionScopedBlocks,
135
143
  renderTurnContextBlocksWithScope
136
- } from "./chunk-3AOLVADY.js";
144
+ } from "./chunk-DVINR3PL.js";
137
145
  import {
138
146
  readPipeText,
139
147
  spawnProcess
@@ -145,13 +153,13 @@ import {
145
153
  CLIENT_VERSION_TOO_OLD_CODE,
146
154
  NOLO_CLIENT_VERSION_HEADER,
147
155
  buildClientVersionUpgradeMessage
148
- } from "./chunk-WL3UOGYO.js";
156
+ } from "./chunk-HPW5MNDQ.js";
149
157
  import {
150
158
  parsePositiveFiniteNumberOrFallback
151
159
  } from "./chunk-Y5GCAMGP.js";
152
160
  import {
153
161
  createMemoryKey
154
- } from "./chunk-SVEUG45B.js";
162
+ } from "./chunk-NHRQCXIQ.js";
155
163
  import {
156
164
  asTrimmedLowercaseString
157
165
  } from "./chunk-QSJ3HFEF.js";
@@ -159,7 +167,7 @@ import {
159
167
  BUILTIN_NOLO_AGENT_KEY,
160
168
  BUILTIN_NOLO_AGENT_NAME,
161
169
  builtinAgentCatalogEntryById
162
- } from "./chunk-VULELK4T.js";
170
+ } from "./chunk-2WBFJHQA.js";
163
171
  import {
164
172
  parsePublicAgentId
165
173
  } from "./chunk-BJIRLHJR.js";
@@ -174,6 +182,7 @@ import {
174
182
  } from "./chunk-G3SUCT4W.js";
175
183
 
176
184
  // packages/cli/client/tokenUsage.ts
185
+ var PLATFORM_CREDIT_UNIT = "credits";
177
186
  var isUsableModelId = (model) => {
178
187
  const raw = model?.trim();
179
188
  return Boolean(raw) && raw !== "-" && raw !== "auto";
@@ -245,7 +254,7 @@ function buildTurnTokenUsage(usage, model) {
245
254
  const contextWindow = resolveContextWindow(model);
246
255
  const remaining = contextWindow && parsed.input > 0 ? Math.max(0, contextWindow - parsed.input) : void 0;
247
256
  const rawCost = typeof usage?.cost === "number" ? usage.cost : void 0;
248
- const isPlatformBilled = usage?.billing_unit === "credits";
257
+ const isPlatformBilled = usage?.billing_unit === PLATFORM_CREDIT_UNIT;
249
258
  const credits = rawCost !== void 0 && rawCost > 0 ? isPlatformBilled ? rawCost : rawCost * API_REPORTED_COST_MULTIPLIER : void 0;
250
259
  return {
251
260
  ...parsed,
@@ -254,6 +263,31 @@ function buildTurnTokenUsage(usage, model) {
254
263
  ...credits !== void 0 ? { credits } : {}
255
264
  };
256
265
  }
266
+ function sumPlatformCredits(records) {
267
+ if (!records?.length) return void 0;
268
+ let total = 0;
269
+ let sawPlatformCall = false;
270
+ for (const record of records) {
271
+ const credits = platformCreditsFromUsage(record?.usage);
272
+ if (credits === void 0) continue;
273
+ sawPlatformCall = true;
274
+ total += credits;
275
+ }
276
+ return sawPlatformCall ? total : void 0;
277
+ }
278
+ function platformCreditsFromUsage(usage) {
279
+ if (!usage || usage.billing_unit !== PLATFORM_CREDIT_UNIT) return void 0;
280
+ const cost = typeof usage.cost === "number" ? usage.cost : 0;
281
+ return Number.isFinite(cost) && cost > 0 ? cost : 0;
282
+ }
283
+ function withTurnCredits(tokens, credits) {
284
+ if (!tokens) return tokens;
285
+ if (credits === void 0) return tokens;
286
+ return { ...tokens, credits };
287
+ }
288
+ function formatCreditsChip(credits, options) {
289
+ return options?.compact ? `\u26A1${credits.toFixed(2)}` : `\u26A1 ${credits.toFixed(2)} \u79EF\u5206`;
290
+ }
257
291
  function formatTokenCount(value) {
258
292
  if (!Number.isFinite(value) || value < 0) return "\u2014";
259
293
  if (value < 1e3) return String(Math.round(value));
@@ -2908,6 +2942,14 @@ function normalizeListLine(line) {
2908
2942
  }
2909
2943
  return line;
2910
2944
  }
2945
+ function isPolishListLikeLine(line) {
2946
+ return LIST_LIKE_RE_FOR_GUARD.test(normalizeListLine(line));
2947
+ }
2948
+ var LIST_LIKE_RE_FOR_GUARD = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]|^\s*[├└]──\s/;
2949
+ function polishBreathInsertsBlankBetween(cur, next) {
2950
+ if (cur === "" || next === "") return false;
2951
+ return isPolishListLikeLine(cur) !== isPolishListLikeLine(next);
2952
+ }
2911
2953
  function convertMarkdownTablesForTerminal(text) {
2912
2954
  const lines = text.split("\n");
2913
2955
  const out = [];
@@ -2975,7 +3017,7 @@ function polishAssistantStructure(text, options = {}) {
2975
3017
  return line;
2976
3018
  });
2977
3019
  const afterHeading = maskedLines.join("\n").replace(/([^\n])\n(#{1,3} )/g, "$1\n\n$2").replace(/^(#{1,3} .+)\n(?!\n)/gm, "$1\n\n").replace(/\n{4,}/g, "\n\n\n");
2978
- const LIST_LIKE = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]/;
3020
+ const LIST_LIKE = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]|^\s*[├└]──\s/;
2979
3021
  const headingLines = afterHeading.split("\n");
2980
3022
  const breathed = [];
2981
3023
  for (let i = 0; i < headingLines.length; i++) {
@@ -3333,130 +3375,16 @@ function formatAssistantTextForCli(text) {
3333
3375
  return text.replace(/\u003cthink\u003e[\s\S]*?\u003c\/think\u003e\s*/gi, "").replace(/\n{3,}/g, "\n\n").trim();
3334
3376
  }
3335
3377
 
3336
- // packages/cli/client/formatReadPathTree.ts
3337
- import { homedir as osHomedir } from "node:os";
3338
-
3339
- // packages/core/foldHomePath.ts
3340
- function foldHomePath(path, home) {
3341
- if (!path) return path;
3342
- if (home) {
3343
- const cleanHome = home.endsWith("/") ? home.slice(0, -1) : home;
3344
- if (path === cleanHome) return "~";
3345
- if (path.startsWith(cleanHome + "/")) return `~${path.slice(cleanHome.length)}`;
3346
- }
3347
- return path.replace(/^(\/Users\/[^/]+|\/home\/[^/]+)(\/|$)/, "~$2");
3348
- }
3349
-
3350
- // packages/cli/client/formatReadPathTree.ts
3351
- function clipPathAware(value, max = 72) {
3352
- const compact = compactWhitespace(value);
3353
- if (compact.length <= max) return compact;
3354
- if (compact.includes(" ") || !compact.includes("/") && !compact.includes("\\")) {
3355
- return clipCompactText(value, max, "\u2026");
3356
- }
3357
- const segments = compact.split(/[/\\]/);
3358
- const filename = segments[segments.length - 1];
3359
- if (filename.length >= max) {
3360
- return clipCompactText(value, max, "\u2026");
3361
- }
3362
- const ELISION = "/\u2026/";
3363
- let prefix = "";
3364
- for (let i = 0; i < segments.length - 1; i += 1) {
3365
- const candidate = segments.slice(0, i + 1).join("/");
3366
- if (candidate.length + ELISION.length + filename.length > max) break;
3367
- prefix = candidate;
3368
- }
3369
- if (prefix) return `${prefix}${ELISION}${filename}`;
3370
- const filenameOnly = `\u2026/${filename}`;
3371
- if (filenameOnly.length <= max) return filenameOnly;
3372
- return clipCompactText(value, max, "\u2026");
3373
- }
3374
- function formatHomePath(path, customHomedir) {
3375
- if (!path) return "";
3376
- const home = customHomedir || (typeof process !== "undefined" ? process.env?.HOME : void 0) || (typeof osHomedir === "function" ? osHomedir() : "");
3377
- return foldHomePath(path, home);
3378
- }
3379
- function formatReadItemPath(rawPath, metadata, customHomedir) {
3380
- const inputPath = rawPath || (typeof metadata?.path === "string" ? metadata.path : void 0) || (typeof metadata?.filePath === "string" ? metadata.filePath : void 0) || "file";
3381
- let formattedPath = formatHomePath(inputPath, customHomedir);
3382
- if (!formattedPath) return "file";
3383
- let rangePart = "";
3384
- const match = formattedPath.match(/(:[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*)$/);
3385
- if (match) {
3386
- rangePart = match[1];
3387
- formattedPath = formattedPath.slice(0, -rangePart.length);
3388
- } else if (metadata && typeof metadata.startLine === "number" && typeof metadata.endLine === "number" && typeof metadata.totalLines === "number") {
3389
- const { startLine, endLine, totalLines, truncated } = metadata;
3390
- if (truncated || startLine !== 1 || endLine !== totalLines) {
3391
- rangePart = `:${startLine}-${endLine}`;
3392
- }
3393
- }
3394
- const clippedPath = clipPathAware(formattedPath, 72);
3395
- return `${clippedPath}${rangePart}`;
3396
- }
3397
- function formatReadTreeLines(items, customHomedir) {
3398
- const count = items.length;
3399
- const header = `Read (${count})`;
3400
- const lines = items.map((item, index) => {
3401
- const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
3402
- const pathWithRange = formatReadItemPath(item.path, item.metadata, customHomedir);
3403
- return { connector, pathWithRange };
3404
- });
3405
- return { header, count, lines };
3406
- }
3407
- function formatSearchItemQuery(query, path, customHomedir) {
3408
- let text = (query || "").trim();
3409
- if (path) {
3410
- const formattedPath = formatHomePath(path, customHomedir);
3411
- if (formattedPath) {
3412
- text = text ? `${text} in ${formattedPath}` : formattedPath;
3413
- }
3414
- }
3415
- if (!text) return "search";
3416
- return text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
3417
- }
3418
- function formatSearchTreeLines(items, customHomedir) {
3419
- const count = items.length;
3420
- const header = `Search (${count})`;
3421
- const lines = items.map((item, index) => {
3422
- const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
3423
- const queryText = formatSearchItemQuery(item.query, item.path, customHomedir);
3424
- return { connector, queryText };
3425
- });
3426
- return { header, count, lines };
3427
- }
3428
- function formatRunItemCommand(command, exitCode, timedOut) {
3429
- let text = compactWhitespace(command || "");
3430
- if (!text) text = "command";
3431
- text = text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
3432
- if (timedOut) return `${text} (timed out)`;
3433
- if (typeof exitCode === "number" && exitCode !== 0) return `${text} (exit ${exitCode})`;
3434
- return text;
3435
- }
3436
- function formatRunTreeLines(items) {
3437
- const count = items.length;
3438
- const header = `Run (${count})`;
3439
- const lines = items.map((item, index) => {
3440
- const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
3441
- const commandText = formatRunItemCommand(item.command, item.exitCode, item.timedOut);
3442
- return { connector, commandText };
3443
- });
3444
- return { header, count, lines };
3445
- }
3446
- function formatFetchItemUrl(url) {
3447
- const text = (url || "").trim();
3448
- if (!text) return "webpage";
3449
- return text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
3450
- }
3451
- function formatFetchTreeLines(items) {
3452
- const count = items.length;
3453
- const header = `Fetch (${count})`;
3454
- const lines = items.map((item, index) => {
3455
- const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
3456
- const urlText = formatFetchItemUrl(item.url);
3457
- return { connector, urlText };
3458
- });
3459
- return { header, count, lines };
3378
+ // packages/cli/tui/redactSecrets.ts
3379
+ var REDACTED = "\u27E8redacted\u27E9";
3380
+ function redactSecrets(text) {
3381
+ return text.replace(/\b(?:sk|pk)-[A-Za-z0-9_-]{10,}/g, REDACTED).replace(/\b(Bearer\s+)[A-Za-z0-9._~+/=-]{12,}/gi, `$1${REDACTED}`).replace(
3382
+ /\b((?:api[_-]?key|apikey|access[_-]?token|auth[_-]?token|token|secret|password|passwd|credential)s?\s*[=:]\s*["']?)[^\s"',;]{8,}/gi,
3383
+ `$1${REDACTED}`
3384
+ ).replace(
3385
+ /\b((?:--[a-z-]*(?:token|key|secret|password|credential)[a-z-]*)\s+)[^\s"']{8,}/gi,
3386
+ `$1${REDACTED}`
3387
+ );
3460
3388
  }
3461
3389
 
3462
3390
  // node_modules/diff/libesm/diff/base.js
@@ -3709,186 +3637,110 @@ function tokenize(value, options) {
3709
3637
  return retLines;
3710
3638
  }
3711
3639
 
3712
- // packages/cli/client/toolOutput.ts
3713
- function normalizeToolDisplayMode(raw, fallback = "normal") {
3714
- const normalized = asTrimmedLowercaseString(raw);
3715
- if (normalized === "hide" || normalized === "off" || normalized === "false" || normalized === "0") {
3716
- return "hide";
3640
+ // packages/cli/client/formatReadPathTree.ts
3641
+ import { homedir as osHomedir } from "node:os";
3642
+
3643
+ // packages/core/foldHomePath.ts
3644
+ function foldHomePath(path, home) {
3645
+ if (!path) return path;
3646
+ if (home) {
3647
+ const cleanHome = home.endsWith("/") ? home.slice(0, -1) : home;
3648
+ if (path === cleanHome) return "~";
3649
+ if (path.startsWith(cleanHome + "/")) return `~${path.slice(cleanHome.length)}`;
3717
3650
  }
3718
- if (normalized === "verbose" || normalized === "debug" || normalized === "trace" || normalized === "full") {
3719
- return "verbose";
3651
+ return path.replace(/^(\/Users\/[^/]+|\/home\/[^/]+)(\/|$)/, "~$2");
3652
+ }
3653
+
3654
+ // packages/cli/client/formatReadPathTree.ts
3655
+ function clipPathAware(value, max = 72) {
3656
+ const compact = compactWhitespace(value);
3657
+ if (compact.length <= max) return compact;
3658
+ if (compact.includes(" ") || !compact.includes("/") && !compact.includes("\\")) {
3659
+ return clipCompactText(value, max, "\u2026");
3720
3660
  }
3721
- if (normalized === "normal" || normalized === "summary" || normalized === "on") {
3722
- return "normal";
3661
+ const segments = compact.split(/[/\\]/);
3662
+ const filename = segments[segments.length - 1];
3663
+ if (filename.length >= max) {
3664
+ return clipCompactText(value, max, "\u2026");
3723
3665
  }
3724
- if (normalized === "pro" || normalized === "compact" || normalized === "minimal" || normalized === "short") {
3725
- return "pro";
3666
+ const ELISION = "/\u2026/";
3667
+ let prefix = "";
3668
+ for (let i = 0; i < segments.length - 1; i += 1) {
3669
+ const candidate = segments.slice(0, i + 1).join("/");
3670
+ if (candidate.length + ELISION.length + filename.length > max) break;
3671
+ prefix = candidate;
3726
3672
  }
3727
- return fallback;
3673
+ if (prefix) return `${prefix}${ELISION}${filename}`;
3674
+ const filenameOnly = `\u2026/${filename}`;
3675
+ if (filenameOnly.length <= max) return filenameOnly;
3676
+ return clipCompactText(value, max, "\u2026");
3677
+ }
3678
+ function formatHomePath(path, customHomedir) {
3679
+ if (!path) return "";
3680
+ const home = customHomedir || (typeof process !== "undefined" ? process.env?.HOME : void 0) || (typeof osHomedir === "function" ? osHomedir() : "");
3681
+ return foldHomePath(path, home);
3728
3682
  }
3729
- function resolveToolDisplayMode(env = process.env) {
3730
- const legacyTrace = asTrimmedLowercaseString(env.NOLO_TRACE_TOOLS);
3731
- if (legacyTrace === "0" || legacyTrace === "false" || legacyTrace === "off") {
3732
- return "hide";
3683
+ function formatReadItemPath(rawPath, metadata, customHomedir) {
3684
+ const inputPath = rawPath || (typeof metadata?.path === "string" ? metadata.path : void 0) || (typeof metadata?.filePath === "string" ? metadata.filePath : void 0) || "file";
3685
+ let formattedPath = formatHomePath(inputPath, customHomedir);
3686
+ if (!formattedPath) return "file";
3687
+ let rangePart = "";
3688
+ const match = formattedPath.match(/(:[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*)$/);
3689
+ if (match) {
3690
+ rangePart = match[1];
3691
+ formattedPath = formattedPath.slice(0, -rangePart.length);
3692
+ } else if (metadata && typeof metadata.startLine === "number" && typeof metadata.endLine === "number" && typeof metadata.totalLines === "number") {
3693
+ const { startLine, endLine, totalLines, truncated } = metadata;
3694
+ if (truncated || startLine !== 1 || endLine !== totalLines) {
3695
+ rangePart = `:${startLine}-${endLine}`;
3696
+ }
3733
3697
  }
3734
- if (legacyTrace === "verbose" || legacyTrace === "full") {
3735
- return "verbose";
3698
+ const clippedPath = clipPathAware(formattedPath, 72);
3699
+ return `${clippedPath}${rangePart}`;
3700
+ }
3701
+ function formatSearchItemQuery(query, path, customHomedir) {
3702
+ let text = (query || "").trim();
3703
+ if (path) {
3704
+ const formattedPath = formatHomePath(path, customHomedir);
3705
+ if (formattedPath) {
3706
+ text = text ? `${text} in ${formattedPath}` : formattedPath;
3707
+ }
3736
3708
  }
3737
- return normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "normal");
3709
+ if (!text) return "search";
3710
+ return text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
3711
+ }
3712
+ function formatRunItemCommand(command, exitCode, timedOut) {
3713
+ let text = compactWhitespace(command || "");
3714
+ if (!text) text = "command";
3715
+ text = text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
3716
+ if (timedOut) return `${text} (timed out)`;
3717
+ if (typeof exitCode === "number" && exitCode !== 0) return `${text} (exit ${exitCode})`;
3718
+ return text;
3738
3719
  }
3739
- function shouldEmitToolEvents(mode) {
3740
- return mode !== "hide";
3720
+ function formatFetchItemUrl(url) {
3721
+ const text = (url || "").trim();
3722
+ if (!text) return "webpage";
3723
+ return text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
3741
3724
  }
3725
+
3726
+ // packages/cli/client/toolOutput.ts
3742
3727
  function clip(value, max = 72) {
3743
3728
  return clipCompactText(value, max, "\u2026");
3744
3729
  }
3745
- function formatActiveToolLabel(event) {
3746
- const toolName = event.toolName || "tool";
3747
- const args = clipPathAware(event.argumentsPreview ?? "");
3748
- const label = toolLabel(toolName);
3749
- return args ? `${label} ${args}` : label;
3750
- }
3751
3730
  function formatConservativeActiveToolLabel(event) {
3752
3731
  return toolLabel(event.toolName || "tool");
3753
3732
  }
3754
- function compactResultHint(event) {
3755
- const gate = readActionGate(event.metadata?.actionGate);
3756
- if (gate) {
3757
- const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
3758
- const command = commandPayload?.displayCommand ?? commandPayload?.command.join(" ") ?? "";
3759
- const detail = command.trim() ? command : gate.title;
3760
- return { inline: `${t("toolNeedsAction")}: ${clip(detail, 120)}` };
3761
- }
3762
- if (event.metadata?.timedOut) return { inline: t("toolTimedOut") };
3763
- if (event.toolName === "readFile" && event.metadata) {
3764
- const range = readReadFileRange(event.metadata);
3765
- if (range) return { inline: range };
3766
- }
3767
- if (event.toolName === "editFile" && event.metadata) {
3768
- const res = formatEditFileSnippet(event.metadata);
3769
- if (res) {
3770
- const stats = [];
3771
- if (res.addedCount > 0) stats.push(`+${res.addedCount}`);
3772
- if (res.removedCount > 0) stats.push(`-${res.removedCount}`);
3773
- const inline = stats.length > 0 ? `(${stats.join(", ")})` : "";
3774
- return { inline, detail: res.lines };
3775
- }
3776
- }
3777
- if (event.toolName === "writeFile" && event.metadata) {
3778
- const totalLines = event.metadata.totalLines ?? event.metadata.lines;
3779
- if (typeof totalLines === "number" && totalLines > 0) {
3780
- return { inline: `(+${totalLines})` };
3781
- }
3782
- }
3783
- const summary = event.summary;
3784
- if (!summary) return { inline: "" };
3785
- const exitMatch = summary.match(/exit=(\d+)/);
3786
- if (exitMatch && exitMatch[1] !== "0") return { inline: `${t("toolExitCode")} ${exitMatch[1]}` };
3787
- return { inline: "" };
3788
- }
3789
- function readReadFileRange(metadata) {
3790
- const startLine = metadata.startLine;
3791
- const endLine = metadata.endLine;
3792
- const totalLines = metadata.totalLines;
3793
- const truncated = metadata.truncated;
3794
- if (typeof startLine !== "number" || typeof endLine !== "number" || typeof totalLines !== "number") {
3795
- return void 0;
3796
- }
3797
- if (!truncated && startLine === 1 && endLine === totalLines) return void 0;
3798
- return `${startLine}-${endLine}/${totalLines}`;
3799
- }
3800
- var EDIT_SNIPPET_MAX_LINES = 24;
3801
- var DEFAULT_EDIT_SNIPPET_MAX_WIDTH = 96;
3802
- function resolveEditSnippetMaxWidth(env = process.env, columns) {
3803
- if (env.NOLO_TEST_DIFF_WIDTH) {
3804
- const parsed = parseInt(env.NOLO_TEST_DIFF_WIDTH, 10);
3805
- if (!Number.isNaN(parsed) && parsed > 0) return parsed;
3806
- }
3807
- const cols = typeof columns === "number" ? columns : typeof process !== "undefined" && typeof process.stdout?.columns === "number" ? process.stdout.columns : 0;
3808
- if (cols > 0) {
3809
- return Math.max(80, Math.min(160, cols - 8));
3810
- }
3811
- return DEFAULT_EDIT_SNIPPET_MAX_WIDTH;
3812
- }
3813
- function formatEditFileSnippet(metadata) {
3814
- const oldSnippet = typeof metadata.oldSnippet === "string" ? metadata.oldSnippet : void 0;
3815
- const newSnippet = typeof metadata.newSnippet === "string" ? metadata.newSnippet : void 0;
3816
- if (!oldSnippet && !newSnippet) return void 0;
3817
- const maxWidth = resolveEditSnippetMaxWidth();
3818
- if (oldSnippet && !newSnippet) {
3819
- const lines = snippetLinesWithKind(oldSnippet, "removed", maxWidth);
3820
- return { lines, addedCount: 0, removedCount: lines.length };
3821
- }
3822
- if (newSnippet && !oldSnippet) {
3823
- const lines = snippetLinesWithKind(newSnippet, "added", maxWidth);
3824
- return { lines, addedCount: lines.length, removedCount: 0 };
3825
- }
3826
- const parts = diffLines(oldSnippet, newSnippet);
3827
- const all = [];
3828
- let addedCount = 0;
3829
- let removedCount = 0;
3830
- for (const part of parts) {
3831
- const kind = part.added ? "added" : part.removed ? "removed" : "context";
3832
- const raw = part.value.split("\n");
3833
- if (raw.length > 0 && raw[raw.length - 1] === "") raw.pop();
3834
- for (const line of raw) {
3835
- if (kind === "added") addedCount++;
3836
- if (kind === "removed") removedCount++;
3837
- all.push(buildEditLine(kind, line, maxWidth));
3838
- }
3839
- }
3840
- const changeCount = all.filter((l) => l.kind !== "context").length;
3841
- if (changeCount === 0) return void 0;
3842
- return {
3843
- lines: windowAndTruncate(all, EDIT_SNIPPET_MAX_LINES),
3844
- addedCount,
3845
- removedCount
3846
- };
3847
- }
3848
- function prefixFor(kind) {
3849
- return kind === "added" ? "+ " : kind === "removed" ? "- " : " ";
3733
+ function isRunToolName(name) {
3734
+ return name === "execShell" || name === "runCommand" || name === "launchProcess";
3850
3735
  }
3851
- function buildEditLine(kind, body, maxWidth = resolveEditSnippetMaxWidth()) {
3852
- return { kind, text: prefixFor(kind) + truncateByDisplayWidth(body, maxWidth) };
3736
+ function isReadToolName(name) {
3737
+ return name === "readFile";
3853
3738
  }
3854
- function snippetLinesWithKind(snippet, kind, maxWidth = resolveEditSnippetMaxWidth()) {
3855
- const lines = snippet.split(/\r?\n/).filter((line) => line.length > 0);
3856
- return lines.slice(0, EDIT_SNIPPET_MAX_LINES).map((line) => buildEditLine(kind, line, maxWidth));
3857
- }
3858
- function truncateByDisplayWidth(line, maxWidth) {
3859
- if (displayWidth(line) <= maxWidth) return line;
3860
- let width = 0;
3861
- let kept = "";
3862
- for (const char of line) {
3863
- const w = displayWidth(char);
3864
- if (width + w + 1 > maxWidth) break;
3865
- kept += char;
3866
- width += w;
3867
- }
3868
- return `${kept}\u2026`;
3869
- }
3870
- function windowAndTruncate(lines, maxLines) {
3871
- if (lines.length <= maxLines) return lines;
3872
- const firstChange = lines.findIndex((l) => l.kind !== "context");
3873
- if (firstChange === -1) return lines.slice(0, maxLines);
3874
- const half = Math.floor(maxLines / 2);
3875
- let start = Math.max(0, firstChange - half);
3876
- if (start + maxLines > lines.length) start = Math.max(0, lines.length - maxLines);
3877
- const kept = lines.slice(start, start + maxLines);
3878
- const omitted = lines.length - kept.length;
3879
- if (omitted > 0) {
3880
- kept.push({ kind: "context", text: ` \u2026 +${omitted} more lines` });
3881
- }
3882
- return kept;
3883
- }
3884
- function isFailedToolResult(event) {
3885
- const exitCode = event.metadata?.exitCode;
3886
- if (event.metadata?.actionGate) return false;
3887
- if (typeof exitCode === "number" && exitCode !== 0) return true;
3888
- return Boolean(event.metadata?.timedOut);
3889
- }
3890
- function isNeedsActionToolResult(event) {
3891
- return Boolean(event.metadata?.actionGate);
3739
+ function isFailedToolResult(event) {
3740
+ const exitCode = event.metadata?.exitCode;
3741
+ if (event.metadata?.actionGate) return false;
3742
+ if (typeof exitCode === "number" && exitCode !== 0) return true;
3743
+ return Boolean(event.metadata?.timedOut);
3892
3744
  }
3893
3745
  function parseUiAskChoiceForCli(event) {
3894
3746
  if (event.toolName !== "ask_user" && !event.metadata?.uiAskChoice) {
@@ -4006,7 +3858,10 @@ function renderRunCard(snapshot, opts) {
4006
3858
  lastToolNames: snapshot.lastToolNames?.map(cleanUserText)
4007
3859
  } : snapshot;
4008
3860
  const hadError = safe && Boolean(source.errorMessage?.trim());
4009
- const errorFields = safe ? { errorMessage: void 0, logLines: void 0 } : { errorMessage: source.errorMessage, logLines: source.logLines };
3861
+ const errorFields = safe ? {
3862
+ errorMessage: hadError ? clip(redactSecrets(cleanUserText(source.errorMessage)), 160) : void 0,
3863
+ logLines: void 0
3864
+ } : { errorMessage: source.errorMessage, logLines: source.logLines };
4010
3865
  const body = isAgentRunTerminalStatus(snapshot.status) ? formatFinishedRunCard(name, snapshot.status, {
4011
3866
  runId: snapshot.runId,
4012
3867
  toolCallCount: source.toolCallCount,
@@ -4026,8 +3881,7 @@ function renderRunCard(snapshot, opts) {
4026
3881
  ...opts?.includeLogTail !== void 0 ? { includeLogTail: opts.includeLogTail } : {},
4027
3882
  labels
4028
3883
  });
4029
- return hadError ? `${body}
4030
- error ${t("runDiagnosticsHidden")}` : body;
3884
+ return body;
4031
3885
  }
4032
3886
  function recoverOrchestrationCard(event, toolName, opts) {
4033
3887
  const safe = opts?.safe === true;
@@ -4073,10 +3927,6 @@ function recoverOrchestrationCard(event, toolName, opts) {
4073
3927
  if (kind === "stop") return formatStopRunCard(snapshot.status, labels);
4074
3928
  return renderRunCard(snapshot, opts);
4075
3929
  }
4076
- function parseControlAgentRunStatusEvent(event) {
4077
- const parsed = parseAgentRunEvent(event);
4078
- return parsed?.kind === "status" ? parsed.snapshot : null;
4079
- }
4080
3930
  function formatOrchestrationCardBlock(event, toolName, colorEnabled, opts) {
4081
3931
  const safe = opts?.safe === true;
4082
3932
  const rawLabel = toolLabel(toolName);
@@ -4084,8 +3934,8 @@ function formatOrchestrationCardBlock(event, toolName, colorEnabled, opts) {
4084
3934
  const rawDataStr = recoverOrchestrationCard(event, toolName, { safe }) || bakedCard || (typeof event.content === "string" ? event.content : "");
4085
3935
  const failed = event.type === "tool-error" || isFailedToolResult(event) || Boolean(event.metadata?.failed) || /^Error:/i.test(rawDataStr.trim());
4086
3936
  if (failed) {
4087
- const firstLine = safe ? t("toolFailed") : rawDataStr.trim().split("\n")[0] || event.summary || event.message || t("toolFailed");
4088
- const message = clip(firstLine, 96);
3937
+ const firstLine = stripAnsi2(rawDataStr.trim().split("\n")[0] || event.summary || event.message || t("toolFailed"));
3938
+ const message = clip(redactSecrets(firstLine), 96);
4089
3939
  if (!colorEnabled) {
4090
3940
  return `\u2717 ${rawLabel} ${message}
4091
3941
  `;
@@ -4127,7 +3977,7 @@ function sanitizeRunCardForNormal(lines) {
4127
3977
  break;
4128
3978
  }
4129
3979
  if (/^\s*error\b/i.test(line)) {
4130
- out.push(` error ${t("runDiagnosticsHidden")}`);
3980
+ out.push(clip(redactSecrets(stripAnsi2(line)), 160));
4131
3981
  errorIndent = line.length - line.trimStart().length;
4132
3982
  continue;
4133
3983
  }
@@ -4146,59 +3996,207 @@ function sanitizeRunCardForNormal(lines) {
4146
3996
  }
4147
3997
  return out;
4148
3998
  }
4149
- function mergeRunSnapshot(previous, next) {
4150
- return {
4151
- ...previous,
4152
- ...next,
4153
- errorMessage: next.errorMessage ?? previous.errorMessage,
4154
- logLines: next.logLines ?? previous.logLines,
4155
- logKey: next.logKey || previous.logKey,
4156
- toolCallCount: next.toolCallCount ?? previous.toolCallCount,
4157
- lastToolNames: next.lastToolNames ?? previous.lastToolNames,
4158
- lastAssistantText: next.lastAssistantText ?? previous.lastAssistantText,
4159
- startedAt: next.startedAt ?? previous.startedAt,
4160
- finishedAt: next.finishedAt ?? previous.finishedAt
4161
- };
3999
+ var NORMAL_TOOL_GIST_MAX = 28;
4000
+ function gistClip(value, max = NORMAL_TOOL_GIST_MAX) {
4001
+ const oneLine = value.replace(/\s+/g, " ").trim();
4002
+ if (!oneLine) return "";
4003
+ return oneLine.length <= max ? oneLine : `${oneLine.slice(0, max - 1)}\u2026`;
4162
4004
  }
4163
- function formatFoldedControlStatusCard(snapshot, colorEnabled) {
4164
- const body = renderRunCard(snapshot, { includeLogTail: snapshot.includeLogTail });
4165
- return formatOrchestrationCardBlock(
4166
- {
4167
- type: "tool-result",
4168
- round: 0,
4169
- toolCallId: `fold-${snapshot.runId}`,
4170
- toolName: "controlAgentRun",
4171
- content: "",
4172
- metadata: { displayData: body }
4173
- },
4174
- "controlAgentRun",
4175
- colorEnabled
4176
- );
4005
+ var DEFAULT_RUN_GIST_MAX = 96;
4006
+ function normalRunGistMaxWidth(env = process.env, columns) {
4007
+ const pinned = parseInt(env.NOLO_TEST_RUN_GIST_WIDTH ?? "", 10);
4008
+ if (!Number.isNaN(pinned) && pinned > 0) return pinned;
4009
+ const cols = typeof columns === "number" ? columns : typeof process !== "undefined" && typeof process.stdout?.columns === "number" ? process.stdout.columns : 0;
4010
+ if (cols > 0) {
4011
+ return Math.max(48, Math.min(160, cols - 32));
4012
+ }
4013
+ return DEFAULT_RUN_GIST_MAX;
4014
+ }
4015
+ function commandFullGist(command, max) {
4016
+ const oneLine = command.replace(/\s+/g, " ").trim();
4017
+ if (!oneLine) return "";
4018
+ return truncateByDisplayWidth(redactSecrets(oneLine), max);
4177
4019
  }
4178
- function formatVerboseToolEvent(event, colorEnabled) {
4179
- const round = event.round + 1;
4180
- const detail = event.argumentsPreview ? ` ${event.argumentsPreview}` : "";
4181
- if (event.type === "tool-call") {
4182
- return formatToolTraceLine(`[nolo:tool] #${round} -> ${event.toolName}${detail}`, colorEnabled);
4020
+ function pathBasenameGist(path) {
4021
+ const segments = path.split(/[\\/]/).filter((segment) => segment.length > 0);
4022
+ const base = segments.pop();
4023
+ return base ? gistClip(base) : "";
4024
+ }
4025
+ var EDIT_SNIPPET_MAX_LINES = 24;
4026
+ var DEFAULT_EDIT_SNIPPET_MAX_WIDTH = 96;
4027
+ function resolveEditSnippetMaxWidth(env = process.env, columns) {
4028
+ if (env.NOLO_TEST_DIFF_WIDTH) {
4029
+ const parsed = parseInt(env.NOLO_TEST_DIFF_WIDTH, 10);
4030
+ if (!Number.isNaN(parsed) && parsed > 0) return parsed;
4183
4031
  }
4184
- if (event.type === "tool-error") {
4185
- const elapsed2 = typeof event.elapsedMs === "number" ? ` ${event.elapsedMs}ms` : "";
4186
- return formatToolTraceLine(
4187
- `[nolo:tool] #${round} !! ${event.toolName}${elapsed2}: ${event.message ?? "failed"}`,
4188
- colorEnabled,
4189
- "error"
4190
- );
4032
+ const cols = typeof columns === "number" ? columns : typeof process !== "undefined" && typeof process.stdout?.columns === "number" ? process.stdout.columns : 0;
4033
+ if (cols > 0) {
4034
+ return Math.max(80, Math.min(160, cols - 8));
4191
4035
  }
4192
- const elapsed = typeof event.elapsedMs === "number" ? ` ${event.elapsedMs}ms` : "";
4193
- if (event.type === "tool-result" && (event.toolName === "ask_user" || event.metadata?.uiAskChoice)) {
4194
- const block = formatUiAskChoiceBlock(event, colorEnabled);
4195
- if (block) return `${formatToolTraceLine(`[nolo:tool] #${round} <- ${event.toolName}${elapsed}`, colorEnabled)}${block}`;
4036
+ return DEFAULT_EDIT_SNIPPET_MAX_WIDTH;
4037
+ }
4038
+ function prefixFor(kind) {
4039
+ return kind === "added" ? "+ " : kind === "removed" ? "- " : " ";
4040
+ }
4041
+ function buildEditLine(kind, body, maxWidth = resolveEditSnippetMaxWidth()) {
4042
+ return { kind, text: prefixFor(kind) + truncateByDisplayWidth(body, maxWidth) };
4043
+ }
4044
+ function snippetLinesWithKind(snippet, kind, maxWidth = resolveEditSnippetMaxWidth()) {
4045
+ const lines = snippet.split(/\r?\n/);
4046
+ if (lines.at(-1) === "") lines.pop();
4047
+ return lines.slice(0, EDIT_SNIPPET_MAX_LINES).map((line) => buildEditLine(kind, line, maxWidth));
4048
+ }
4049
+ function truncateByDisplayWidth(line, maxWidth) {
4050
+ if (displayWidth(line) <= maxWidth) return line;
4051
+ let width = 0;
4052
+ let kept = "";
4053
+ for (const char of line) {
4054
+ const w = displayWidth(char);
4055
+ if (width + w + 1 > maxWidth) break;
4056
+ kept += char;
4057
+ width += w;
4196
4058
  }
4197
- const summary = event.summary ? ` ${event.summary}` : "";
4198
- return formatToolTraceLine(
4199
- `[nolo:tool] #${round} <- ${event.toolName}${elapsed}${summary}`,
4200
- colorEnabled
4201
- );
4059
+ return `${kept}\u2026`;
4060
+ }
4061
+ function windowAndTruncate(lines, maxLines) {
4062
+ if (lines.length <= maxLines) return lines;
4063
+ const firstChange = lines.findIndex((l) => l.kind !== "context");
4064
+ if (firstChange === -1) return lines.slice(0, maxLines);
4065
+ const half = Math.floor(maxLines / 2);
4066
+ let start = Math.max(0, firstChange - half);
4067
+ if (start + maxLines > lines.length) start = Math.max(0, lines.length - maxLines);
4068
+ const kept = lines.slice(start, start + maxLines);
4069
+ const omitted = lines.length - kept.length;
4070
+ if (omitted > 0) {
4071
+ kept.push({ kind: "context", text: ` \u2026 +${omitted} more lines` });
4072
+ }
4073
+ return kept;
4074
+ }
4075
+ function formatEditFileSnippet(metadata) {
4076
+ const oldSnippet = typeof metadata.oldSnippet === "string" ? metadata.oldSnippet : void 0;
4077
+ const newSnippet = typeof metadata.newSnippet === "string" ? metadata.newSnippet : void 0;
4078
+ if (!oldSnippet && !newSnippet) return void 0;
4079
+ const maxWidth = resolveEditSnippetMaxWidth();
4080
+ if (oldSnippet && !newSnippet) {
4081
+ const lines = snippetLinesWithKind(oldSnippet, "removed", maxWidth);
4082
+ return { lines, addedCount: 0, removedCount: lines.length };
4083
+ }
4084
+ if (newSnippet && !oldSnippet) {
4085
+ const lines = snippetLinesWithKind(newSnippet, "added", maxWidth);
4086
+ return { lines, addedCount: lines.length, removedCount: 0 };
4087
+ }
4088
+ const parts = diffLines(oldSnippet, newSnippet);
4089
+ const all = [];
4090
+ let addedCount = 0;
4091
+ let removedCount = 0;
4092
+ for (const part of parts) {
4093
+ const kind = part.added ? "added" : part.removed ? "removed" : "context";
4094
+ const bodyLines = part.value.replace(/\n$/, "").split("\n");
4095
+ for (const line of bodyLines) {
4096
+ if (kind === "added") addedCount++;
4097
+ if (kind === "removed") removedCount++;
4098
+ all.push(buildEditLine(kind, line, maxWidth));
4099
+ }
4100
+ }
4101
+ return {
4102
+ lines: windowAndTruncate(all, EDIT_SNIPPET_MAX_LINES),
4103
+ addedCount,
4104
+ removedCount
4105
+ };
4106
+ }
4107
+ function editFileResultHint(event) {
4108
+ if (event.toolName !== "editFile" || !event.metadata) return null;
4109
+ const res = formatEditFileSnippet(event.metadata);
4110
+ if (!res) return null;
4111
+ const stats = [];
4112
+ if (res.addedCount > 0) stats.push(`+${res.addedCount}`);
4113
+ if (res.removedCount > 0) stats.push(`-${res.removedCount}`);
4114
+ const inline = stats.length > 0 ? `(${stats.join(", ")})` : "";
4115
+ return { inline, detail: res.lines };
4116
+ }
4117
+ function formatEditDetailBlock(lines, colorEnabled, filePath, env = process.env) {
4118
+ if (!colorEnabled) {
4119
+ return lines.map((line) => ` ${line.text}
4120
+ `).join("");
4121
+ }
4122
+ const isTruecolor = supportsTruecolor(env);
4123
+ const lang = isTruecolor ? detectCodeLangFromPath(filePath) : "unknown";
4124
+ const brightness = resolveTuiBrightness(env);
4125
+ const padTo = Math.max(...lines.map((line) => displayWidth(line.text))) + 1;
4126
+ return lines.map((line) => ` ${renderDiffLine({
4127
+ kind: line.kind,
4128
+ text: line.text,
4129
+ highlightedText: shouldHighlightEditLine(line, lang, isTruecolor) ? buildHighlightedEditLine(line, lang, brightness, env) : void 0,
4130
+ padTo,
4131
+ colorEnabled: true,
4132
+ env
4133
+ })}
4134
+ `).join("");
4135
+ }
4136
+ function shouldHighlightEditLine(line, lang, isTruecolor) {
4137
+ if (!isTruecolor || lang === "unknown") return false;
4138
+ if (line.text.startsWith(" \u2026") || line.text.startsWith("\u2026")) return false;
4139
+ return line.text.length >= 2;
4140
+ }
4141
+ function buildHighlightedEditLine(line, lang, brightness, env) {
4142
+ const prefix = line.text.slice(0, 2);
4143
+ const body = line.text.slice(2);
4144
+ const prefixToken = line.kind === "added" ? "success" : line.kind === "removed" ? "danger" : "chrome";
4145
+ const coloredPrefix = themeText(prefix, prefixToken, true, env);
4146
+ const highlightedBody = highlightCodeLine(body, lang, brightness);
4147
+ return `${coloredPrefix}${highlightedBody}`;
4148
+ }
4149
+ function normalToolGistRaw(event) {
4150
+ const metadata = event.metadata ?? {};
4151
+ const toolName = event.toolName || "";
4152
+ if (toolName === "readFile") {
4153
+ const path2 = typeof metadata.path === "string" ? metadata.path : typeof metadata.filePath === "string" ? metadata.filePath : "";
4154
+ if (path2) return gistClip(formatReadItemPath(path2, metadata), 52);
4155
+ }
4156
+ if (toolName === "fetchWebpage") {
4157
+ const url = typeof metadata.url === "string" ? metadata.url : "";
4158
+ if (url) return formatFetchItemUrl(url);
4159
+ }
4160
+ if (toolName === "exa_search") {
4161
+ const query2 = typeof metadata.query === "string" ? metadata.query : typeof metadata.pattern === "string" ? metadata.pattern : "";
4162
+ const path2 = typeof metadata.path === "string" ? metadata.path : void 0;
4163
+ if (query2 || path2) return formatSearchItemQuery(query2, path2);
4164
+ }
4165
+ if (isRunToolName(toolName)) {
4166
+ const command2 = typeof metadata.command === "string" ? metadata.command : "";
4167
+ if (command2) {
4168
+ return commandFullGist(command2, normalRunGistMaxWidth());
4169
+ }
4170
+ }
4171
+ const path = typeof metadata.path === "string" ? metadata.path : "";
4172
+ if (path) return pathBasenameGist(path);
4173
+ const command = typeof metadata.command === "string" ? metadata.command : "";
4174
+ if (command) return commandFullGist(command, normalRunGistMaxWidth());
4175
+ const query = typeof metadata.query === "string" ? metadata.query : "";
4176
+ if (query) return clipCompactText(query, 64, "\u2026");
4177
+ const remembered = event.toolName === "rememberMemory" && typeof metadata.content === "string" ? metadata.content : "";
4178
+ if (remembered) return clipCompactText(redactSecrets(remembered), 64, "\u2026");
4179
+ return "";
4180
+ }
4181
+ var NORMAL_GIST_SECRET_PATTERNS = [
4182
+ /\bbearer\s+[A-Za-z0-9._~+/=-]{8,}/i,
4183
+ /\bsk-(?:ant-)?(?:api)?[0-9a-zA-Z-]{10,}/,
4184
+ /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{10,}/,
4185
+ /\bxox[baprs]-[A-Za-z0-9-]{10,}/
4186
+ ];
4187
+ function withholdIfSecretLike(gist) {
4188
+ if (!gist) return "";
4189
+ if (findPotentialSecrets(gist).length > 0) return "";
4190
+ if (NORMAL_GIST_SECRET_PATTERNS.some((pattern) => pattern.test(gist))) return "";
4191
+ return gist;
4192
+ }
4193
+ function normalToolGist(event) {
4194
+ return withholdIfSecretLike(normalToolGistRaw(event));
4195
+ }
4196
+ function formatNormalToolDuration(elapsedMs) {
4197
+ if (typeof elapsedMs !== "number" || !Number.isFinite(elapsedMs) || elapsedMs <= 500) return "";
4198
+ if (elapsedMs < 1e3) return `${Math.round(elapsedMs)}ms`;
4199
+ return `${(elapsedMs / 1e3).toFixed(1)}s`;
4202
4200
  }
4203
4201
  function formatNormalToolLine(event, pending, colorEnabled) {
4204
4202
  if (event.type === "tool-call") return "";
@@ -4220,158 +4218,42 @@ function formatNormalToolLine(event, pending, colorEnabled) {
4220
4218
  return formatToolTraceLine(`\u25B8 ${label} ! ${t("toolNeedsAction")}`, colorEnabled, "error");
4221
4219
  }
4222
4220
  if (event.type === "tool-error") {
4223
- return formatToolTraceLine(`\u25B8 ${label} \u2717 ${t("toolFailed")}`, colorEnabled, "error");
4221
+ return formatToolTraceLine(`\u25B8 ${label} \u2717 ${toolFailureReason(event) || t("toolFailed")}`, colorEnabled, "error");
4224
4222
  }
4225
4223
  if (event.metadata?.timedOut) {
4226
4224
  return formatToolTraceLine(`\u25B8 ${label} \u2717 ${t("toolTimedOut")}`, colorEnabled, "error");
4227
4225
  }
4228
4226
  if (isFailedToolResult(event)) {
4229
- return formatToolTraceLine(`\u25B8 ${label} \u2717 ${t("toolFailed")}`, colorEnabled, "error");
4230
- }
4231
- return formatToolTraceLine(`\u25B8 ${label} \u2713`, colorEnabled);
4232
- }
4233
- function isReadToolName(name) {
4234
- if (!name) return false;
4235
- return name === "read" || name === "readFile" || name === "read_file" || name === "readWorkspaceFile";
4236
- }
4237
- function isSearchToolName(name) {
4238
- if (!name) return false;
4239
- return name === "grep" || name === "codeSearch" || name === "code_search" || name === "globFiles" || name === "glob_files" || name === "glob" || name === "searchWorkspace" || name === "search_workspace" || name === "search_all_spaces" || name === "search";
4240
- }
4241
- function isRunToolName(name) {
4242
- if (!name) return false;
4243
- return name === "execShell" || name === "runCommand" || name === "run_command" || name === "launchProcess";
4244
- }
4245
- function isFetchToolName(name) {
4246
- if (!name) return false;
4247
- return name === "fetchWebpage" || name === "fetch_webpage";
4248
- }
4249
- function isWebSearchToolName(name) {
4250
- if (!name) return false;
4251
- return name === "exa_search" || name === "exaSearch";
4252
- }
4253
- function isRunResultFoldable(event) {
4254
- return Boolean(event.metadata?.actionGate) === false;
4255
- }
4256
- function formatSearchTreeBlockForCli(items, colorEnabled) {
4257
- if (items.length === 0) return "";
4258
- const { count, lines } = formatSearchTreeLines(items);
4259
- const titleText = toolLabel("codeSearch");
4260
- if (!colorEnabled) {
4261
- const headerLine2 = `\u2022 ${titleText} (${count})
4262
- `;
4263
- const treeLines2 = lines.map((l) => ` ${l.connector}${l.queryText}`).join("\n");
4264
- return `${headerLine2}${treeLines2}
4265
- `;
4266
- }
4267
- const bullet = themeText("\u2022", "chrome", true);
4268
- const title = styleCliText(titleText, "bold", true);
4269
- const countText = themeText(`(${count})`, "muted", true);
4270
- const headerLine = `${bullet} ${title} ${countText}
4271
- `;
4272
- const treeLines = lines.map((l) => {
4273
- const connector = themeText(` ${l.connector}`, "chrome", true);
4274
- const queryText = themeText(l.queryText, "muted", true);
4275
- return `${connector}${queryText}`;
4276
- }).join("\n");
4277
- return `${headerLine}${treeLines}
4278
- `;
4279
- }
4280
- function formatReadTreeBlockForCli(items, colorEnabled) {
4281
- if (items.length === 0) return "";
4282
- const { count, lines } = formatReadTreeLines(items);
4283
- const titleText = toolLabel("readFile");
4284
- if (!colorEnabled) {
4285
- const headerLine2 = `\u2022 ${titleText} (${count})
4286
- `;
4287
- const treeLines2 = lines.map((l) => ` ${l.connector}${l.pathWithRange}`).join("\n");
4288
- return `${headerLine2}${treeLines2}
4289
- `;
4290
- }
4291
- const bullet = themeText("\u2022", "chrome", true);
4292
- const title = styleCliText(titleText, "bold", true);
4293
- const countText = themeText(`(${count})`, "muted", true);
4294
- const headerLine = `${bullet} ${title} ${countText}
4295
- `;
4296
- const treeLines = lines.map((l) => {
4297
- const connector = themeText(` ${l.connector}`, "chrome", true);
4298
- const pathText = themeText(l.pathWithRange, "muted", true);
4299
- return `${connector}${pathText}`;
4300
- }).join("\n");
4301
- return `${headerLine}${treeLines}
4302
- `;
4303
- }
4304
- function formatRunTreeBlockForCli(items, colorEnabled) {
4305
- if (items.length === 0) return "";
4306
- const { count, lines } = formatRunTreeLines(items);
4307
- const titleText = toolLabel("execShell");
4308
- if (!colorEnabled) {
4309
- const headerLine2 = `\u2022 ${titleText} (${count})
4310
- `;
4311
- const treeLines2 = lines.map((l) => ` ${l.connector}${l.commandText}`).join("\n");
4312
- return `${headerLine2}${treeLines2}
4313
- `;
4314
- }
4315
- const bullet = themeText("\u2022", "chrome", true);
4316
- const title = styleCliText(titleText, "bold", true);
4317
- const countText = themeText(`(${count})`, "muted", true);
4318
- const headerLine = `${bullet} ${title} ${countText}
4319
- `;
4320
- const treeLines = lines.map((l) => {
4321
- const connector = themeText(` ${l.connector}`, "chrome", true);
4322
- const commandText = themeText(l.commandText, "muted", true);
4323
- return `${connector}${commandText}`;
4324
- }).join("\n");
4325
- return `${headerLine}${treeLines}
4326
- `;
4327
- }
4328
- function formatWebSearchTreeBlockForCli(items, colorEnabled) {
4329
- if (items.length === 0) return "";
4330
- const { count, lines } = formatSearchTreeLines(items);
4331
- const titleText = toolLabel("exa_search");
4332
- if (!colorEnabled) {
4333
- const headerLine2 = `\u2022 ${titleText} (${count})
4334
- `;
4335
- const treeLines2 = lines.map((l) => ` ${l.connector}${l.queryText}`).join("\n");
4336
- return `${headerLine2}${treeLines2}
4337
- `;
4338
- }
4339
- const bullet = themeText("\u2022", "chrome", true);
4340
- const title = styleCliText(titleText, "bold", true);
4341
- const countText = themeText(`(${count})`, "muted", true);
4342
- const headerLine = `${bullet} ${title} ${countText}
4343
- `;
4344
- const treeLines = lines.map((l) => {
4345
- const connector = themeText(` ${l.connector}`, "chrome", true);
4346
- const queryText = themeText(l.queryText, "muted", true);
4347
- return `${connector}${queryText}`;
4348
- }).join("\n");
4349
- return `${headerLine}${treeLines}
4350
- `;
4351
- }
4352
- function formatFetchTreeBlockForCli(items, colorEnabled) {
4353
- if (items.length === 0) return "";
4354
- const { count, lines } = formatFetchTreeLines(items);
4355
- const titleText = toolLabel("fetchWebpage");
4356
- if (!colorEnabled) {
4357
- const headerLine2 = `\u2022 ${titleText} (${count})
4358
- `;
4359
- const treeLines2 = lines.map((l) => ` ${l.connector}${l.urlText}`).join("\n");
4360
- return `${headerLine2}${treeLines2}
4361
- `;
4362
- }
4363
- const bullet = themeText("\u2022", "chrome", true);
4364
- const title = styleCliText(titleText, "bold", true);
4365
- const countText = themeText(`(${count})`, "muted", true);
4366
- const headerLine = `${bullet} ${title} ${countText}
4367
- `;
4368
- const treeLines = lines.map((l) => {
4369
- const connector = themeText(` ${l.connector}`, "chrome", true);
4370
- const urlText = themeText(l.urlText, "muted", true);
4371
- return `${connector}${urlText}`;
4372
- }).join("\n");
4373
- return `${headerLine}${treeLines}
4374
- `;
4227
+ return formatToolTraceLine(`\u25B8 ${label} \u2717 ${toolFailureReason(event) || t("toolFailed")}`, colorEnabled, "error");
4228
+ }
4229
+ const gist = normalToolGist(event);
4230
+ const hint = editFileResultHint(event);
4231
+ const statsInline = hint?.inline ? ` ${hint.inline}` : "";
4232
+ const durationInline = formatNormalToolDuration(event.elapsedMs);
4233
+ const tail = durationInline ? ` \u2713 ${durationInline}` : " \u2713";
4234
+ const mainLine = formatToolTraceLine(
4235
+ gist ? `\u25B8 ${label} \xB7 ${gist}${statsInline}${tail}` : `\u25B8 ${label}${statsInline}${tail}`,
4236
+ colorEnabled
4237
+ );
4238
+ if (hint?.detail?.length) {
4239
+ const filePath = typeof event.metadata?.path === "string" ? event.metadata.path : void 0;
4240
+ return `${mainLine}${formatEditDetailBlock(hint.detail, colorEnabled, filePath)}`;
4241
+ }
4242
+ return mainLine;
4243
+ }
4244
+ function toolFailureReason(event) {
4245
+ const metadata = event.metadata ?? {};
4246
+ const rawError = metadata.error ?? metadata.errorMessage;
4247
+ const raw = typeof rawError === "string" && rawError.trim() || event.message?.trim() || typeof event.content === "string" && event.content.trim() || event.summary?.trim() || "";
4248
+ const lines = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
4249
+ const sectionLines = (section) => {
4250
+ const start = lines.findIndex((line) => new RegExp(`^${section}\\s*:$`, "i").test(line));
4251
+ if (start < 0) return [];
4252
+ const end = lines.findIndex((line, index) => index > start && /^(stdout|stderr|exitCode)\s*:/i.test(line));
4253
+ return lines.slice(start + 1, end < 0 ? lines.length : end);
4254
+ };
4255
+ const reasonLine = sectionLines("stderr")[0] ?? sectionLines("stdout")[0] ?? lines.find((line) => !/^(stdout|stderr|exitCode)\s*:/i.test(line)) ?? lines[0] ?? "";
4256
+ return reasonLine ? clip(redactSecrets(stripAnsi2(reasonLine)), 96) : "";
4375
4257
  }
4376
4258
  function resolveLoadSkillName(event) {
4377
4259
  const metaName = typeof event.metadata?.name === "string" ? event.metadata.name : void 0;
@@ -4436,326 +4318,63 @@ function formatLoadSkillBlock(event, colorEnabled, opts) {
4436
4318
  return `${star} ${labelPart}: ${namePart}
4437
4319
  `;
4438
4320
  }
4439
- function formatCompactToolLine(event, pending, colorEnabled) {
4440
- const toolName = event.toolName || pending?.toolName || "tool";
4441
- const todoBlock = formatTodoListForCli(event, colorEnabled);
4442
- if (todoBlock) return todoBlock;
4443
- if (isReadToolName(toolName) && event.type === "tool-result") {
4444
- const rawPath = (typeof event.metadata?.path === "string" ? event.metadata.path : void 0) || (typeof event.metadata?.filePath === "string" ? event.metadata.filePath : void 0) || event.argumentsPreview || pending?.argumentsPreview || "";
4445
- return formatReadTreeBlockForCli([{ path: rawPath, metadata: event.metadata }], colorEnabled);
4446
- }
4447
- if (isSearchToolName(toolName) && event.type === "tool-result") {
4448
- const rawQuery = (typeof event.metadata?.query === "string" ? event.metadata.query : void 0) || (typeof event.metadata?.pattern === "string" ? event.metadata.pattern : void 0) || event.argumentsPreview || pending?.argumentsPreview || "";
4449
- const rawPath = typeof event.metadata?.path === "string" ? event.metadata.path : void 0;
4450
- return formatSearchTreeBlockForCli([{ query: rawQuery, path: rawPath }], colorEnabled);
4451
- }
4452
- if (isFetchToolName(toolName) && event.type === "tool-result") {
4453
- const rawUrl = (typeof event.metadata?.url === "string" ? event.metadata.url : void 0) || event.argumentsPreview || pending?.argumentsPreview || "";
4454
- return formatFetchTreeBlockForCli([{ url: rawUrl }], colorEnabled);
4455
- }
4456
- if (isRunToolName(toolName) && event.type === "tool-result" && isRunResultFoldable(event)) {
4457
- const rawCommand = (typeof event.metadata?.command === "string" ? event.metadata.command : void 0) || event.argumentsPreview || pending?.argumentsPreview || "";
4458
- const exitCode = typeof event.metadata?.exitCode === "number" ? event.metadata.exitCode : void 0;
4459
- const timedOut = Boolean(event.metadata?.timedOut);
4460
- return formatRunTreeBlockForCli([{ command: rawCommand, exitCode, timedOut }], colorEnabled);
4461
- }
4462
- const rawArgs = clipPathAware(event.argumentsPreview || pending?.argumentsPreview || "", 72);
4463
- const rawLabel = toolLabel(toolName);
4464
- const label = rawArgs ? `${rawLabel} ${rawArgs}` : rawLabel;
4465
- if (event.type === "tool-error") {
4466
- const message = clip(event.message ?? t("toolFailed"), 96);
4467
- return formatToolTraceLine(`\u25B8 ${label} \u2717 ${message}`, colorEnabled, "error");
4468
- }
4469
- const loadSkillBlock = formatLoadSkillBlock(event, colorEnabled);
4470
- if (loadSkillBlock) return loadSkillBlock;
4471
- if (event.type === "tool-result" && (toolName === "listAgents" || toolName === "startAgentRun" || toolName === "controlAgentRun")) {
4472
- return formatOrchestrationCardBlock(event, toolName, colorEnabled);
4473
- }
4474
- if (event.type === "tool-result" && (event.toolName === "ask_user" || event.metadata?.uiAskChoice)) {
4475
- const block = formatUiAskChoiceBlock(event, colorEnabled);
4476
- if (block) return block;
4477
- }
4478
- const hint = compactResultHint(event);
4479
- const suffix = hint.inline ? ` ${hint.inline}` : "";
4480
- const failed = isFailedToolResult(event);
4481
- const marker = failed ? "\u2717" : isNeedsActionToolResult(event) ? "!" : "\u2713";
4482
- let mainLine;
4483
- if (!colorEnabled) {
4484
- mainLine = `\u25B8 ${label} ${marker}${suffix}
4485
- `;
4486
- } else {
4487
- const chromePointer = themeText("\u25B8", "chrome", true);
4488
- const mutedLabel = themeText(rawLabel, "muted", true);
4489
- const argsPart = rawArgs ? ` ${dimCliText(rawArgs, true)}` : "";
4490
- const statusToken = failed ? themeText("\u2717", "danger", true) : isNeedsActionToolResult(event) ? themeText("!", "warning", true) : themeText("\u2713", "success", true);
4491
- const suffixPart = hint.inline ? ` ${dimCliText(hint.inline, true)}` : "";
4492
- mainLine = `${chromePointer} ${mutedLabel}${argsPart} ${statusToken}${suffixPart}
4493
- `;
4494
- }
4495
- if (!hint.detail?.length) return mainLine;
4496
- const filePath = typeof event.metadata?.path === "string" ? event.metadata.path : event.argumentsPreview;
4497
- return `${mainLine}${formatEditDetailBlock(hint.detail, colorEnabled, filePath)}`;
4498
- }
4499
- function formatEditDetailBlock(lines, colorEnabled, filePath, env = process.env) {
4500
- if (!colorEnabled) {
4501
- return lines.map((line) => ` ${line.text}
4502
- `).join("");
4503
- }
4504
- const isTruecolor = supportsTruecolor(env);
4505
- const lang = isTruecolor ? detectCodeLangFromPath(filePath) : "unknown";
4506
- const brightness = resolveTuiBrightness(env);
4507
- const padTo = Math.max(...lines.map((line) => displayWidth(line.text))) + 1;
4508
- return lines.map((line) => ` ${renderDiffLine({
4509
- kind: line.kind,
4510
- text: line.text,
4511
- highlightedText: shouldHighlightEditLine(line, lang, isTruecolor) ? buildHighlightedEditLine(line, lang, brightness, env) : void 0,
4512
- padTo,
4513
- colorEnabled: true,
4514
- env
4515
- })}
4516
- `).join("");
4517
- }
4518
- function shouldHighlightEditLine(line, lang, isTruecolor) {
4519
- if (!isTruecolor || lang === "unknown") return false;
4520
- if (line.text.startsWith(" \u2026") || line.text.startsWith("\u2026")) return false;
4521
- return line.text.length >= 2;
4522
- }
4523
- function buildHighlightedEditLine(line, lang, brightness, env) {
4524
- const prefix = line.text.slice(0, 2);
4525
- const body = line.text.slice(2);
4526
- const prefixToken = line.kind === "added" ? "success" : line.kind === "removed" ? "danger" : "chrome";
4527
- const coloredPrefix = themeText(prefix, prefixToken, true, env);
4528
- const highlightedBody = highlightCodeLine(body, lang, brightness);
4529
- return `${coloredPrefix}${highlightedBody}`;
4530
- }
4531
- function createToolEventFormatter(mode, colorEnabled = resolveCliColorEnabled(), opts = {}) {
4532
- const suppressRunProgressCards = opts.suppressRunProgressCards === true;
4321
+ var TUI_TREE_MARKER = "TUI_TREE\n";
4322
+ var TUI_TREE_END = "";
4323
+ function createToolEventFormatter(colorEnabled = resolveCliColorEnabled(), opts = {}) {
4533
4324
  const pending = /* @__PURE__ */ new Map();
4534
- let readBuffer = [];
4535
- let searchBuffer = [];
4536
- let runBuffer = [];
4537
- let fetchBuffer = [];
4538
- let webSearchBuffer = [];
4539
- let statusFold = null;
4540
- const lastEmittedLogByRunId = /* @__PURE__ */ new Map();
4541
- const lastPrintedCardByRunId = /* @__PURE__ */ new Map();
4542
- const cardSubstance = (snapshot) => JSON.stringify([
4543
- snapshot.status,
4544
- snapshot.toolCallCount ?? -1,
4545
- snapshot.lastToolNames ?? [],
4546
- snapshot.lastAssistantText ?? "",
4547
- snapshot.errorMessage ?? "",
4548
- snapshot.logKey
4549
- ]);
4550
- const flushStatusFold = () => {
4551
- if (!statusFold) return "";
4552
- const fold = statusFold;
4553
- statusFold = null;
4554
- const substance = cardSubstance(fold);
4555
- if (lastPrintedCardByRunId.get(fold.runId) === substance) return "";
4556
- const prevLog = lastEmittedLogByRunId.get(fold.runId);
4557
- const changed = Boolean(fold.logKey) && fold.logKey !== prevLog;
4558
- if (suppressRunProgressCards) {
4559
- const terminal = isAgentRunTerminalStatus(fold.status);
4560
- if (!terminal && !fold.errorMessage && !changed) {
4561
- lastPrintedCardByRunId.set(fold.runId, substance);
4562
- return "";
4563
- }
4564
- }
4565
- lastPrintedCardByRunId.set(fold.runId, substance);
4566
- if (changed && runShowsLogTail(fold.status)) {
4567
- lastEmittedLogByRunId.set(fold.runId, fold.logKey);
4568
- }
4569
- return formatFoldedControlStatusCard({ ...fold, includeLogTail: changed }, colorEnabled);
4570
- };
4571
- const flushToolBuffers = () => {
4572
- let out = "";
4573
- if (readBuffer.length > 0) {
4574
- const items = readBuffer.map((evt) => {
4575
- const call = pending.get(evt.toolCallId);
4576
- const rawPath = (typeof evt.metadata?.path === "string" ? evt.metadata.path : void 0) || (typeof evt.metadata?.filePath === "string" ? evt.metadata.filePath : void 0) || evt.argumentsPreview || call?.argumentsPreview || "";
4577
- return { path: rawPath, metadata: evt.metadata };
4578
- });
4579
- for (const evt of readBuffer) pending.delete(evt.toolCallId);
4580
- readBuffer = [];
4581
- out += formatReadTreeBlockForCli(items, colorEnabled);
4582
- }
4583
- if (searchBuffer.length > 0) {
4584
- const items = searchBuffer.map((evt) => {
4585
- const call = pending.get(evt.toolCallId);
4586
- const rawQuery = (typeof evt.metadata?.query === "string" ? evt.metadata.query : void 0) || (typeof evt.metadata?.pattern === "string" ? evt.metadata.pattern : void 0) || evt.argumentsPreview || call?.argumentsPreview || "";
4587
- const rawPath = typeof evt.metadata?.path === "string" ? evt.metadata.path : void 0;
4588
- return { query: rawQuery, path: rawPath };
4589
- });
4590
- for (const evt of searchBuffer) pending.delete(evt.toolCallId);
4591
- searchBuffer = [];
4592
- out += formatSearchTreeBlockForCli(items, colorEnabled);
4593
- }
4594
- if (runBuffer.length > 0) {
4595
- const items = runBuffer.map((evt) => {
4596
- const call = pending.get(evt.toolCallId);
4597
- const rawCommand = (typeof evt.metadata?.command === "string" ? evt.metadata.command : void 0) || evt.argumentsPreview || call?.argumentsPreview || "";
4598
- const exitCode = typeof evt.metadata?.exitCode === "number" ? evt.metadata.exitCode : void 0;
4599
- const timedOut = Boolean(evt.metadata?.timedOut);
4600
- return { command: rawCommand, exitCode, timedOut };
4601
- });
4602
- for (const evt of runBuffer) pending.delete(evt.toolCallId);
4603
- runBuffer = [];
4604
- out += formatRunTreeBlockForCli(items, colorEnabled);
4605
- }
4606
- if (fetchBuffer.length > 0) {
4607
- const items = fetchBuffer.map((evt) => {
4608
- const call = pending.get(evt.toolCallId);
4609
- const rawUrl = (typeof evt.metadata?.url === "string" ? evt.metadata.url : void 0) || evt.argumentsPreview || call?.argumentsPreview || "";
4610
- return { url: rawUrl };
4611
- });
4612
- for (const evt of fetchBuffer) pending.delete(evt.toolCallId);
4613
- fetchBuffer = [];
4614
- out += formatFetchTreeBlockForCli(items, colorEnabled);
4615
- }
4616
- if (webSearchBuffer.length > 0) {
4617
- const items = webSearchBuffer.map((evt) => {
4618
- const call = pending.get(evt.toolCallId);
4619
- const rawQuery = (typeof evt.metadata?.query === "string" ? evt.metadata.query : void 0) || (typeof evt.metadata?.pattern === "string" ? evt.metadata.pattern : void 0) || evt.argumentsPreview || call?.argumentsPreview || "";
4620
- return { query: rawQuery };
4621
- });
4622
- for (const evt of webSearchBuffer) pending.delete(evt.toolCallId);
4623
- webSearchBuffer = [];
4624
- out += formatWebSearchTreeBlockForCli(items, colorEnabled);
4625
- }
4626
- return out;
4627
- };
4628
- const flushBuffers = () => `${flushStatusFold()}${flushToolBuffers()}`;
4629
- const bufferToolResult = (buffer, event) => {
4630
- const flushed = flushStatusFold();
4631
- buffer.push(event);
4632
- return flushed;
4325
+ let tree = null;
4326
+ const treeKind = (name) => isRunToolName(name) ? "Run" : isReadToolName(name) ? "Read" : name === "exa_search" ? "Search" : name === "fetchWebpage" ? "Fetch" : null;
4327
+ const treeLine = (kind, items) => {
4328
+ const label = kind === "Run" ? toolLabel("execShell") : kind === "Read" ? toolLabel("readFile") : kind === "Fetch" ? toolLabel("fetchWebpage") : toolLabel("exa_search");
4329
+ return `${TUI_TREE_MARKER}${label} (${items.length})
4330
+ ${items.map((item, i) => `${i === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 "}${item} \u2713`).join("\n")}${TUI_TREE_END}
4331
+ `;
4633
4332
  };
4634
- const formatter = (event) => {
4635
- if (mode === "hide") return "";
4636
- if (mode === "verbose") return formatVerboseToolEvent(event, colorEnabled);
4637
- if (mode === "normal") {
4638
- if (event.type === "tool-call") {
4639
- pending.set(event.toolCallId, {
4640
- toolName: event.toolName,
4641
- argumentsPreview: event.argumentsPreview
4642
- });
4643
- return "";
4644
- }
4645
- const call2 = pending.get(event.toolCallId);
4646
- pending.delete(event.toolCallId);
4647
- return formatNormalToolLine(event, call2, colorEnabled);
4648
- }
4649
- if (event.toolName === "controlAgentRun") {
4650
- if (event.type === "tool-call") {
4651
- pending.set(event.toolCallId, {
4652
- toolName: event.toolName,
4653
- argumentsPreview: event.argumentsPreview
4654
- });
4655
- return "";
4656
- }
4657
- if (event.type === "tool-result") {
4658
- const snapshot = parseControlAgentRunStatusEvent(event);
4659
- if (snapshot) {
4660
- let out = flushToolBuffers();
4661
- const open = statusFold;
4662
- const sameRun = open?.runId === snapshot.runId;
4663
- if (open && (!sameRun || open.status !== snapshot.status)) {
4664
- out += flushStatusFold();
4665
- }
4666
- statusFold = open && sameRun ? mergeRunSnapshot(open, snapshot) : snapshot;
4667
- pending.delete(event.toolCallId);
4668
- if (isAgentRunTerminalStatus(snapshot.status)) {
4669
- out += flushBuffers();
4670
- }
4671
- return out;
4672
- }
4673
- const flushed2 = flushBuffers();
4674
- const call2 = pending.get(event.toolCallId);
4675
- pending.delete(event.toolCallId);
4676
- return `${flushed2}${formatCompactToolLine(event, call2, colorEnabled)}`;
4677
- }
4678
- }
4679
- if (isReadToolName(event.toolName)) {
4680
- if (event.type === "tool-call") {
4681
- pending.set(event.toolCallId, {
4682
- toolName: event.toolName,
4683
- argumentsPreview: event.argumentsPreview
4684
- });
4685
- return "";
4686
- }
4687
- if (event.type === "tool-result") {
4688
- return bufferToolResult(readBuffer, event);
4689
- }
4690
- }
4691
- if (isSearchToolName(event.toolName)) {
4692
- if (event.type === "tool-call") {
4693
- pending.set(event.toolCallId, {
4694
- toolName: event.toolName,
4695
- argumentsPreview: event.argumentsPreview
4696
- });
4697
- return "";
4698
- }
4699
- if (event.type === "tool-result") {
4700
- return bufferToolResult(searchBuffer, event);
4701
- }
4702
- }
4703
- if (isRunToolName(event.toolName)) {
4704
- if (event.type === "tool-result" && !isRunResultFoldable(event)) {
4705
- const flushed2 = flushBuffers();
4706
- const call2 = pending.get(event.toolCallId);
4707
- pending.delete(event.toolCallId);
4708
- return `${flushed2}${formatCompactToolLine(event, call2, colorEnabled)}`;
4709
- }
4710
- if (event.type === "tool-call") {
4711
- pending.set(event.toolCallId, {
4712
- toolName: event.toolName,
4713
- argumentsPreview: event.argumentsPreview
4714
- });
4715
- return "";
4716
- }
4717
- if (event.type === "tool-result") {
4718
- return bufferToolResult(runBuffer, event);
4719
- }
4720
- }
4721
- if (isFetchToolName(event.toolName)) {
4722
- if (event.type === "tool-call") {
4723
- pending.set(event.toolCallId, {
4724
- toolName: event.toolName,
4725
- argumentsPreview: event.argumentsPreview
4726
- });
4727
- return "";
4728
- }
4729
- if (event.type === "tool-result") {
4730
- return bufferToolResult(fetchBuffer, event);
4731
- }
4333
+ const formatTreeEvent = (event, call) => {
4334
+ if (!opts.tuiTrees || event.type !== "tool-result") return null;
4335
+ if (isFailedToolResult(event) || event.metadata?.failed || event.metadata?.timedOut || readActionGate(event.metadata?.actionGate)) {
4336
+ tree = null;
4337
+ return null;
4732
4338
  }
4733
- if (isWebSearchToolName(event.toolName)) {
4734
- if (event.type === "tool-call") {
4735
- pending.set(event.toolCallId, {
4736
- toolName: event.toolName,
4737
- argumentsPreview: event.argumentsPreview
4738
- });
4739
- return "";
4740
- }
4741
- if (event.type === "tool-result") {
4742
- return bufferToolResult(webSearchBuffer, event);
4743
- }
4339
+ const name = event.toolName || call?.toolName || "tool";
4340
+ const kind = treeKind(name);
4341
+ if (!kind) {
4342
+ tree = null;
4343
+ return null;
4744
4344
  }
4745
- const flushed = flushBuffers();
4345
+ let item = "";
4346
+ const m = event.metadata ?? {};
4347
+ if (kind === "Run") {
4348
+ const command = typeof m.command === "string" ? m.command : "";
4349
+ item = command ? formatRunItemCommand(command, typeof m.exitCode === "number" ? m.exitCode : void 0, Boolean(m.timedOut)) : "command";
4350
+ }
4351
+ if (kind === "Read") item = formatReadItemPath(typeof m.path === "string" ? m.path : typeof m.filePath === "string" ? m.filePath : "file", m);
4352
+ if (kind === "Search") item = formatSearchItemQuery(typeof m.query === "string" ? m.query : typeof m.pattern === "string" ? m.pattern : "search", typeof m.path === "string" ? m.path : void 0);
4353
+ if (kind === "Fetch") item = formatFetchItemUrl(typeof m.url === "string" ? m.url : "webpage");
4354
+ item = withholdIfSecretLike(item) || toolLabel(name);
4355
+ if (tree?.kind !== kind) tree = { kind, items: [] };
4356
+ tree.items.push(item);
4357
+ if (tree.items.length < 2) return formatNormalToolLine(event, call, colorEnabled);
4358
+ return treeLine(kind, tree.items);
4359
+ };
4360
+ const format = (event) => {
4746
4361
  if (event.type === "tool-call") {
4747
4362
  pending.set(event.toolCallId, {
4748
4363
  toolName: event.toolName,
4749
4364
  argumentsPreview: event.argumentsPreview
4750
4365
  });
4751
- return flushed;
4366
+ return "";
4752
4367
  }
4753
4368
  const call = pending.get(event.toolCallId);
4754
4369
  pending.delete(event.toolCallId);
4755
- return `${flushed}${formatCompactToolLine(event, call, colorEnabled)}`;
4370
+ const treeOutput = formatTreeEvent(event, call);
4371
+ if (treeOutput !== null) return treeOutput;
4372
+ return formatNormalToolLine(event, call, colorEnabled);
4373
+ };
4374
+ format.reset = () => {
4375
+ tree = null;
4756
4376
  };
4757
- formatter.flush = flushBuffers;
4758
- return formatter;
4377
+ return format;
4759
4378
  }
4760
4379
  function createSseToolEventAdapter(onEvent) {
4761
4380
  let round = 0;
@@ -4973,10 +4592,8 @@ function createCliTurnOutput(params) {
4973
4592
  const { options } = params;
4974
4593
  const workingLabel = params.workingLabel ?? `${options.agentName} -> working`;
4975
4594
  const spinner = params.spinner ?? new Spinner(options.output, workingLabel, Boolean(options.activityReporter));
4976
- const toolDisplayMode = resolveToolDisplayMode(options.env);
4977
- const traceLocalTools = shouldEmitToolEvents(toolDisplayMode);
4978
- const formatToolEvent = createToolEventFormatter(toolDisplayMode, void 0, {
4979
- suppressRunProgressCards: typeof options.onAgentRunStatus === "function"
4595
+ const formatToolEvent = createToolEventFormatter(void 0, {
4596
+ tuiTrees: options.output.tuiTrees === true
4980
4597
  });
4981
4598
  const eventMode = resolveAgentEventMode(options);
4982
4599
  const showThinking = options.showThinking !== false;
@@ -4995,6 +4612,7 @@ function createCliTurnOutput(params) {
4995
4612
  if (thinkingFirstAt === null) return;
4996
4613
  const seconds = Math.max(0, Math.round((thinkingLastAt - thinkingFirstAt) / 1e3));
4997
4614
  thinkingFirstAt = null;
4615
+ if (seconds < 1) return;
4998
4616
  options.output.write(`${dimCliText(t("thinkingTraceLine", formatElapsed(seconds)))}
4999
4617
  `);
5000
4618
  };
@@ -5003,7 +4621,7 @@ function createCliTurnOutput(params) {
5003
4621
  const writeToolOutput = (chunk) => {
5004
4622
  if (!chunk) return;
5005
4623
  if (typeof options.output.writeToolBlock === "function") {
5006
- options.output.writeToolBlock(chunk);
4624
+ if (!options.output.writeToolBlock(chunk)) formatToolEvent.reset?.();
5007
4625
  } else {
5008
4626
  options.output.write(chunk);
5009
4627
  }
@@ -5013,6 +4631,7 @@ function createCliTurnOutput(params) {
5013
4631
  });
5014
4632
  const writeVisibleAssistantChunk = (chunk) => {
5015
4633
  if (!chunk) return;
4634
+ formatToolEvent.reset?.();
5016
4635
  const parsed = processThinkChunk(chunk, thinkState);
5017
4636
  thinkState = parsed.state;
5018
4637
  if (!parsed.content && !parsed.reasoning) return;
@@ -5036,7 +4655,6 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
5036
4655
  renderWriter.push(parsed.content);
5037
4656
  };
5038
4657
  const handleToolEvent = (event) => {
5039
- if (!traceLocalTools) return;
5040
4658
  const chunk = eventMode === "jsonl" ? formatToolJsonEvent(event) : formatToolEvent(event);
5041
4659
  if (eventMode === "jsonl") {
5042
4660
  options.output.write(chunk);
@@ -5054,8 +4672,8 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
5054
4672
  if (chunk) {
5055
4673
  writeToolOutput(chunk);
5056
4674
  }
5057
- if ((toolDisplayMode === "compact" || toolDisplayMode === "pro" || toolDisplayMode === "normal") && event.type === "tool-call") {
5058
- const activeLabel = toolDisplayMode === "normal" ? formatConservativeActiveToolLabel(event) : formatActiveToolLabel(event);
4675
+ if (event.type === "tool-call") {
4676
+ const activeLabel = formatConservativeActiveToolLabel(event);
5059
4677
  spinner.show(activeLabel);
5060
4678
  options.activityReporter?.(activeLabel);
5061
4679
  }
@@ -5068,16 +4686,8 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
5068
4686
  };
5069
4687
  return {
5070
4688
  spinner,
5071
- toolDisplayMode,
5072
- traceLocalTools,
5073
4689
  eventMode,
5074
4690
  pushText(chunk) {
5075
- if (eventMode !== "jsonl" && formatToolEvent.flush) {
5076
- const pendingToolOutput = formatToolEvent.flush();
5077
- if (pendingToolOutput) {
5078
- writeToolOutput(pendingToolOutput);
5079
- }
5080
- }
5081
4691
  writeVisibleAssistantChunk(chunk);
5082
4692
  },
5083
4693
  pushThinking(chunk) {
@@ -5105,10 +4715,6 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
5105
4715
  if (flushedThink.content) {
5106
4716
  writeVisibleAssistantChunk(flushedThink.content);
5107
4717
  }
5108
- const pendingToolOutput = formatToolEvent.flush ? formatToolEvent.flush() : "";
5109
- if (pendingToolOutput) {
5110
- writeToolOutput(pendingToolOutput);
5111
- }
5112
4718
  if (streamedAssistantText) {
5113
4719
  renderWriter.flush();
5114
4720
  options.output.write("\n");
@@ -5309,10 +4915,12 @@ ${describeClientVersionTooOldFailure(message, error)}`);
5309
4915
  if (usageText && shouldShowUsage(options.env))
5310
4916
  options.output.write(`${usageText}
5311
4917
  `);
4918
+ const turnCredits = platformCreditsFromUsage(usage);
5312
4919
  return {
5313
4920
  exitCode: 0,
5314
4921
  ...dialogId ? { dialogId } : {},
5315
- turnTokens: buildTurnTokenUsage(usage, options.agentKey)
4922
+ turnTokens: buildTurnTokenUsage(usage, options.agentKey),
4923
+ ...turnCredits !== void 0 ? { turnCredits } : {}
5316
4924
  };
5317
4925
  }
5318
4926
 
@@ -5592,10 +5200,14 @@ function findCollapsedPasteSpanAt(buffer, pos, opts = {}) {
5592
5200
  // packages/cli/client/agentRun.ts
5593
5201
  import { ulid } from "ulid";
5594
5202
  async function loadRunLocalAgentTurn() {
5595
- const { runLocalAgentTurn } = await import("./agentRuntimeLocal-PCJJ56J2.js");
5203
+ const { runLocalAgentTurn } = await import("./agentRuntimeLocal-K327ELSL.js");
5596
5204
  return runLocalAgentTurn;
5597
5205
  }
5598
5206
  var stripDebugNoise = (s) => s.replace(/\s*raw="[\s\S]*"/g, "").replace(/\s*raw=\S+/g, "").replace(/\s*headers=\[[^\]]*\]/g, "").replace(/\s*headers=\S+/g, "").trim();
5207
+ var pickEmptyAssistantFlags = (result) => ({
5208
+ ...result.emptyAssistantFallbackReason ? { emptyAssistantFallbackReason: result.emptyAssistantFallbackReason } : {},
5209
+ ...result.emptyAssistantOutputUsable ? { emptyAssistantOutputUsable: true } : {}
5210
+ });
5599
5211
  function extractEmbeddedErrorMessage(message) {
5600
5212
  const match = /"message"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(message);
5601
5213
  if (!match) return void 0;
@@ -6133,13 +5745,17 @@ ${options.agentName} > (no text response)
6133
5745
  const usage = formatUsage(data?.usage, data?.dialogId);
6134
5746
  if (usage && shouldShowUsage(options.env)) options.output.write(`${usage}
6135
5747
  `);
5748
+ const turnCredits = platformCreditsFromUsage(
5749
+ data?.usage
5750
+ );
6136
5751
  return {
6137
5752
  exitCode: 0,
6138
5753
  ...typeof data?.dialogId === "string" && data.dialogId ? { dialogId: data.dialogId } : {},
6139
5754
  turnTokens: buildTurnTokenUsage(
6140
5755
  data?.usage,
6141
5756
  typeof data?.model === "string" ? data.model : options.agentKey
6142
- )
5757
+ ),
5758
+ ...turnCredits !== void 0 ? { turnCredits } : {}
6143
5759
  };
6144
5760
  }
6145
5761
  async function runInjectedLocalAgentTurn(options) {
@@ -6244,11 +5860,13 @@ async function runLocalAgentTurnForCli(options, settings) {
6244
5860
  options.onLoopEvent?.(event);
6245
5861
  },
6246
5862
  ...options.abortSignal ? { abortSignal: options.abortSignal } : {},
6247
- ...turnOutput.traceLocalTools ? {
6248
- onToolEvent: (event) => {
6249
- turnOutput.handleToolEvent(event);
6250
- }
6251
- } : {},
5863
+ // 回合内注入(TUI 后台 run 唤醒直投):透传给 local loop。
5864
+ ...options.drainInjections ? { drainInjections: options.drainInjections } : {},
5865
+ // tool-gist-fold 后 onToolEvent 无条件挂载(不再受 traceLocalTools 开关
5866
+ // 控制,显示模式合并为单一 gist/折叠通道)——保留 alpha 的新形态。
5867
+ onToolEvent: (event) => {
5868
+ turnOutput.handleToolEvent(event);
5869
+ },
6252
5870
  ...!options.noStream ? {
6253
5871
  onTextDelta: (chunk) => {
6254
5872
  turnOutput.pushText(chunk);
@@ -6259,24 +5877,35 @@ async function runLocalAgentTurnForCli(options, settings) {
6259
5877
  } : {}
6260
5878
  });
6261
5879
  turnOutput.finish(result.content);
5880
+ const turnCredits = sumPlatformCredits(result.usageRecords);
6262
5881
  return {
6263
5882
  exitCode: 0,
6264
5883
  dialogId: result.dialogId,
6265
5884
  title: result.title,
6266
5885
  ...result.titlePatchPromise ? { titlePatchPromise: result.titlePatchPromise } : {},
6267
- ...result.emptyAssistantFallbackReason ? { emptyAssistantFallbackReason: result.emptyAssistantFallbackReason } : {},
6268
- turnTokens: buildTurnTokenUsage(result.usage, result.model)
5886
+ ...pickEmptyAssistantFlags(result),
5887
+ // 积分口径按「全轮」而非「最后一次调用」:result.usage 只是收尾那次
5888
+ // provider 调用的 usage,本轮前面 N-1 次工具循环调用(以及自动压缩摘要)
5889
+ // 的 cost 都只存在于 usageRecords 里。token 字段仍取 result.usage——
5890
+ // 上下文占用本来就该看最后一次调用的累计输入,不是各次相加。
5891
+ turnTokens: withTurnCredits(buildTurnTokenUsage(result.usage, result.model), turnCredits),
5892
+ ...turnCredits !== void 0 ? { turnCredits } : {},
5893
+ ...result.usageRecords?.length ? { usageRecords: result.usageRecords } : {}
6269
5894
  };
6270
5895
  } catch (error) {
6271
5896
  turnOutput.spinner.stop();
6272
5897
  const savedDialogId = error?.dialogId;
5898
+ const abortedUsageRecords = error?.usageRecords;
5899
+ const abortedTurnCredits = sumPlatformCredits(abortedUsageRecords);
6273
5900
  if (error?.code === LOCAL_TURN_ABORTED_CODE || options.abortSignal?.aborted) {
6274
5901
  const pendingToolName = error?.pendingToolName;
6275
5902
  return {
6276
5903
  exitCode: 0,
6277
5904
  streamInterrupted: true,
6278
5905
  ...savedDialogId ? { dialogId: savedDialogId } : {},
6279
- ...pendingToolName ? { pendingToolName } : {}
5906
+ ...pendingToolName ? { pendingToolName } : {},
5907
+ ...abortedTurnCredits !== void 0 ? { turnCredits: abortedTurnCredits } : {},
5908
+ ...abortedUsageRecords?.length ? { usageRecords: abortedUsageRecords } : {}
6280
5909
  };
6281
5910
  }
6282
5911
  const cooldownUntil = await markStartupRateLimitCooldown(
@@ -6302,10 +5931,70 @@ async function runLocalAgentTurnForCli(options, settings) {
6302
5931
  return {
6303
5932
  exitCode: 1,
6304
5933
  localError: error,
6305
- ...savedDialogId ? { dialogId: savedDialogId } : {}
5934
+ ...savedDialogId ? { dialogId: savedDialogId } : {},
5935
+ ...abortedTurnCredits !== void 0 ? { turnCredits: abortedTurnCredits } : {},
5936
+ ...abortedUsageRecords?.length ? { usageRecords: abortedUsageRecords } : {}
6306
5937
  };
6307
5938
  }
6308
5939
  }
5940
+ async function checkLocalAvailabilityBeforeHttpDispatch(options) {
5941
+ const adapter = resolveLocalRuntimeAdapter(options);
5942
+ if (!adapter || typeof adapter.loadAgentConfig !== "function") return null;
5943
+ let config;
5944
+ try {
5945
+ config = await adapter.loadAgentConfig(options.agentKey);
5946
+ } catch {
5947
+ return null;
5948
+ }
5949
+ if (!config || typeof config !== "object") return null;
5950
+ const baseRecord = config.rawRecord ?? config;
5951
+ const credentialKey = resolveCredentialKeyWithFallback(baseRecord);
5952
+ const agentLevelAt = baseRecord.nextAvailableAt;
5953
+ const agentLevelNextAvailableAt = typeof agentLevelAt === "number" && Number.isFinite(agentLevelAt) ? agentLevelAt : void 0;
5954
+ if (!credentialKey && agentLevelNextAvailableAt === void 0) return null;
5955
+ const env = options.env;
5956
+ const now = Date.now();
5957
+ const entry = credentialKey ? await readCredentialEntry(credentialKey, env, now).catch(() => void 0) : void 0;
5958
+ const entryAt = entry?.nextAvailableAt;
5959
+ const effectiveNextAvailableAt = typeof entryAt === "number" ? mergeAvailabilityDeadline(agentLevelNextAvailableAt, entryAt) : agentLevelNextAvailableAt;
5960
+ if (typeof effectiveNextAvailableAt !== "number") return null;
5961
+ const gateDecision = resolveCooldownGate(
5962
+ { nextAvailableAt: effectiveNextAvailableAt, lastProbeAt: entry?.lastProbeAt },
5963
+ now
5964
+ );
5965
+ if (gateDecision === "probe" && credentialKey) {
5966
+ await recordCredentialProbe(credentialKey, env, now).catch(() => void 0);
5967
+ return null;
5968
+ }
5969
+ if (gateDecision !== "blocked") return null;
5970
+ options.output.write(
5971
+ `[nolo] Agent ${options.agentName || options.agentKey} is temporarily unavailable (429 cooldown) until ${new Date(Number(effectiveNextAvailableAt)).toISOString()}.
5972
+ Dispatch aborted before reaching the server. Pick another agent via listAgents, or retry after the cooldown.
5973
+ `
5974
+ );
5975
+ return { exitCode: 1 };
5976
+ }
5977
+ function foldLocalResultForTui(localResult) {
5978
+ return {
5979
+ exitCode: localResult.exitCode,
5980
+ ...localResult.dialogId ? { dialogId: localResult.dialogId } : {},
5981
+ title: localResult.title,
5982
+ ...localResult.titlePatchPromise ? { titlePatchPromise: localResult.titlePatchPromise } : {},
5983
+ // 空 assistant 兜底成因必须随行:后台 run 的结算(resolveRunOutcome 的
5984
+ // isStalledOrTruncated)靠它把截断轮判成 stalled 而不是 clean 失败。
5985
+ ...pickEmptyAssistantFlags(localResult),
5986
+ ...localResult.turnTokens ? { turnTokens: localResult.turnTokens } : {},
5987
+ // 平台积分必须随行:runLocalAgentTurnForCli 里 sumPlatformCredits 已按
5988
+ // 「全轮逐次求和」算好(只认 billing_unit === "credits" 的平台计费帧)。
5989
+ ...localResult.turnCredits !== void 0 ? { turnCredits: localResult.turnCredits } : {},
5990
+ // 逐帧用量明细必须随行:cli-local 计费走 fail-open 客户端记账,服务端没有
5991
+ // 逐帧记录,TUI 计费审计(appendTurnBillingAudit)要靠它对账。白名单历史上
5992
+ // 漏过 turnCredits(fix/tui-session-credits),usageRecords 是同坑位新字段。
5993
+ ...localResult.usageRecords?.length ? { usageRecords: localResult.usageRecords } : {},
5994
+ ...localResult.streamInterrupted ? { streamInterrupted: localResult.streamInterrupted } : {},
5995
+ ...localResult.pendingToolName ? { pendingToolName: localResult.pendingToolName } : {}
5996
+ };
5997
+ }
6309
5998
  async function runAgentTurn(options) {
6310
5999
  const authToken = resolveAuthToken2(options.env);
6311
6000
  const runtimeMode = resolveRequestedRuntimeMode(options);
@@ -6319,15 +6008,7 @@ async function runAgentTurn(options) {
6319
6008
  reportFailure: false
6320
6009
  });
6321
6010
  if (localResult.exitCode === 0) {
6322
- return {
6323
- exitCode: localResult.exitCode,
6324
- ...localResult.dialogId ? { dialogId: localResult.dialogId } : {},
6325
- title: localResult.title,
6326
- ...localResult.titlePatchPromise ? { titlePatchPromise: localResult.titlePatchPromise } : {},
6327
- ...localResult.turnTokens ? { turnTokens: localResult.turnTokens } : {},
6328
- ...localResult.streamInterrupted ? { streamInterrupted: localResult.streamInterrupted } : {},
6329
- ...localResult.pendingToolName ? { pendingToolName: localResult.pendingToolName } : {}
6330
- };
6011
+ return foldLocalResultForTui(localResult);
6331
6012
  }
6332
6013
  if (isMissingLocalAgentConfigError(localResult.localError, options.agentKey)) {
6333
6014
  options.output.write(
@@ -6341,13 +6022,7 @@ async function runAgentTurn(options) {
6341
6022
  reportFailure: false
6342
6023
  });
6343
6024
  if (retriedLocalResult.exitCode === 0) {
6344
- return {
6345
- exitCode: retriedLocalResult.exitCode,
6346
- ...retriedLocalResult.dialogId ? { dialogId: retriedLocalResult.dialogId } : {},
6347
- title: retriedLocalResult.title,
6348
- ...retriedLocalResult.titlePatchPromise ? { titlePatchPromise: retriedLocalResult.titlePatchPromise } : {},
6349
- ...retriedLocalResult.turnTokens ? { turnTokens: retriedLocalResult.turnTokens } : {}
6350
- };
6025
+ return foldLocalResultForTui(retriedLocalResult);
6351
6026
  }
6352
6027
  }
6353
6028
  } catch {
@@ -6360,7 +6035,11 @@ async function runAgentTurn(options) {
6360
6035
  ...localResult.dialogId ? { dialogId: localResult.dialogId } : {},
6361
6036
  // Keep localError so TUI can show balance/quota/dialog-preserved hints
6362
6037
  // instead of only the raw auto-runtime line.
6363
- ...localResult.localError ? { localError: localResult.localError } : {}
6038
+ ...localResult.localError ? { localError: localResult.localError } : {},
6039
+ // 失败轮同样可能已发生平台计费(abort/失败照样扣费):turnCredits 与
6040
+ // 逐帧明细一起随行,否则审计日志在 auto 失败路径上缺账。
6041
+ ...localResult.turnCredits !== void 0 ? { turnCredits: localResult.turnCredits } : {},
6042
+ ...localResult.usageRecords?.length ? { usageRecords: localResult.usageRecords } : {}
6364
6043
  };
6365
6044
  }
6366
6045
  }
@@ -6370,26 +6049,50 @@ async function runAgentTurn(options) {
6370
6049
  );
6371
6050
  return { exitCode: 1 };
6372
6051
  }
6052
+ const localBlock = await checkLocalAvailabilityBeforeHttpDispatch(options);
6053
+ if (localBlock) {
6054
+ return { exitCode: localBlock.exitCode };
6055
+ }
6373
6056
  return runHttpAgentTurn(options, authToken);
6374
6057
  }
6375
6058
 
6376
6059
  // packages/cli/agentRunCommand.ts
6377
6060
  import * as nodeFs from "node:fs";
6378
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
6379
- import { join as join2 } from "node:path";
6380
6061
 
6381
6062
  // packages/cli/client/autoModelRouter.ts
6382
6063
  var CLI_AUTO_ROUTE_AGENT_KEY = BUILTIN_NOLO_AGENT_KEY;
6383
6064
 
6065
+ // packages/agent-runtime/agentsMd.ts
6066
+ import { existsSync, readFileSync } from "node:fs";
6067
+ import { join } from "node:path";
6068
+ var AGENTS_MD_MAX_BYTES = 8192;
6069
+ var AGENTS_MD_CANDIDATES = ["AGENTS.md", "CLAUDE.md"];
6070
+ function readAgentsMdLayerFromDisk(cwd) {
6071
+ for (const name of AGENTS_MD_CANDIDATES) {
6072
+ const filePath = join(cwd, name);
6073
+ if (!existsSync(filePath)) continue;
6074
+ try {
6075
+ let content = readFileSync(filePath, "utf8").trim();
6076
+ if (!content) continue;
6077
+ if (Buffer.byteLength(content, "utf8") > AGENTS_MD_MAX_BYTES) {
6078
+ content = Buffer.from(content, "utf8").subarray(0, AGENTS_MD_MAX_BYTES).toString("utf8") + "\n\n<!-- AGENTS.md truncated -->";
6079
+ }
6080
+ return buildAgentsMdLayer(content, name);
6081
+ } catch {
6082
+ }
6083
+ }
6084
+ return null;
6085
+ }
6086
+
6384
6087
  // packages/cli/agentRunPrompts.ts
6385
- import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
6386
- import { dirname, extname, isAbsolute, join, relative as relativePath, resolve, sep } from "node:path";
6088
+ import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync, statSync } from "node:fs";
6089
+ import { dirname, extname, isAbsolute, join as join2, relative as relativePath, resolve, sep } from "node:path";
6387
6090
  function workflowRefToCandidatePath(cwd, ref) {
6388
6091
  const normalized = ref.trim();
6389
6092
  if (!normalized) return "";
6390
6093
  if (normalized.endsWith(".md") || normalized.includes("/") || normalized.includes("\\")) {
6391
6094
  const directPath = resolve(cwd, normalized);
6392
- if (existsSync(directPath)) return directPath;
6095
+ if (existsSync2(directPath)) return directPath;
6393
6096
  }
6394
6097
  const fileName = normalized.replace(/[^a-zA-Z0-9一-鿿]+/g, "-").replace(/^-+|-+$/g, "");
6395
6098
  return resolve(cwd, "docs", "workflows", `${fileName}.md`);
@@ -6402,21 +6105,21 @@ function skillRefToCandidatePath(cwd, ref) {
6402
6105
  if (!normalized) return "";
6403
6106
  if (normalized.endsWith(".md") || normalized.includes("/") || normalized.includes("\\")) {
6404
6107
  const directPath = resolve(cwd, normalized);
6405
- if (existsSync(directPath)) return directPath;
6108
+ if (existsSync2(directPath)) return directPath;
6406
6109
  }
6407
6110
  const fileName = normalized.replace(/[^a-zA-Z0-9一-鿿]+/g, "-").replace(/^-+|-+$/g, "");
6408
6111
  for (const dir of SKILL_SEARCH_DIRS) {
6409
6112
  const skillMdPath = resolve(cwd, dir, fileName, "SKILL.md");
6410
- if (existsSync(skillMdPath)) return skillMdPath;
6113
+ if (existsSync2(skillMdPath)) return skillMdPath;
6411
6114
  }
6412
6115
  return resolve(cwd, ".agents", "skills", fileName, "SKILL.md");
6413
6116
  }
6414
6117
  async function resolveWorkflowReference(ref, cwd = process.cwd()) {
6415
6118
  const path = workflowRefToCandidatePath(cwd, ref);
6416
- if (!path || !existsSync(path)) {
6119
+ if (!path || !existsSync2(path)) {
6417
6120
  throw new Error(`Workflow reference not found: ${ref}`);
6418
6121
  }
6419
- const markdown = readFileSync(path, "utf8");
6122
+ const markdown = readFileSync2(path, "utf8");
6420
6123
  const parsed = parseSkillDocProtocol(markdown);
6421
6124
  return {
6422
6125
  ref,
@@ -6433,8 +6136,8 @@ function inlineRelativeRefs(body, skillDir) {
6433
6136
  const absPath = resolve(skillDir, cleaned);
6434
6137
  const relative = relativePath(normalizedSkillDir, absPath);
6435
6138
  if (relative.startsWith("..") || isAbsolute(relative)) return match;
6436
- if (!existsSync(absPath) || !absPath.endsWith(".md")) return match;
6437
- const refContent = readFileSync(absPath, "utf8");
6139
+ if (!existsSync2(absPath) || !absPath.endsWith(".md")) return match;
6140
+ const refContent = readFileSync2(absPath, "utf8");
6438
6141
  return `
6439
6142
 
6440
6143
  ### ${label}
@@ -6445,8 +6148,8 @@ ${refContent}
6445
6148
  });
6446
6149
  }
6447
6150
  function listSkillScripts(skillDir) {
6448
- const scriptsDir = join(skillDir, "scripts");
6449
- if (!existsSync(scriptsDir) || !statSync(scriptsDir).isDirectory()) return null;
6151
+ const scriptsDir = join2(skillDir, "scripts");
6152
+ if (!existsSync2(scriptsDir) || !statSync(scriptsDir).isDirectory()) return null;
6450
6153
  const entries = readdirSync(scriptsDir).filter((e) => !e.startsWith("."));
6451
6154
  if (entries.length === 0) return null;
6452
6155
  return [
@@ -6473,10 +6176,10 @@ async function resolveSkillReference(ref, options = {}) {
6473
6176
  } else {
6474
6177
  const cwd = options.cwd ?? process.cwd();
6475
6178
  const path = skillRefToCandidatePath(cwd, ref);
6476
- if (!path || !existsSync(path)) {
6179
+ if (!path || !existsSync2(path)) {
6477
6180
  throw new Error(`Skill reference not found: ${ref}`);
6478
6181
  }
6479
- markdown = readFileSync(path, "utf8");
6182
+ markdown = readFileSync2(path, "utf8");
6480
6183
  filePath = path;
6481
6184
  skillDir = dirname(path);
6482
6185
  }
@@ -6581,8 +6284,8 @@ function prependSubjectDialogMarker(message, subjectDialogKey) {
6581
6284
  function normalizeCliImageInput(input) {
6582
6285
  if (/^(https?:|data:|file:)/i.test(input)) return input;
6583
6286
  const absolutePath = resolve(input);
6584
- if (!existsSync(absolutePath)) return input;
6585
- const base64 = readFileSync(absolutePath).toString("base64");
6287
+ if (!existsSync2(absolutePath)) return input;
6288
+ const base64 = readFileSync2(absolutePath).toString("base64");
6586
6289
  return `data:${imageMimeTypeForPath(absolutePath)};base64,${base64}`;
6587
6290
  }
6588
6291
  function imageMimeTypeForPath(path) {
@@ -6665,6 +6368,19 @@ var touchMemoryItemsInDb = async (db, items, now = (/* @__PURE__ */ new Date()).
6665
6368
  // packages/ai/memory/constants.ts
6666
6369
  var EXPLICIT_REMEMBER_PREFIX_REGEX = /^(你要记住|请记住|以后记住|记住)[,,。.\s::]*/u;
6667
6370
 
6371
+ // packages/ai/memory/source.ts
6372
+ var getMemorySourceKind = (item) => {
6373
+ if (item.sourceKind) return item.sourceKind;
6374
+ if (item.patternKey === "explicit-remember") return "explicit-user-directive";
6375
+ if (item.patternKey === "agent-remember" || item.patternKey === "procedural-runbook")
6376
+ return "agent-tool";
6377
+ if (item.patternKey?.startsWith("dialog-learning:"))
6378
+ return "dialog-learning";
6379
+ if (item.tags?.includes("understanding-memory"))
6380
+ return "inferred-understanding";
6381
+ return "agent-tool";
6382
+ };
6383
+
6668
6384
  // packages/ai/memory/overlay.ts
6669
6385
  var KIND_TITLES = {
6670
6386
  episodic: "Episodic",
@@ -6698,6 +6414,8 @@ var FACET_DISPLAY = {
6698
6414
  style: { label: "\u66F4\u504F\u597D", strip: "\u66F4\u559C\u6B22" },
6699
6415
  goal: { label: "\u60F3\u63A8\u8FDB", strip: "\u60F3\u63A8\u8FDB" }
6700
6416
  };
6417
+ var INFERRED_SOURCE_KINDS = /* @__PURE__ */ new Set(["inferred-understanding", "dialog-learning"]);
6418
+ var isInferredMemory = (item) => INFERRED_SOURCE_KINDS.has(getMemorySourceKind(item));
6701
6419
  var formatFacetContent = (facet, normalized, prefix) => {
6702
6420
  const { label, strip } = FACET_DISPLAY[facet];
6703
6421
  const stripped = normalized.startsWith(strip) ? normalized.slice(strip.length).trim() : normalized;
@@ -6719,9 +6437,79 @@ var normalizeDisplayContent = (item) => {
6719
6437
  }
6720
6438
  return normalized;
6721
6439
  };
6440
+ var pickWithinKind = (list, perKindLimit) => {
6441
+ if (perKindLimit <= 0) return [];
6442
+ const head = list.slice(0, perKindLimit);
6443
+ if (head.length < perKindLimit) return head;
6444
+ if (head.some((item) => item.subjectType === "user")) return head;
6445
+ const firstUserSubject = list.find((item) => item.subjectType === "user");
6446
+ if (!firstUserSubject) return head;
6447
+ return [...head.slice(0, perKindLimit - 1), firstUserSubject];
6448
+ };
6449
+ var DEFAULT_MEMORY_OVERLAY_TOKEN_BUDGET = 3200;
6450
+ var MIN_TRUNCATED_TOKENS = 20;
6451
+ var TRUNCATED_SUFFIX = "\u2026\uFF08\u672C\u6761\u5DF2\u622A\u65AD\uFF09";
6452
+ var truncateLineToTokens = (lineText, budgetTokens) => {
6453
+ if (budgetTokens < MIN_TRUNCATED_TOKENS) return null;
6454
+ const suffixTokens = estimateTokens(TRUNCATED_SUFFIX);
6455
+ const bodyBudget = budgetTokens - suffixTokens;
6456
+ if (bodyBudget < MIN_TRUNCATED_TOKENS / 2) return null;
6457
+ let used = 0;
6458
+ let cut = 0;
6459
+ for (const ch of lineText) {
6460
+ const chTokens = estimateTokens(ch);
6461
+ if (used + chTokens > bodyBudget) break;
6462
+ used += chTokens;
6463
+ cut += ch.length;
6464
+ }
6465
+ if (cut <= 2) return null;
6466
+ return `${lineText.slice(0, cut).trimEnd()}${TRUNCATED_SUFFIX}`;
6467
+ };
6468
+ var fitLinesToBudget = (allLines, remainingBudget) => {
6469
+ let usedTokens = 0;
6470
+ const keptByKind = {};
6471
+ let truncatedCount = 0;
6472
+ let droppedCount = 0;
6473
+ const pushLine = (kind, lineText) => {
6474
+ if (!keptByKind[kind]) keptByKind[kind] = [];
6475
+ keptByKind[kind].push(lineText);
6476
+ };
6477
+ for (const candidate of allLines) {
6478
+ const remaining = remainingBudget - usedTokens;
6479
+ if (remaining <= 0) {
6480
+ droppedCount += 1;
6481
+ continue;
6482
+ }
6483
+ if (candidate.lineTokens <= remaining) {
6484
+ usedTokens += candidate.lineTokens;
6485
+ pushLine(candidate.kind, candidate.lineText);
6486
+ continue;
6487
+ }
6488
+ const truncated = truncateLineToTokens(candidate.lineText, remaining);
6489
+ if (!truncated) {
6490
+ droppedCount += 1;
6491
+ continue;
6492
+ }
6493
+ usedTokens += estimateTokens(truncated);
6494
+ pushLine(candidate.kind, truncated);
6495
+ truncatedCount += 1;
6496
+ }
6497
+ return { keptByKind, truncatedCount, droppedCount };
6498
+ };
6499
+ var buildBudgetFooter = (fit) => {
6500
+ const notices = [];
6501
+ if (fit.truncatedCount > 0) {
6502
+ notices.push(`${fit.truncatedCount} \u6761\u56E0\u9884\u7B97\u88AB\u622A\u65AD`);
6503
+ }
6504
+ if (fit.droppedCount > 0) {
6505
+ notices.push(`${fit.droppedCount} \u6761\u672A\u663E\u793A`);
6506
+ }
6507
+ if (notices.length === 0) return [];
6508
+ return [`\uFF08${notices.join("\u3001")}\uFF1B\u9700\u8981\u5B8C\u6574\u5185\u5BB9\u6216\u66F4\u591A\u76F8\u5173\u8BB0\u5FC6\u65F6\u7528 queryMemory \u68C0\u7D22\uFF09`];
6509
+ };
6722
6510
  var buildMemoryOverlay = (items, options) => {
6723
6511
  if (items.length === 0) return null;
6724
- const maxTokens = options?.maxTokens ?? 2e3;
6512
+ const maxTokens = options?.maxTokens ?? DEFAULT_MEMORY_OVERLAY_TOKEN_BUDGET;
6725
6513
  const perKindLimit = options?.perKindLimit ?? 3;
6726
6514
  const byKind = {
6727
6515
  episodic: [],
@@ -6736,19 +6524,15 @@ var buildMemoryOverlay = (items, options) => {
6736
6524
  return OVERLAY_HEADER_LINES.join("\n");
6737
6525
  }
6738
6526
  const allLines = Object.entries(byKind).filter(([, list]) => list.length > 0).flatMap(
6739
- ([kind, list]) => list.slice(0, perKindLimit).map((item) => {
6740
- const lineText = `- ${normalizeDisplayContent(item)}`;
6527
+ ([kind, list]) => pickWithinKind(list, perKindLimit).map((item) => {
6528
+ const lineText = `- ${isInferredMemory(item) ? "\uFF08\u63A8\u65AD\uFF09" : ""}${normalizeDisplayContent(item)}`;
6741
6529
  return { kind, lineText, lineTokens: estimateTokens(lineText) };
6742
6530
  })
6743
6531
  ).sort((a, b) => (KIND_PRIORITY[a.kind] ?? 99) - (KIND_PRIORITY[b.kind] ?? 99));
6744
- let usedTokens = 0;
6745
- const keptByKind = {};
6746
- for (const candidate of allLines) {
6747
- if (usedTokens + candidate.lineTokens > remainingBudget) continue;
6748
- usedTokens += candidate.lineTokens;
6749
- if (!keptByKind[candidate.kind]) keptByKind[candidate.kind] = [];
6750
- keptByKind[candidate.kind].push(candidate.lineText);
6751
- }
6532
+ const { keptByKind, truncatedCount, droppedCount } = fitLinesToBudget(
6533
+ allLines,
6534
+ remainingBudget
6535
+ );
6752
6536
  const kindOrder = ["semantic", "procedural", "episodic"];
6753
6537
  const sections = kindOrder.filter((kind) => keptByKind[kind] && keptByKind[kind].length > 0).map((kind) => {
6754
6538
  return [`[${KIND_TITLES[kind]}]`, ...keptByKind[kind]].join("\n");
@@ -6756,7 +6540,7 @@ var buildMemoryOverlay = (items, options) => {
6756
6540
  if (sections.length === 0) {
6757
6541
  return OVERLAY_HEADER_LINES.join("\n");
6758
6542
  }
6759
- return [...OVERLAY_HEADER_LINES, ...sections].join("\n");
6543
+ return [...OVERLAY_HEADER_LINES, ...sections, ...buildBudgetFooter({ keptByKind, truncatedCount, droppedCount })].join("\n");
6760
6544
  };
6761
6545
 
6762
6546
  // packages/ai/memory/rank.ts
@@ -6803,13 +6587,28 @@ var identifierScore = (query, item) => {
6803
6587
  ).length;
6804
6588
  return matches / identifiers.length;
6805
6589
  };
6806
- var activationScore = (item, nowMs) => {
6590
+ var DAY_MS = 864e5;
6591
+ var UNPROVEN_MEMORY_GRACE_DAYS = 3;
6592
+ var MIN_UNPROVEN_SCORE_FACTOR = 0.3;
6593
+ var UNPROVEN_DECAY_HALF_LIFE_DAYS = 7;
6594
+ var provenActivationScore = (item, nowMs) => {
6807
6595
  const lastActivatedMs = Date.parse(item.lastActivatedAt || item.createdAt);
6808
- const ageDays = Math.max(0, (nowMs - lastActivatedMs) / 864e5);
6596
+ const ageDays = Math.max(0, (nowMs - lastActivatedMs) / DAY_MS);
6809
6597
  const recency = 1 / (1 + ageDays / 7);
6810
6598
  const reinforcement = Math.min(1, Math.log1p(item.activationCount ?? 0) / 3);
6811
6599
  return 0.7 * recency + 0.3 * reinforcement;
6812
6600
  };
6601
+ var unprovenDecayFactor = (item, nowMs) => {
6602
+ if ((item.activationCount ?? 0) !== 0) return 1;
6603
+ const createdAgeDays = Math.max(0, (nowMs - Date.parse(item.createdAt)) / DAY_MS);
6604
+ if (createdAgeDays <= UNPROVEN_MEMORY_GRACE_DAYS) return 1;
6605
+ const overdue = createdAgeDays - UNPROVEN_MEMORY_GRACE_DAYS;
6606
+ return Math.max(
6607
+ MIN_UNPROVEN_SCORE_FACTOR,
6608
+ 1 / (1 + overdue / UNPROVEN_DECAY_HALF_LIFE_DAYS)
6609
+ );
6610
+ };
6611
+ var activationScore = (item, nowMs) => provenActivationScore(item, nowMs) * unprovenDecayFactor(item, nowMs);
6813
6612
  var creationRecencyScore = (item, nowMs) => {
6814
6613
  const createdMs = Date.parse(item.createdAt);
6815
6614
  const ageDays = Math.max(0, (nowMs - createdMs) / 864e5);
@@ -6865,7 +6664,7 @@ var rankMemoryCandidates = (items, query, context) => {
6865
6664
 
6866
6665
  // packages/ai/memory/runtime.ts
6867
6666
  var COLD_STORAGE_CONFIDENCE = 0.3;
6868
- var MEMORY_OVERLAY_TOKEN_BUDGET = 2e3;
6667
+ var MEMORY_OVERLAY_TOKEN_BUDGET = DEFAULT_MEMORY_OVERLAY_TOKEN_BUDGET;
6869
6668
  var normalizeSelectedContent = (text) => text.trim().replace(EXPLICIT_REMEMBER_PREFIX_REGEX, "").replace(/[。!?!?]+$/u, "").trim();
6870
6669
  var STACK_TERMS = [
6871
6670
  "typescript",
@@ -6967,6 +6766,7 @@ var selectRuntimeMemoryItems = (items, context, userInput = "") => {
6967
6766
  );
6968
6767
  add(unique.find((item) => item.ownerType === "user"));
6969
6768
  add(unique.find((item) => item.ownerType === "space"));
6769
+ add(unique.find((item) => item.subjectType === "user"));
6970
6770
  add(unique.find((item) => item.kind === "procedural"));
6971
6771
  for (const item of unique) {
6972
6772
  add(item);
@@ -7086,6 +6886,36 @@ var resolveCliMemory = async (input) => {
7086
6886
  function resolvePositiveMs(value, fallback) {
7087
6887
  return parsePositiveFiniteNumberOrFallback(value, fallback);
7088
6888
  }
6889
+ function resolveRunOutcome(input) {
6890
+ switch (input.kind) {
6891
+ case "stall":
6892
+ return { status: "failed", exitCode: 1 };
6893
+ case "timeout":
6894
+ return { status: "timeout", exitCode: 124 };
6895
+ case "result": {
6896
+ const failed = input.isStalledOrTruncated || input.exitCode !== 0;
6897
+ if (!failed) {
6898
+ return { status: "done", exitCode: 0 };
6899
+ }
6900
+ return { status: "failed", exitCode: input.exitCode !== 0 ? input.exitCode : 1 };
6901
+ }
6902
+ }
6903
+ }
6904
+ var FAILED_EMPTY_ASSISTANT_REASONS = /* @__PURE__ */ new Set([
6905
+ "length_truncated",
6906
+ "stream_truncated",
6907
+ "repetition_loop",
6908
+ "stagnant_tool_calls"
6909
+ ]);
6910
+ var isRunResultStalledOrTruncated = (result) => !result.emptyAssistantOutputUsable && FAILED_EMPTY_ASSISTANT_REASONS.has(result.emptyAssistantFallbackReason ?? "");
6911
+ var resolveRunSettlementNote = (result) => {
6912
+ const reason = result.emptyAssistantFallbackReason;
6913
+ if (!reason || !FAILED_EMPTY_ASSISTANT_REASONS.has(reason)) return {};
6914
+ if (result.emptyAssistantOutputUsable) {
6915
+ return { note: `output complete but stream lacked finish frame: ${reason}` };
6916
+ }
6917
+ return { note: `empty assistant output: ${reason}` };
6918
+ };
7089
6919
  async function resolveAgentRunAgentKey(args) {
7090
6920
  if (!args.agentInput.trim() || args.agentInput.startsWith("agent-")) {
7091
6921
  return void 0;
@@ -7121,11 +6951,14 @@ async function runAgentRunCommand(args, deps) {
7121
6951
  deps.stallTimeoutMs ?? env.NOLO_LOCAL_RUN_STALL_TIMEOUT_MS,
7122
6952
  5 * 6e4
7123
6953
  );
6954
+ const stallEnvExplicitlySet = typeof env.NOLO_LOCAL_RUN_STALL_TIMEOUT_MS === "string" && env.NOLO_LOCAL_RUN_STALL_TIMEOUT_MS.trim().length > 0;
6955
+ const armStallWatchdog = hasRegistry || stallEnvExplicitlySet;
6956
+ const armTimeoutWatchdog = typeof parsed.timeoutMs === "number" && parsed.timeoutMs > 0;
7124
6957
  let timedOut = false;
7125
6958
  let stalled = false;
7126
6959
  let timeoutTimer;
7127
6960
  let stallTimer;
7128
- const activityTracker = hasRegistry ? createRunActivityTracker(childRunId, {
6961
+ const activityTracker = armStallWatchdog ? createRunActivityTracker(childRunId ?? "__foreground__", {
7129
6962
  env,
7130
6963
  homedir: deps.homedir,
7131
6964
  fs: deps.fs,
@@ -7138,7 +6971,7 @@ async function runAgentRunCommand(args, deps) {
7138
6971
  activityTracker?.dispose();
7139
6972
  };
7140
6973
  let rejectOnWatchdogFailure;
7141
- const watchdogFailure = hasRegistry ? new Promise((_, reject) => {
6974
+ const watchdogFailure = armStallWatchdog || armTimeoutWatchdog ? new Promise((_, reject) => {
7142
6975
  rejectOnWatchdogFailure = reject;
7143
6976
  }) : void 0;
7144
6977
  const raceWithWatchdog = (work) => watchdogFailure ? Promise.race([work, watchdogFailure]) : work;
@@ -7148,7 +6981,15 @@ async function runAgentRunCommand(args, deps) {
7148
6981
  } catch {
7149
6982
  }
7150
6983
  };
7151
- if (hasRegistry) {
6984
+ const finalizeWatchdogOutcome = (outcome, note) => {
6985
+ if (!hasRegistry) return;
6986
+ (deps.finalizeRunRecord ?? finalizeRunRecord)(
6987
+ childRunId,
6988
+ { status: outcome.status, exitCode: outcome.exitCode, note },
6989
+ { env, homedir: deps.homedir, fs: deps.fs, now: deps.now }
6990
+ );
6991
+ };
6992
+ if (armStallWatchdog) {
7152
6993
  stallTimer = setInterval(() => {
7153
6994
  if (timedOut || stalled) return;
7154
6995
  const activity = activityTracker?.getActivity();
@@ -7166,31 +7007,25 @@ async function runAgentRunCommand(args, deps) {
7166
7007
  const note = `stalled: no progress for ${stallTimeoutMs}ms`;
7167
7008
  output.write(`[nolo] local run ${note}
7168
7009
  `);
7169
- (deps.finalizeRunRecord ?? finalizeRunRecord)(
7170
- childRunId,
7171
- { status: "failed", note },
7172
- { env, homedir: deps.homedir, fs: deps.fs, now: deps.now }
7173
- );
7010
+ const outcome = resolveRunOutcome({ kind: "stall" });
7011
+ finalizeWatchdogOutcome(outcome, note);
7174
7012
  rejectOnWatchdogFailure?.(new Error(`[nolo] local run ${note}`));
7175
- exitFromWatchdog(1);
7013
+ exitFromWatchdog(outcome.exitCode);
7176
7014
  }
7177
7015
  }, Math.min(stallTimeoutMs, 1e4));
7178
- if (typeof parsed.timeoutMs === "number" && parsed.timeoutMs > 0) {
7179
- timeoutTimer = setTimeout(() => {
7180
- timedOut = true;
7181
- clearWatchdogs();
7182
- const note = `timed out after ${parsed.timeoutMs}ms`;
7183
- output.write(`[nolo] local run ${note}
7016
+ }
7017
+ if (armTimeoutWatchdog) {
7018
+ timeoutTimer = setTimeout(() => {
7019
+ timedOut = true;
7020
+ clearWatchdogs();
7021
+ const note = `timed out after ${parsed.timeoutMs}ms`;
7022
+ output.write(`[nolo] local run ${note}
7184
7023
  `);
7185
- (deps.finalizeRunRecord ?? finalizeRunRecord)(
7186
- childRunId,
7187
- { status: "timeout", note },
7188
- { env, homedir: deps.homedir, fs: deps.fs, now: deps.now }
7189
- );
7190
- rejectOnWatchdogFailure?.(new Error(`[nolo] local run ${note}`));
7191
- exitFromWatchdog(124);
7192
- }, parsed.timeoutMs);
7193
- }
7024
+ const outcome = resolveRunOutcome({ kind: "timeout" });
7025
+ finalizeWatchdogOutcome(outcome, note);
7026
+ rejectOnWatchdogFailure?.(new Error(`[nolo] local run ${note}`));
7027
+ exitFromWatchdog(outcome.exitCode);
7028
+ }, parsed.timeoutMs);
7194
7029
  }
7195
7030
  const wantsFallbackSuggestions = parsed.fallbackAgentKeys && parsed.fallbackAgentKeys.length > 0;
7196
7031
  const rawAgentInput = resolveRawAgentInput(args, deps.commandPath) ?? parsed.agentKey;
@@ -7345,22 +7180,8 @@ async function runAgentRunCommand(args, deps) {
7345
7180
  let memoryOverlayLayer = null;
7346
7181
  let memoryUseGuidanceLayer = null;
7347
7182
  if (!isSubtask) {
7348
- const AGENTS_MD_MAX = 8192;
7349
- for (const name of ["AGENTS.md", "CLAUDE.md"]) {
7350
- const agentsMdPath = join2(cliCwd, name);
7351
- if (existsSync2(agentsMdPath)) {
7352
- try {
7353
- let mdContent = readFileSync2(agentsMdPath, "utf8").trim();
7354
- if (!mdContent) continue;
7355
- if (Buffer.byteLength(mdContent, "utf8") > AGENTS_MD_MAX) {
7356
- mdContent = Buffer.from(mdContent, "utf8").subarray(0, AGENTS_MD_MAX).toString("utf8") + "\n\n<!-- AGENTS.md truncated -->";
7357
- }
7358
- scopedLayers.push(buildAgentsMdLayer(mdContent, name));
7359
- break;
7360
- } catch {
7361
- }
7362
- }
7363
- }
7183
+ const agentsMdLayer = readAgentsMdLayerFromDisk(cliCwd);
7184
+ if (agentsMdLayer) scopedLayers.push(agentsMdLayer);
7364
7185
  skillContentBlocks.push(...buildSkillContextBlocks(skillReferences));
7365
7186
  scopedLayers.push(buildSkillDiscoveryContextLayer(cliCwd));
7366
7187
  if (!deps.memoryRecallDisabled) {
@@ -7441,6 +7262,7 @@ async function runAgentRunCommand(args, deps) {
7441
7262
  })
7442
7263
  );
7443
7264
  clearWatchdogs();
7265
+ let runCreditsTotal = result.turnCredits;
7444
7266
  if (result.exitCode !== 0 && isQuotaExhaustedError(result.localError) && isLocalRun && parsed.fallbackAgentKeys && parsed.fallbackAgentKeys.length > 0) {
7445
7267
  const fallbackAgentKey = parsed.fallbackAgentKeys[0];
7446
7268
  output.write(
@@ -7456,7 +7278,11 @@ async function runAgentRunCommand(args, deps) {
7456
7278
  clearWatchdogs();
7457
7279
  if (fallbackResult.exitCode === 0) {
7458
7280
  result = fallbackResult;
7459
- } else {
7281
+ }
7282
+ if (fallbackResult.turnCredits !== void 0) {
7283
+ runCreditsTotal = (runCreditsTotal ?? 0) + fallbackResult.turnCredits;
7284
+ }
7285
+ if (fallbackResult.exitCode !== 0) {
7460
7286
  result = {
7461
7287
  ...fallbackResult,
7462
7288
  ...fallbackResult.dialogId || result.dialogId ? { dialogId: fallbackResult.dialogId ?? result.dialogId } : {}
@@ -7499,6 +7325,9 @@ async function runAgentRunCommand(args, deps) {
7499
7325
  );
7500
7326
  clearWatchdogs();
7501
7327
  result = turnResult;
7328
+ if (turnResult.turnCredits !== void 0) {
7329
+ runCreditsTotal = (runCreditsTotal ?? 0) + turnResult.turnCredits;
7330
+ }
7502
7331
  if (result.exitCode !== 0) {
7503
7332
  break;
7504
7333
  }
@@ -7549,15 +7378,22 @@ async function runAgentRunCommand(args, deps) {
7549
7378
  }
7550
7379
  }
7551
7380
  if (typeof childRunId === "string" && childRunId.length > 0) {
7552
- const isStalledOrTruncated = result.emptyAssistantFallbackReason === "length_truncated" || result.emptyAssistantFallbackReason === "stream_truncated" || result.emptyAssistantFallbackReason === "repetition_loop" || result.emptyAssistantFallbackReason === "stagnant_tool_calls";
7553
- const truncationNote = isStalledOrTruncated ? { note: `empty assistant output: ${result.emptyAssistantFallbackReason}` } : {};
7554
- const finalStatus = isStalledOrTruncated || result.exitCode !== 0 ? "failed" : "done";
7381
+ const isStalledOrTruncated = isRunResultStalledOrTruncated(result);
7382
+ const truncationNote = resolveRunSettlementNote(result);
7383
+ const outcome = resolveRunOutcome({
7384
+ kind: "result",
7385
+ exitCode: result.exitCode,
7386
+ isStalledOrTruncated
7387
+ });
7555
7388
  await (deps.finalizeRunRecord ?? finalizeRunRecord)(
7556
7389
  childRunId,
7557
7390
  {
7558
- status: finalStatus,
7559
- exitCode: result.exitCode,
7391
+ status: outcome.status,
7392
+ exitCode: outcome.exitCode,
7560
7393
  dialogId: result.dialogId,
7394
+ // run 级累计的平台积分(主轮 + fallback + drain 轮):dock 行据此显示
7395
+ // 「⚡ x.xx」,让派发任务的消耗可见。undefined = 全程无平台计费。
7396
+ ...runCreditsTotal !== void 0 ? { credits: runCreditsTotal } : {},
7561
7397
  ...truncationNote
7562
7398
  },
7563
7399
  {
@@ -7602,6 +7438,7 @@ function isBalanceExhaustedError(error) {
7602
7438
  export {
7603
7439
  resolveAgentModelIdentity,
7604
7440
  resolveAgentContextWindow,
7441
+ formatCreditsChip,
7605
7442
  formatTokenCount,
7606
7443
  renderTokenStatus,
7607
7444
  resolveCliColorEnabled,
@@ -7640,8 +7477,10 @@ export {
7640
7477
  themeText,
7641
7478
  tuiRenderThemeFingerprint,
7642
7479
  setMathRenderingEnabled,
7480
+ polishBreathInsertsBlankBetween,
7643
7481
  formatAssistantDisplay,
7644
- normalizeToolDisplayMode,
7482
+ redactSecrets,
7483
+ TUI_TREE_MARKER,
7645
7484
  COLLAPSED_PASTE_PLACEHOLDER_RE,
7646
7485
  shouldCollapsePaste,
7647
7486
  createCollapsedPasteStore,
@@ -7653,6 +7492,7 @@ export {
7653
7492
  expandRangeToCollapsedPasteChips,
7654
7493
  findCollapsedPasteSpanAt,
7655
7494
  runAgentTurn,
7495
+ readAgentsMdLayerFromDisk,
7656
7496
  resolveWorkflowReference,
7657
7497
  resolveSkillReference,
7658
7498
  buildSkillContextBlocks,
@@ -7660,6 +7500,9 @@ export {
7660
7500
  normalizeCliImageInput,
7661
7501
  inspectLocalRunWorkspace,
7662
7502
  resolveCliMemory,
7503
+ resolveRunOutcome,
7504
+ isRunResultStalledOrTruncated,
7505
+ resolveRunSettlementNote,
7663
7506
  runAgentRunCommand,
7664
7507
  isBalanceExhaustedError
7665
7508
  };