nolo-cli 0.50.0-alpha.1 → 0.50.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 (131) hide show
  1. package/{_executeModel-4BPV4B2U.js → _executeModel-JKEH7ACW.js} +48 -42
  2. package/{action-IU6ON7ZB.js → action-VSG2IYP3.js} +8 -8
  3. package/{addContentAction-5V5CCI3I.js → addContentAction-2HJJITDI.js} +8 -7
  4. package/{addDialogAgentAction-KF3KZZNZ.js → addDialogAgentAction-7BSQVVL5.js} +10 -9
  5. package/{agentDeleteCommand-KZSETRE3.js → agentDeleteCommand-SVXKS5SC.js} +30 -28
  6. package/{agentEmailCommands-5TEW64UO.js → agentEmailCommands-WN7QBTP3.js} +57 -52
  7. package/{agentListCommands-KVLURCS7.js → agentListCommands-2BEBOQIG.js} +42 -33
  8. package/{agentMachineCommands-4LQF5YB5.js → agentMachineCommands-WALP3ONU.js} +30 -28
  9. package/{agentRecordCommands-OXC6JSH6.js → agentRecordCommands-E652SW57.js} +55 -50
  10. package/{agentRunCommand-4AXTA7MR.js → agentRunCommand-6VXWXKCS.js} +60 -53
  11. package/{agentRunControl-4GHHSXFZ.js → agentRunControl-LJVFDJGU.js} +3 -1
  12. package/{agentRuntimeLocal-SIQYQGSK.js → agentRuntimeLocal-SBG7BDFQ.js} +30 -26
  13. package/{agentSlice-VD3BAJAU.js → agentSlice-3WYXIGEO.js} +8 -8
  14. package/{agentSuperviseCommands-VB6BUS5H.js → agentSuperviseCommands-F3RFAL7K.js} +2 -2
  15. package/{appDeleteCommands-LSIIQFYN.js → appDeleteCommands-NTUNMEXY.js} +31 -29
  16. package/{appDeployCommands-VYGKN7HU.js → appDeployCommands-DISWXRTL.js} +31 -29
  17. package/{appDeployStatusCommands-ODFHFUR7.js → appDeployStatusCommands-IKRA6B6F.js} +31 -29
  18. package/{appGetCommands-DPQY67UZ.js → appGetCommands-UMOP2DFV.js} +31 -29
  19. package/{appListCommands-EFXENXWX.js → appListCommands-ZKFD2AKS.js} +31 -29
  20. package/{authCommand-WLWOEVYI.js → authCommand-BS3CQC6I.js} +11 -11
  21. package/{chatQueueReduxAdapter-N5432EP2.js → chatQueueReduxAdapter-A3YH4MT4.js} +24 -21
  22. package/{chunk-76UA7376.js → chunk-273FJUYI.js} +6 -6
  23. package/{chunk-7CH6U3FL.js → chunk-2GRGFCF6.js} +2 -4
  24. package/{chunk-T27IEBNQ.js → chunk-2QDDKFG5.js} +74 -1
  25. package/{chunk-WWXZYFWM.js → chunk-2TLYVDTN.js} +464 -1135
  26. package/{chunk-6BYAXNH5.js → chunk-3QOCS5IF.js} +11 -2
  27. package/chunk-6IGD47IC.js +19 -0
  28. package/{chunk-QDNFRWAX.js → chunk-6TUT5ZJD.js} +4 -6
  29. package/chunk-6YTOJY35.js +352 -0
  30. package/{chunk-B54WOZ77.js → chunk-7H7GQL6V.js} +2 -2
  31. package/{chunk-OYNDYVSE.js → chunk-B45YNDAE.js} +1 -1
  32. package/{chunk-OZ4JNDIL.js → chunk-BKIDF5LV.js} +1 -1
  33. package/{chunk-5XCW6RQG.js → chunk-BUBPRCIU.js} +1 -1
  34. package/chunk-BYXBJQAS.js +0 -0
  35. package/{chunk-X7S7OFUX.js → chunk-CEVCRRHU.js} +4 -4
  36. package/{chunk-JBL24PK6.js → chunk-DEIGUGP6.js} +2 -2
  37. package/{chunk-V2IPBG5U.js → chunk-DGEPT6FH.js} +1 -1
  38. package/{chunk-3AOLVADY.js → chunk-DVINR3PL.js} +1 -1
  39. package/{chunk-HMMOAG2I.js → chunk-DXOELY7S.js} +67 -69
  40. package/{chunk-OFZPJ3NT.js → chunk-E4MARS3Q.js} +1 -1
  41. package/{chunk-27MWS6HD.js → chunk-EAYBPWHX.js} +179 -86
  42. package/{chunk-DQLYEGP7.js → chunk-EGVY3GMT.js} +1 -1
  43. package/{chunk-2JYSSXLY.js → chunk-EJFW7TRP.js} +5 -26
  44. package/{chunk-4YAMAMNA.js → chunk-FGRCSLPV.js} +36 -46
  45. package/{chunk-VFN256RI.js → chunk-G4WSLTQF.js} +56 -97
  46. package/{chunk-HR5XDXYM.js → chunk-G5SQVIFZ.js} +3 -3
  47. package/{chunk-J3UALFHL.js → chunk-GHE5XMVR.js} +1 -1
  48. package/{chunk-7M72YPM2.js → chunk-GKB4AZKV.js} +440 -2981
  49. package/{chunk-S3HB4CQY.js → chunk-GKNGRBE6.js} +256 -40
  50. package/{chunk-Q24S4NDF.js → chunk-HQTK2SFT.js} +1 -1
  51. package/{chunk-XB7ACJFH.js → chunk-IPTZ5TVU.js} +7 -6
  52. package/{chunk-4RXXP6WD.js → chunk-J7KDNHUO.js} +5 -64
  53. package/{chunk-BO3YFOZR.js → chunk-KNQ5LYVZ.js} +57 -2
  54. package/{chunk-AV4Z57LV.js → chunk-KVVNC5V3.js} +2 -2
  55. package/{chunk-VKSBVRGP.js → chunk-LVCAWHI5.js} +4 -4
  56. package/{chunk-5JXRVJAC.js → chunk-N6SLQMSA.js} +6 -6
  57. package/{chunk-SQTVMYMU.js → chunk-NTZO3KX2.js} +3 -3
  58. package/{chunk-LGUQHYAL.js → chunk-O5FLGN2L.js} +3 -2
  59. package/{chunk-72COHDZR.js → chunk-OSUZKICS.js} +1600 -190
  60. package/{chunk-HIDPTO4B.js → chunk-Q2QN2RHG.js} +7 -7
  61. package/{chunk-L3JWI7WX.js → chunk-QOKAKDPE.js} +15 -11
  62. package/{chunk-4ZL2KBI7.js → chunk-RFYXK6KI.js} +1 -1
  63. package/chunk-RQSN75DW.js +1766 -0
  64. package/{chunk-RPO6WAZV.js → chunk-S3JNURSO.js} +2 -2
  65. package/{chunk-YZ2WE6CW.js → chunk-SAJSBPI2.js} +2 -2
  66. package/{chunk-WHVQA7PJ.js → chunk-SCBBGS2N.js} +23 -5
  67. package/chunk-SGSJBBKP.js +297 -0
  68. package/{chunk-FTSPVLKJ.js → chunk-TUBNQ3OF.js} +2 -2
  69. package/{chunk-BANYWEYY.js → chunk-TY3ADTX5.js} +1 -1
  70. package/chunk-UAD2WT54.js +64 -0
  71. package/{chunk-F22JQTSX.js → chunk-UEV5WVQV.js} +3 -3
  72. package/{chunk-MCX2LX27.js → chunk-UMCMW5R3.js} +51 -34
  73. package/{chunk-6L6UPZNH.js → chunk-VFDRZHPM.js} +16 -16
  74. package/{chunk-C2WF2OY7.js → chunk-W22UTILW.js} +3 -3
  75. package/{chunk-W3RZLXMA.js → chunk-WERPP2S7.js} +2 -2
  76. package/{chunk-AZ6DT2UD.js → chunk-WSUHBABG.js} +1 -1
  77. package/{chunk-3YVCM5PE.js → chunk-X3OGKR5Q.js} +4 -4
  78. package/{chunk-IERBSHMR.js → chunk-X5LRMXTS.js} +10 -10
  79. package/{chunk-DIQCV4FR.js → chunk-X665UCNM.js} +1 -1
  80. package/{chunk-HCBQVVFZ.js → chunk-X7P6EJUY.js} +4 -4
  81. package/{chunk-HHBXCRJS.js → chunk-XOJRZUPF.js} +4 -4
  82. package/{chunk-MRWGHF56.js → chunk-YDH3FDFQ.js} +12 -356
  83. package/{chunk-TNPCQNGQ.js → chunk-YEFRCO5N.js} +4 -9
  84. package/{chunk-RO2IUWZE.js → chunk-YUKTCDVN.js} +1 -1
  85. package/{chunk-Y7TGWSUN.js → chunk-YWY25N4V.js} +1 -1
  86. package/{chunk-Z7A54NFZ.js → chunk-ZDS63Y4O.js} +2 -2
  87. package/chunk-ZJ7UHBJS.js +89 -0
  88. package/{chunk-SG65C33A.js → chunk-ZLMG6NRV.js} +4 -4
  89. package/{codingSkills-BYQI6EPT.js → codingSkills-FQPCEIWL.js} +2 -2
  90. package/contentThunks-J33BZB3E.js +71 -0
  91. package/{createAgentAutomationAction-IHKV53QC.js → createAgentAutomationAction-HTMTGX6Q.js} +25 -21
  92. package/{createDialogAction-4ARDCKPP.js → createDialogAction-WYQBSN6A.js} +27 -23
  93. package/{createPageAction-GQOCPICU.js → createPageAction-ICRRK3SA.js} +27 -22
  94. package/{dbSlice-FWF5F4L7.js → dbSlice-YORO4VL4.js} +6 -6
  95. package/{deleteFile-NPZ64DFN.js → deleteFile-JYKRT7C3.js} +4 -4
  96. package/{dialogCommands-YOTCP26N.js → dialogCommands-FRSIAPKY.js} +31 -29
  97. package/{dialogSlice-NX26W623.js → dialogSlice-5KPVIAWH.js} +24 -21
  98. package/{docCreateCommands-JVAMHES4.js → docCreateCommands-DBRJMPDX.js} +30 -28
  99. package/{docDeleteCommands-LW5DWICT.js → docDeleteCommands-BCYPLWXN.js} +31 -29
  100. package/{docReadCommands-AQOZS3I5.js → docReadCommands-L5JX4Q7G.js} +30 -28
  101. package/{docStore-YAE7GYHZ.js → docStore-34NXLCEO.js} +8 -33
  102. package/{docUpdateCommands-FFGGX5RG.js → docUpdateCommands-RELG7XJD.js} +30 -28
  103. package/fetchMessages-KZQVBXKY.js +1 -1
  104. package/{getPricing-JNOCWYDH.js → getPricing-FM7TJZFV.js} +4 -4
  105. package/{handleSendMessageAction-7YKH4UBI.js → handleSendMessageAction-MEYK7RPD.js} +25 -22
  106. package/index.js +64 -64
  107. package/{machineCommands-FMMFBMCQ.js → machineCommands-YSXTOWHQ.js} +59 -54
  108. package/{machineWsRunDispatch-UODRJY63.js → machineWsRunDispatch-DNAYOPQT.js} +54 -49
  109. package/memberThunks-KVPBG4V7.js +638 -0
  110. package/{models-N4NXQ44D.js → models-CW5EL6Z7.js} +2 -2
  111. package/package.json +2 -3
  112. package/{read-J7RVVCHH.js → read-NIOV5F7W.js} +4 -4
  113. package/{readDocTool-G2WBM4IH.js → readDocTool-ULKJ5BEM.js} +1 -1
  114. package/{readlineWorkspace-GVDEA7RH.js → readlineWorkspace-KZ3LPQG2.js} +866 -377
  115. package/{removeDialogAgentAction-RMPISD42.js → removeDialogAgentAction-JGSCPML3.js} +12 -11
  116. package/{runAgentClientLoop-6NCW5AS6.js → runAgentClientLoop-O2AUHIJT.js} +46 -40
  117. package/{setDialogExtraReferencesAction-7BUTHDAL.js → setDialogExtraReferencesAction-CORU64NM.js} +9 -8
  118. package/{setPrimaryDialogAgentAction-WCYIBGZ4.js → setPrimaryDialogAgentAction-5VS2VKLZ.js} +12 -11
  119. package/{settingSlice-7NN2MI6Y.js → settingSlice-3GNGTC2T.js} +7 -7
  120. package/{skillDiscovery-COX56OBO.js → skillDiscovery-CYUCJMAG.js} +3 -3
  121. package/{spaceCommands-7MJVL4XR.js → spaceCommands-OI7RIB2T.js} +30 -28
  122. package/{streamAgentChatTurn-UAKCHWFN.js → streamAgentChatTurn-TA3PGS6C.js} +61 -54
  123. package/{switchDialogAgentAction-WGMMQHDI.js → switchDialogAgentAction-LP433X4D.js} +10 -9
  124. package/{tableCommands-P2TXJ3CF.js → tableCommands-R6WFRDYF.js} +1 -1
  125. package/{toolApiClient-B2MFXMEG.js → toolApiClient-53U4UDFF.js} +3 -2
  126. package/{tools-ROUITGAR.js → tools-6ZPQ75XA.js} +37 -32
  127. package/{tuiSummaryLlmCaller-U4EGD2SX.js → tuiSummaryLlmCaller-YKYQB4ZL.js} +17 -15
  128. package/{updateDialogTitleAction-R4M6ZXCX.js → updateDialogTitleAction-LRJ7NSOS.js} +26 -22
  129. package/chunk-EUG45QJR.js +0 -6104
  130. package/spaceSlice-JVVDCGA3.js +0 -127
  131. package/{chunk-NQ4N4IGO.js → chunk-CS6TCJ7E.js} +3 -3
@@ -1,6 +1,3 @@
1
- import {
2
- generateRunReport
3
- } from "./chunk-J3UALFHL.js";
4
1
  import {
5
2
  buildLocalRunEnv,
6
3
  isFullstackCodingAgentRef,
@@ -10,6 +7,9 @@ import {
10
7
  resolveServerUrl,
11
8
  writeUsage
12
9
  } from "./chunk-LYGNQHUW.js";
10
+ import {
11
+ resolveMachineId
12
+ } from "./chunk-ESHYE7WU.js";
13
13
  import {
14
14
  agentRunCardLabels,
15
15
  createCliLocalRuntimeAdapter,
@@ -19,7 +19,12 @@ import {
19
19
  parseAgentRunEvent,
20
20
  t,
21
21
  toolLabel
22
- } from "./chunk-27MWS6HD.js";
22
+ } from "./chunk-EAYBPWHX.js";
23
+ import {
24
+ readCredentialEntry,
25
+ recordCredentialProbe,
26
+ resolveCredentialKeyWithFallback
27
+ } from "./chunk-NI2BS6UD.js";
23
28
  import {
24
29
  getReadableCliDb
25
30
  } from "./chunk-43CXXVJD.js";
@@ -27,11 +32,14 @@ import {
27
32
  normalizeAgentHandle,
28
33
  readDbRecord,
29
34
  resolveAgentRecordFromHybridStore
30
- } from "./chunk-DQLYEGP7.js";
35
+ } from "./chunk-EGVY3GMT.js";
31
36
  import {
32
37
  NOLO_PROJECT_MANAGER_AGENT_KEY,
33
38
  isLocalCliAgentKey
34
39
  } from "./chunk-EKLRRZIN.js";
40
+ import {
41
+ generateRunReport
42
+ } from "./chunk-GHE5XMVR.js";
35
43
  import {
36
44
  CliProviderQuotaError
37
45
  } from "./chunk-JDSUTNYY.js";
@@ -42,17 +50,14 @@ import {
42
50
  readRunRecord,
43
51
  resolveRunQueuePath,
44
52
  spawnLocalBackgroundRun
45
- } from "./chunk-WHVQA7PJ.js";
46
- import {
47
- resolveMachineId
48
- } from "./chunk-ESHYE7WU.js";
53
+ } from "./chunk-SCBBGS2N.js";
49
54
  import {
50
55
  applyModelLayerOverride,
51
56
  buildModelLayerOverride
52
57
  } from "./chunk-LTRXGFMS.js";
53
58
  import {
54
59
  formatAgentListCard
55
- } from "./chunk-72COHDZR.js";
60
+ } from "./chunk-OSUZKICS.js";
56
61
  import {
57
62
  isTransientFetchError
58
63
  } from "./chunk-5XTOKQLW.js";
@@ -66,26 +71,25 @@ import {
66
71
  formatStartRunCard,
67
72
  formatStatusRunCard,
68
73
  formatStopRunCard,
69
- isAgentRunTerminalStatus,
70
- runShowsLogTail
74
+ isAgentRunTerminalStatus
71
75
  } from "./chunk-KXKQO4Q6.js";
72
76
  import {
73
77
  buildMemorySubjectsForAgent,
74
78
  chooseMemoryOwners,
75
79
  loadMemoryCandidatesFromDb,
76
80
  resolveAgentMemoryPolicy
77
- } from "./chunk-IERBSHMR.js";
81
+ } from "./chunk-X5LRMXTS.js";
78
82
  import {
79
83
  API_REPORTED_COST_MULTIPLIER,
80
84
  normalizeUsage,
81
85
  parseUiAskChoiceContent
82
- } from "./chunk-MCX2LX27.js";
86
+ } from "./chunk-UMCMW5R3.js";
83
87
  import {
84
88
  getDefaultCliLocalRuntimeDb
85
89
  } from "./chunk-IA3A5373.js";
86
90
  import {
87
91
  buildSkillDiscoveryContextLayer
88
- } from "./chunk-OFZPJ3NT.js";
92
+ } from "./chunk-E4MARS3Q.js";
89
93
  import {
90
94
  parseExternalSkillMarkdown,
91
95
  parseSkillDocProtocol
@@ -93,12 +97,11 @@ import {
93
97
  import {
94
98
  LOCAL_AGENT_CONFIG_MISSING_CODE,
95
99
  LOCAL_TURN_ABORTED_CODE,
96
- readActionGate,
97
- readCommandActionGatePayload
98
- } from "./chunk-S3HB4CQY.js";
100
+ readActionGate
101
+ } from "./chunk-GKNGRBE6.js";
99
102
  import {
100
103
  resolveAgentRuntimeConfigFromRecord
101
- } from "./chunk-VKSBVRGP.js";
104
+ } from "./chunk-LVCAWHI5.js";
102
105
  import {
103
106
  createThinkParserState,
104
107
  flushThinkParser,
@@ -107,20 +110,22 @@ import {
107
110
  import {
108
111
  resolveClientVersion,
109
112
  resolvePlatformAuthToken
110
- } from "./chunk-JBL24PK6.js";
113
+ } from "./chunk-DEIGUGP6.js";
111
114
  import {
112
- isQuotaExhaustedError
115
+ isQuotaExhaustedError,
116
+ mergeAvailabilityDeadline,
117
+ resolveCooldownGate
113
118
  } from "./chunk-IWUMSAQF.js";
114
119
  import {
115
120
  DEFAULT_CONTEXT_WINDOW,
116
121
  getModelContextWindow
117
- } from "./chunk-F22JQTSX.js";
122
+ } from "./chunk-UEV5WVQV.js";
118
123
  import {
119
124
  clipCompactText
120
- } from "./chunk-HR5XDXYM.js";
125
+ } from "./chunk-G5SQVIFZ.js";
121
126
  import {
122
127
  findModelConfig
123
- } from "./chunk-BO3YFOZR.js";
128
+ } from "./chunk-KNQ5LYVZ.js";
124
129
  import {
125
130
  compactWhitespace
126
131
  } from "./chunk-DWLEOOGR.js";
@@ -133,7 +138,7 @@ import {
133
138
  buildMemoryUseGuidanceLayer,
134
139
  partitionScopedBlocks,
135
140
  renderTurnContextBlocksWithScope
136
- } from "./chunk-3AOLVADY.js";
141
+ } from "./chunk-DVINR3PL.js";
137
142
  import {
138
143
  readPipeText,
139
144
  spawnProcess
@@ -145,7 +150,7 @@ import {
145
150
  CLIENT_VERSION_TOO_OLD_CODE,
146
151
  NOLO_CLIENT_VERSION_HEADER,
147
152
  buildClientVersionUpgradeMessage
148
- } from "./chunk-VFN256RI.js";
153
+ } from "./chunk-G4WSLTQF.js";
149
154
  import {
150
155
  parsePositiveFiniteNumberOrFallback
151
156
  } from "./chunk-Y5GCAMGP.js";
@@ -159,7 +164,7 @@ import {
159
164
  BUILTIN_NOLO_AGENT_KEY,
160
165
  BUILTIN_NOLO_AGENT_NAME,
161
166
  builtinAgentCatalogEntryById
162
- } from "./chunk-2JYSSXLY.js";
167
+ } from "./chunk-EJFW7TRP.js";
163
168
  import {
164
169
  parsePublicAgentId
165
170
  } from "./chunk-BJIRLHJR.js";
@@ -1240,13 +1245,6 @@ function setActiveThemeMode(mode) {
1240
1245
  function setActiveBrightness(brightness) {
1241
1246
  setActiveThemeMode(brightness ?? "terminal");
1242
1247
  }
1243
- var activeDensity = "spacious";
1244
- function getActiveDensity() {
1245
- return activeDensity;
1246
- }
1247
- function setActiveDensity(density) {
1248
- activeDensity = density;
1249
- }
1250
1248
  var TRUECOLOR_TERM_PROGRAMS = /* @__PURE__ */ new Set([
1251
1249
  "iterm.app",
1252
1250
  "wezterm",
@@ -2824,11 +2822,6 @@ function scanStringCommentRegions(line, lang) {
2824
2822
  }
2825
2823
  return regions;
2826
2824
  }
2827
- function detectCodeLangFromPath(filePath) {
2828
- if (!filePath) return "unknown";
2829
- const ext = filePath.split(".").pop() ?? "";
2830
- return normalizeCodeLang(ext);
2831
- }
2832
2825
  function highlightCodeLine(line, lang, brightness) {
2833
2826
  const info = colorSeq("info", brightness);
2834
2827
  if (lang === "unknown") {
@@ -2915,6 +2908,14 @@ function normalizeListLine(line) {
2915
2908
  }
2916
2909
  return line;
2917
2910
  }
2911
+ function isPolishListLikeLine(line) {
2912
+ return LIST_LIKE_RE_FOR_GUARD.test(normalizeListLine(line));
2913
+ }
2914
+ var LIST_LIKE_RE_FOR_GUARD = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]|^\s*[├└]──\s/;
2915
+ function polishBreathInsertsBlankBetween(cur, next) {
2916
+ if (cur === "" || next === "") return false;
2917
+ return isPolishListLikeLine(cur) !== isPolishListLikeLine(next);
2918
+ }
2918
2919
  function convertMarkdownTablesForTerminal(text) {
2919
2920
  const lines = text.split("\n");
2920
2921
  const out = [];
@@ -2982,7 +2983,7 @@ function polishAssistantStructure(text, options = {}) {
2982
2983
  return line;
2983
2984
  });
2984
2985
  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");
2985
- const LIST_LIKE = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]/;
2986
+ const LIST_LIKE = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]|^\s*[├└]──\s/;
2986
2987
  const headingLines = afterHeading.split("\n");
2987
2988
  const breathed = [];
2988
2989
  for (let i = 0; i < headingLines.length; i++) {
@@ -3401,16 +3402,6 @@ function formatReadItemPath(rawPath, metadata, customHomedir) {
3401
3402
  const clippedPath = clipPathAware(formattedPath, 72);
3402
3403
  return `${clippedPath}${rangePart}`;
3403
3404
  }
3404
- function formatReadTreeLines(items, customHomedir) {
3405
- const count = items.length;
3406
- const header = `Read (${count})`;
3407
- const lines = items.map((item, index) => {
3408
- const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
3409
- const pathWithRange = formatReadItemPath(item.path, item.metadata, customHomedir);
3410
- return { connector, pathWithRange };
3411
- });
3412
- return { header, count, lines };
3413
- }
3414
3405
  function formatSearchItemQuery(query, path, customHomedir) {
3415
3406
  let text = (query || "").trim();
3416
3407
  if (path) {
@@ -3422,16 +3413,6 @@ function formatSearchItemQuery(query, path, customHomedir) {
3422
3413
  if (!text) return "search";
3423
3414
  return text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
3424
3415
  }
3425
- function formatSearchTreeLines(items, customHomedir) {
3426
- const count = items.length;
3427
- const header = `Search (${count})`;
3428
- const lines = items.map((item, index) => {
3429
- const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
3430
- const queryText = formatSearchItemQuery(item.query, item.path, customHomedir);
3431
- return { connector, queryText };
3432
- });
3433
- return { header, count, lines };
3434
- }
3435
3416
  function formatRunItemCommand(command, exitCode, timedOut) {
3436
3417
  let text = compactWhitespace(command || "");
3437
3418
  if (!text) text = "command";
@@ -3440,453 +3421,24 @@ function formatRunItemCommand(command, exitCode, timedOut) {
3440
3421
  if (typeof exitCode === "number" && exitCode !== 0) return `${text} (exit ${exitCode})`;
3441
3422
  return text;
3442
3423
  }
3443
- function formatRunTreeLines(items) {
3444
- const count = items.length;
3445
- const header = `Run (${count})`;
3446
- const lines = items.map((item, index) => {
3447
- const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
3448
- const commandText = formatRunItemCommand(item.command, item.exitCode, item.timedOut);
3449
- return { connector, commandText };
3450
- });
3451
- return { header, count, lines };
3452
- }
3453
3424
  function formatFetchItemUrl(url) {
3454
3425
  const text = (url || "").trim();
3455
3426
  if (!text) return "webpage";
3456
3427
  return text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
3457
3428
  }
3458
- function formatFetchTreeLines(items) {
3459
- const count = items.length;
3460
- const header = `Fetch (${count})`;
3461
- const lines = items.map((item, index) => {
3462
- const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
3463
- const urlText = formatFetchItemUrl(item.url);
3464
- return { connector, urlText };
3465
- });
3466
- return { header, count, lines };
3467
- }
3468
-
3469
- // node_modules/diff/libesm/diff/base.js
3470
- var Diff = class {
3471
- diff(oldStr, newStr, options = {}) {
3472
- let callback;
3473
- if (typeof options === "function") {
3474
- callback = options;
3475
- options = {};
3476
- } else if ("callback" in options) {
3477
- callback = options.callback;
3478
- }
3479
- const oldString = this.castInput(oldStr, options);
3480
- const newString = this.castInput(newStr, options);
3481
- const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
3482
- const newTokens = this.removeEmpty(this.tokenize(newString, options));
3483
- return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
3484
- }
3485
- diffWithOptionsObj(oldTokens, newTokens, options, callback) {
3486
- var _a;
3487
- const done = (value) => {
3488
- value = this.postProcess(value, options);
3489
- if (callback) {
3490
- setTimeout(function() {
3491
- callback(value);
3492
- }, 0);
3493
- return void 0;
3494
- } else {
3495
- return value;
3496
- }
3497
- };
3498
- const newLen = newTokens.length, oldLen = oldTokens.length;
3499
- let editLength = 1;
3500
- let maxEditLength = newLen + oldLen;
3501
- if (options.maxEditLength != null) {
3502
- maxEditLength = Math.min(maxEditLength, options.maxEditLength);
3503
- }
3504
- const maxExecutionTime = (_a = options.timeout) !== null && _a !== void 0 ? _a : Infinity;
3505
- const abortAfterTimestamp = Date.now() + maxExecutionTime;
3506
- const bestPath = [{ oldPos: -1, lastComponent: void 0 }];
3507
- let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
3508
- if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
3509
- return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
3510
- }
3511
- let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
3512
- const execEditLength = () => {
3513
- for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
3514
- let basePath;
3515
- const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
3516
- if (removePath) {
3517
- bestPath[diagonalPath - 1] = void 0;
3518
- }
3519
- let canAdd = false;
3520
- if (addPath) {
3521
- const addPathNewPos = addPath.oldPos - diagonalPath;
3522
- canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
3523
- }
3524
- const canRemove = removePath && removePath.oldPos + 1 < oldLen;
3525
- if (!canAdd && !canRemove) {
3526
- bestPath[diagonalPath] = void 0;
3527
- continue;
3528
- }
3529
- if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
3530
- basePath = this.addToPath(addPath, true, false, 0, options);
3531
- } else {
3532
- basePath = this.addToPath(removePath, false, true, 1, options);
3533
- }
3534
- newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
3535
- if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
3536
- return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
3537
- } else {
3538
- bestPath[diagonalPath] = basePath;
3539
- if (basePath.oldPos + 1 >= oldLen) {
3540
- maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
3541
- }
3542
- if (newPos + 1 >= newLen) {
3543
- minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
3544
- }
3545
- }
3546
- }
3547
- editLength++;
3548
- };
3549
- if (callback) {
3550
- (function exec() {
3551
- setTimeout(function() {
3552
- if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
3553
- return callback(void 0);
3554
- }
3555
- if (!execEditLength()) {
3556
- exec();
3557
- }
3558
- }, 0);
3559
- })();
3560
- } else {
3561
- while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
3562
- const ret = execEditLength();
3563
- if (ret) {
3564
- return ret;
3565
- }
3566
- }
3567
- }
3568
- }
3569
- addToPath(path, added, removed, oldPosInc, options) {
3570
- const last = path.lastComponent;
3571
- if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
3572
- return {
3573
- oldPos: path.oldPos + oldPosInc,
3574
- lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
3575
- };
3576
- } else {
3577
- return {
3578
- oldPos: path.oldPos + oldPosInc,
3579
- lastComponent: { count: 1, added, removed, previousComponent: last }
3580
- };
3581
- }
3582
- }
3583
- extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
3584
- const newLen = newTokens.length, oldLen = oldTokens.length;
3585
- let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
3586
- while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
3587
- newPos++;
3588
- oldPos++;
3589
- commonCount++;
3590
- if (options.oneChangePerToken) {
3591
- basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
3592
- }
3593
- }
3594
- if (commonCount && !options.oneChangePerToken) {
3595
- basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
3596
- }
3597
- basePath.oldPos = oldPos;
3598
- return newPos;
3599
- }
3600
- equals(left, right, options) {
3601
- if (options.comparator) {
3602
- return options.comparator(left, right);
3603
- } else {
3604
- return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
3605
- }
3606
- }
3607
- removeEmpty(array) {
3608
- const ret = [];
3609
- for (let i = 0; i < array.length; i++) {
3610
- if (array[i]) {
3611
- ret.push(array[i]);
3612
- }
3613
- }
3614
- return ret;
3615
- }
3616
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3617
- castInput(value, options) {
3618
- return value;
3619
- }
3620
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3621
- tokenize(value, options) {
3622
- return Array.from(value);
3623
- }
3624
- join(chars) {
3625
- return chars.join("");
3626
- }
3627
- postProcess(changeObjects, options) {
3628
- return changeObjects;
3629
- }
3630
- get useLongestToken() {
3631
- return false;
3632
- }
3633
- buildValues(lastComponent, newTokens, oldTokens) {
3634
- const components = [];
3635
- let nextComponent;
3636
- while (lastComponent) {
3637
- components.push(lastComponent);
3638
- nextComponent = lastComponent.previousComponent;
3639
- delete lastComponent.previousComponent;
3640
- lastComponent = nextComponent;
3641
- }
3642
- components.reverse();
3643
- const componentLen = components.length;
3644
- let componentPos = 0, newPos = 0, oldPos = 0;
3645
- for (; componentPos < componentLen; componentPos++) {
3646
- const component = components[componentPos];
3647
- if (!component.removed) {
3648
- if (!component.added && this.useLongestToken) {
3649
- let value = newTokens.slice(newPos, newPos + component.count);
3650
- value = value.map(function(value2, i) {
3651
- const oldValue = oldTokens[oldPos + i];
3652
- return oldValue.length > value2.length ? oldValue : value2;
3653
- });
3654
- component.value = this.join(value);
3655
- } else {
3656
- component.value = this.join(newTokens.slice(newPos, newPos + component.count));
3657
- }
3658
- newPos += component.count;
3659
- if (!component.added) {
3660
- oldPos += component.count;
3661
- }
3662
- } else {
3663
- component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
3664
- oldPos += component.count;
3665
- }
3666
- }
3667
- return components;
3668
- }
3669
- };
3670
-
3671
- // node_modules/diff/libesm/diff/line.js
3672
- var LineDiff = class extends Diff {
3673
- constructor() {
3674
- super(...arguments);
3675
- this.tokenize = tokenize;
3676
- }
3677
- equals(left, right, options) {
3678
- if (options.ignoreWhitespace) {
3679
- if (!options.newlineIsToken || !left.includes("\n")) {
3680
- left = left.trim();
3681
- }
3682
- if (!options.newlineIsToken || !right.includes("\n")) {
3683
- right = right.trim();
3684
- }
3685
- } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
3686
- if (left.endsWith("\n")) {
3687
- left = left.slice(0, -1);
3688
- }
3689
- if (right.endsWith("\n")) {
3690
- right = right.slice(0, -1);
3691
- }
3692
- }
3693
- return super.equals(left, right, options);
3694
- }
3695
- };
3696
- var lineDiff = new LineDiff();
3697
- function diffLines(oldStr, newStr, options) {
3698
- return lineDiff.diff(oldStr, newStr, options);
3699
- }
3700
- function tokenize(value, options) {
3701
- if (options.stripTrailingCr) {
3702
- value = value.replace(/\r\n/g, "\n");
3703
- }
3704
- const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
3705
- if (!linesAndNewlines[linesAndNewlines.length - 1]) {
3706
- linesAndNewlines.pop();
3707
- }
3708
- for (let i = 0; i < linesAndNewlines.length; i++) {
3709
- const line = linesAndNewlines[i];
3710
- if (i % 2 && !options.newlineIsToken) {
3711
- retLines[retLines.length - 1] += line;
3712
- } else {
3713
- retLines.push(line);
3714
- }
3715
- }
3716
- return retLines;
3717
- }
3718
3429
 
3719
3430
  // packages/cli/client/toolOutput.ts
3720
- function normalizeToolDisplayMode(raw, fallback = "normal") {
3721
- const normalized = asTrimmedLowercaseString(raw);
3722
- if (normalized === "hide" || normalized === "off" || normalized === "false" || normalized === "0") {
3723
- return "hide";
3724
- }
3725
- if (normalized === "verbose" || normalized === "debug" || normalized === "trace" || normalized === "full") {
3726
- return "verbose";
3727
- }
3728
- if (normalized === "normal" || normalized === "summary" || normalized === "on") {
3729
- return "normal";
3730
- }
3731
- if (normalized === "pro" || normalized === "compact" || normalized === "minimal" || normalized === "short") {
3732
- return "pro";
3733
- }
3734
- return fallback;
3735
- }
3736
- function resolveToolDisplayMode(env = process.env) {
3737
- const legacyTrace = asTrimmedLowercaseString(env.NOLO_TRACE_TOOLS);
3738
- if (legacyTrace === "0" || legacyTrace === "false" || legacyTrace === "off") {
3739
- return "hide";
3740
- }
3741
- if (legacyTrace === "verbose" || legacyTrace === "full") {
3742
- return "verbose";
3743
- }
3744
- return normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "normal");
3745
- }
3746
- function shouldEmitToolEvents(mode) {
3747
- return mode !== "hide";
3748
- }
3749
3431
  function clip(value, max = 72) {
3750
3432
  return clipCompactText(value, max, "\u2026");
3751
3433
  }
3752
- function formatActiveToolLabel(event) {
3753
- const toolName = event.toolName || "tool";
3754
- const args = clipPathAware(event.argumentsPreview ?? "");
3755
- const label = toolLabel(toolName);
3756
- return args ? `${label} ${args}` : label;
3757
- }
3758
3434
  function formatConservativeActiveToolLabel(event) {
3759
3435
  return toolLabel(event.toolName || "tool");
3760
3436
  }
3761
- function compactResultHint(event) {
3762
- const gate = readActionGate(event.metadata?.actionGate);
3763
- if (gate) {
3764
- const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
3765
- const command = commandPayload?.displayCommand ?? commandPayload?.command.join(" ") ?? "";
3766
- const detail = command.trim() ? command : gate.title;
3767
- return { inline: `${t("toolNeedsAction")}: ${clip(detail, 120)}` };
3768
- }
3769
- if (event.metadata?.timedOut) return { inline: t("toolTimedOut") };
3770
- if (event.toolName === "readFile" && event.metadata) {
3771
- const range = readReadFileRange(event.metadata);
3772
- if (range) return { inline: range };
3773
- }
3774
- if (event.toolName === "editFile" && event.metadata) {
3775
- const res = formatEditFileSnippet(event.metadata);
3776
- if (res) {
3777
- const stats = [];
3778
- if (res.addedCount > 0) stats.push(`+${res.addedCount}`);
3779
- if (res.removedCount > 0) stats.push(`-${res.removedCount}`);
3780
- const inline = stats.length > 0 ? `(${stats.join(", ")})` : "";
3781
- return { inline, detail: res.lines };
3782
- }
3783
- }
3784
- if (event.toolName === "writeFile" && event.metadata) {
3785
- const totalLines = event.metadata.totalLines ?? event.metadata.lines;
3786
- if (typeof totalLines === "number" && totalLines > 0) {
3787
- return { inline: `(+${totalLines})` };
3788
- }
3789
- }
3790
- const summary = event.summary;
3791
- if (!summary) return { inline: "" };
3792
- const exitMatch = summary.match(/exit=(\d+)/);
3793
- if (exitMatch && exitMatch[1] !== "0") return { inline: `${t("toolExitCode")} ${exitMatch[1]}` };
3794
- return { inline: "" };
3795
- }
3796
- function readReadFileRange(metadata) {
3797
- const startLine = metadata.startLine;
3798
- const endLine = metadata.endLine;
3799
- const totalLines = metadata.totalLines;
3800
- const truncated = metadata.truncated;
3801
- if (typeof startLine !== "number" || typeof endLine !== "number" || typeof totalLines !== "number") {
3802
- return void 0;
3803
- }
3804
- if (!truncated && startLine === 1 && endLine === totalLines) return void 0;
3805
- return `${startLine}-${endLine}/${totalLines}`;
3806
- }
3807
- var EDIT_SNIPPET_MAX_LINES = 24;
3808
- var DEFAULT_EDIT_SNIPPET_MAX_WIDTH = 96;
3809
- function resolveEditSnippetMaxWidth(env = process.env, columns) {
3810
- if (env.NOLO_TEST_DIFF_WIDTH) {
3811
- const parsed = parseInt(env.NOLO_TEST_DIFF_WIDTH, 10);
3812
- if (!Number.isNaN(parsed) && parsed > 0) return parsed;
3813
- }
3814
- const cols = typeof columns === "number" ? columns : typeof process !== "undefined" && typeof process.stdout?.columns === "number" ? process.stdout.columns : 0;
3815
- if (cols > 0) {
3816
- return Math.max(80, Math.min(160, cols - 8));
3817
- }
3818
- return DEFAULT_EDIT_SNIPPET_MAX_WIDTH;
3819
- }
3820
- function formatEditFileSnippet(metadata) {
3821
- const oldSnippet = typeof metadata.oldSnippet === "string" ? metadata.oldSnippet : void 0;
3822
- const newSnippet = typeof metadata.newSnippet === "string" ? metadata.newSnippet : void 0;
3823
- if (!oldSnippet && !newSnippet) return void 0;
3824
- const maxWidth = resolveEditSnippetMaxWidth();
3825
- if (oldSnippet && !newSnippet) {
3826
- const lines = snippetLinesWithKind(oldSnippet, "removed", maxWidth);
3827
- return { lines, addedCount: 0, removedCount: lines.length };
3828
- }
3829
- if (newSnippet && !oldSnippet) {
3830
- const lines = snippetLinesWithKind(newSnippet, "added", maxWidth);
3831
- return { lines, addedCount: lines.length, removedCount: 0 };
3832
- }
3833
- const parts = diffLines(oldSnippet, newSnippet);
3834
- const all = [];
3835
- let addedCount = 0;
3836
- let removedCount = 0;
3837
- for (const part of parts) {
3838
- const kind = part.added ? "added" : part.removed ? "removed" : "context";
3839
- const raw = part.value.split("\n");
3840
- if (raw.length > 0 && raw[raw.length - 1] === "") raw.pop();
3841
- for (const line of raw) {
3842
- if (kind === "added") addedCount++;
3843
- if (kind === "removed") removedCount++;
3844
- all.push(buildEditLine(kind, line, maxWidth));
3845
- }
3846
- }
3847
- const changeCount = all.filter((l) => l.kind !== "context").length;
3848
- if (changeCount === 0) return void 0;
3849
- return {
3850
- lines: windowAndTruncate(all, EDIT_SNIPPET_MAX_LINES),
3851
- addedCount,
3852
- removedCount
3853
- };
3854
- }
3855
- function prefixFor(kind) {
3856
- return kind === "added" ? "+ " : kind === "removed" ? "- " : " ";
3857
- }
3858
- function buildEditLine(kind, body, maxWidth = resolveEditSnippetMaxWidth()) {
3859
- return { kind, text: prefixFor(kind) + truncateByDisplayWidth(body, maxWidth) };
3860
- }
3861
- function snippetLinesWithKind(snippet, kind, maxWidth = resolveEditSnippetMaxWidth()) {
3862
- const lines = snippet.split(/\r?\n/).filter((line) => line.length > 0);
3863
- return lines.slice(0, EDIT_SNIPPET_MAX_LINES).map((line) => buildEditLine(kind, line, maxWidth));
3437
+ function isRunToolName(name) {
3438
+ return name === "execShell" || name === "runCommand" || name === "launchProcess";
3864
3439
  }
3865
- function truncateByDisplayWidth(line, maxWidth) {
3866
- if (displayWidth(line) <= maxWidth) return line;
3867
- let width = 0;
3868
- let kept = "";
3869
- for (const char of line) {
3870
- const w = displayWidth(char);
3871
- if (width + w + 1 > maxWidth) break;
3872
- kept += char;
3873
- width += w;
3874
- }
3875
- return `${kept}\u2026`;
3876
- }
3877
- function windowAndTruncate(lines, maxLines) {
3878
- if (lines.length <= maxLines) return lines;
3879
- const firstChange = lines.findIndex((l) => l.kind !== "context");
3880
- if (firstChange === -1) return lines.slice(0, maxLines);
3881
- const half = Math.floor(maxLines / 2);
3882
- let start = Math.max(0, firstChange - half);
3883
- if (start + maxLines > lines.length) start = Math.max(0, lines.length - maxLines);
3884
- const kept = lines.slice(start, start + maxLines);
3885
- const omitted = lines.length - kept.length;
3886
- if (omitted > 0) {
3887
- kept.push({ kind: "context", text: ` \u2026 +${omitted} more lines` });
3888
- }
3889
- return kept;
3440
+ function isReadToolName(name) {
3441
+ return name === "readFile";
3890
3442
  }
3891
3443
  function isFailedToolResult(event) {
3892
3444
  const exitCode = event.metadata?.exitCode;
@@ -3894,9 +3446,6 @@ function isFailedToolResult(event) {
3894
3446
  if (typeof exitCode === "number" && exitCode !== 0) return true;
3895
3447
  return Boolean(event.metadata?.timedOut);
3896
3448
  }
3897
- function isNeedsActionToolResult(event) {
3898
- return Boolean(event.metadata?.actionGate);
3899
- }
3900
3449
  function parseUiAskChoiceForCli(event) {
3901
3450
  if (event.toolName !== "ask_user" && !event.metadata?.uiAskChoice) {
3902
3451
  return null;
@@ -3999,36 +3548,45 @@ function formatToolTraceLine(text, colorEnabled, accent = "none") {
3999
3548
  return `${dimCliText(text, true)}
4000
3549
  `;
4001
3550
  }
3551
+ var cleanUserText = (value) => stripAnsi2(value).replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
4002
3552
  function renderRunCard(snapshot, opts) {
4003
3553
  const labels = agentRunCardLabels();
4004
3554
  const timing = { startedAt: snapshot.startedAt, finishedAt: snapshot.finishedAt };
4005
- const name = snapshot.agentName ?? "agent";
4006
- if (isAgentRunTerminalStatus(snapshot.status)) {
4007
- return formatFinishedRunCard(name, snapshot.status, {
4008
- runId: snapshot.runId,
4009
- toolCallCount: snapshot.toolCallCount,
4010
- lastToolNames: snapshot.lastToolNames,
4011
- lastAssistantText: snapshot.lastAssistantText,
4012
- errorMessage: snapshot.errorMessage,
4013
- logLines: snapshot.logLines,
4014
- timing,
4015
- ...opts?.includeLogTail !== void 0 ? { includeLogTail: opts.includeLogTail } : {},
4016
- labels
4017
- });
4018
- }
4019
- return formatStatusRunCard(name, snapshot.status, {
3555
+ const safe = opts?.safe === true;
3556
+ const name = safe ? cleanUserText(snapshot.agentName ?? "agent") : snapshot.agentName ?? "agent";
3557
+ const source = safe ? {
3558
+ ...snapshot,
3559
+ agentName: snapshot.agentName ? cleanUserText(snapshot.agentName) : snapshot.agentName,
3560
+ taskPreview: snapshot.taskPreview ? cleanUserText(snapshot.taskPreview) : snapshot.taskPreview,
3561
+ lastAssistantText: snapshot.lastAssistantText ? cleanUserText(snapshot.lastAssistantText) : snapshot.lastAssistantText,
3562
+ lastToolNames: snapshot.lastToolNames?.map(cleanUserText)
3563
+ } : snapshot;
3564
+ const hadError = safe && Boolean(source.errorMessage?.trim());
3565
+ const errorFields = safe ? { errorMessage: void 0, logLines: void 0 } : { errorMessage: source.errorMessage, logLines: source.logLines };
3566
+ const body = isAgentRunTerminalStatus(snapshot.status) ? formatFinishedRunCard(name, snapshot.status, {
3567
+ runId: snapshot.runId,
3568
+ toolCallCount: source.toolCallCount,
3569
+ lastToolNames: source.lastToolNames,
3570
+ lastAssistantText: source.lastAssistantText,
3571
+ ...errorFields,
3572
+ timing,
3573
+ ...opts?.includeLogTail !== void 0 ? { includeLogTail: opts.includeLogTail } : {},
3574
+ labels
3575
+ }) : formatStatusRunCard(name, snapshot.status, {
4020
3576
  runId: snapshot.runId,
4021
- toolCallCount: snapshot.toolCallCount,
4022
- lastToolNames: snapshot.lastToolNames,
4023
- lastAssistantText: snapshot.lastAssistantText,
4024
- errorMessage: snapshot.errorMessage,
4025
- logLines: snapshot.logLines,
3577
+ toolCallCount: source.toolCallCount,
3578
+ lastToolNames: source.lastToolNames,
3579
+ lastAssistantText: source.lastAssistantText,
3580
+ ...errorFields,
4026
3581
  timing,
4027
3582
  ...opts?.includeLogTail !== void 0 ? { includeLogTail: opts.includeLogTail } : {},
4028
3583
  labels
4029
3584
  });
3585
+ return hadError ? `${body}
3586
+ error ${t("runDiagnosticsHidden")}` : body;
4030
3587
  }
4031
- function recoverOrchestrationCard(event, toolName) {
3588
+ function recoverOrchestrationCard(event, toolName, opts) {
3589
+ const safe = opts?.safe === true;
4032
3590
  const content = typeof event.content === "string" ? event.content : "";
4033
3591
  const trimmed = content.trim();
4034
3592
  if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
@@ -4059,27 +3617,26 @@ function recoverOrchestrationCard(event, toolName) {
4059
3617
  if (!parsedEvent) return null;
4060
3618
  const { kind, snapshot } = parsedEvent;
4061
3619
  if (kind === "start") {
4062
- return formatStartRunCard(snapshot.agentName ?? "agent", snapshot.status, {
4063
- task: snapshot.taskPreview,
3620
+ const name = safe ? cleanUserText(snapshot.agentName ?? "agent") : snapshot.agentName ?? "agent";
3621
+ const task = snapshot.taskPreview ? safe ? cleanUserText(snapshot.taskPreview) : snapshot.taskPreview : snapshot.taskPreview;
3622
+ return formatStartRunCard(name, snapshot.status, {
3623
+ task,
4064
3624
  runId: snapshot.runId,
4065
3625
  labels
4066
3626
  });
4067
3627
  }
4068
3628
  if (kind === "gone") return formatNotFoundRunCard(labels);
4069
3629
  if (kind === "stop") return formatStopRunCard(snapshot.status, labels);
4070
- return renderRunCard(snapshot);
3630
+ return renderRunCard(snapshot, opts);
4071
3631
  }
4072
- function parseControlAgentRunStatusEvent(event) {
4073
- const parsed = parseAgentRunEvent(event);
4074
- return parsed?.kind === "status" ? parsed.snapshot : null;
4075
- }
4076
- function formatOrchestrationCardBlock(event, toolName, colorEnabled) {
3632
+ function formatOrchestrationCardBlock(event, toolName, colorEnabled, opts) {
3633
+ const safe = opts?.safe === true;
4077
3634
  const rawLabel = toolLabel(toolName);
4078
3635
  const bakedCard = typeof event.metadata?.displayData === "string" && event.metadata.displayData.trim() ? event.metadata.displayData : "";
4079
- const rawDataStr = recoverOrchestrationCard(event, toolName) || bakedCard || (typeof event.content === "string" ? event.content : "");
3636
+ const rawDataStr = recoverOrchestrationCard(event, toolName, { safe }) || bakedCard || (typeof event.content === "string" ? event.content : "");
4080
3637
  const failed = event.type === "tool-error" || isFailedToolResult(event) || Boolean(event.metadata?.failed) || /^Error:/i.test(rawDataStr.trim());
4081
3638
  if (failed) {
4082
- const firstLine = rawDataStr.trim().split("\n")[0] || event.summary || event.message || t("toolFailed");
3639
+ const firstLine = safe ? t("toolFailed") : rawDataStr.trim().split("\n")[0] || event.summary || event.message || t("toolFailed");
4083
3640
  const message = clip(firstLine, 96);
4084
3641
  if (!colorEnabled) {
4085
3642
  return `\u2717 ${rawLabel} ${message}
@@ -4092,11 +3649,12 @@ function formatOrchestrationCardBlock(event, toolName, colorEnabled) {
4092
3649
  `;
4093
3650
  }
4094
3651
  const displayData = rawDataStr.trim();
4095
- const lines = displayData ? displayData.split("\n").filter((line) => !/^\s*agent\s+agent\s*$/.test(line)) : [];
3652
+ const lines = displayData ? displayData.split("\n") : [];
3653
+ const projected = safe ? sanitizeRunCardForNormal(lines) : lines;
4096
3654
  if (!colorEnabled) {
4097
3655
  let out2 = `\u25CF ${rawLabel}
4098
3656
  `;
4099
- for (const line of lines) {
3657
+ for (const line of projected) {
4100
3658
  out2 += ` ${line}
4101
3659
  `;
4102
3660
  }
@@ -4106,65 +3664,66 @@ function formatOrchestrationCardBlock(event, toolName, colorEnabled) {
4106
3664
  const labelPart = themeText(rawLabel, "muted", true);
4107
3665
  let out = `${bullet} ${labelPart}
4108
3666
  `;
4109
- for (const line of lines) {
3667
+ for (const line of projected) {
4110
3668
  out += ` ${themeText(line, "muted", true)}
4111
3669
  `;
4112
3670
  }
4113
3671
  return out;
4114
3672
  }
4115
- function mergeRunSnapshot(previous, next) {
4116
- return {
4117
- ...previous,
4118
- ...next,
4119
- errorMessage: next.errorMessage ?? previous.errorMessage,
4120
- logLines: next.logLines ?? previous.logLines,
4121
- logKey: next.logKey || previous.logKey,
4122
- toolCallCount: next.toolCallCount ?? previous.toolCallCount,
4123
- lastToolNames: next.lastToolNames ?? previous.lastToolNames,
4124
- lastAssistantText: next.lastAssistantText ?? previous.lastAssistantText,
4125
- startedAt: next.startedAt ?? previous.startedAt,
4126
- finishedAt: next.finishedAt ?? previous.finishedAt
4127
- };
4128
- }
4129
- function formatFoldedControlStatusCard(snapshot, colorEnabled) {
4130
- const body = renderRunCard(snapshot, { includeLogTail: snapshot.includeLogTail });
4131
- return formatOrchestrationCardBlock(
4132
- {
4133
- type: "tool-result",
4134
- round: 0,
4135
- toolCallId: `fold-${snapshot.runId}`,
4136
- toolName: "controlAgentRun",
4137
- content: "",
4138
- metadata: { displayData: body }
4139
- },
4140
- "controlAgentRun",
4141
- colorEnabled
4142
- );
4143
- }
4144
- function formatVerboseToolEvent(event, colorEnabled) {
4145
- const round = event.round + 1;
4146
- const detail = event.argumentsPreview ? ` ${event.argumentsPreview}` : "";
4147
- if (event.type === "tool-call") {
4148
- return formatToolTraceLine(`[nolo:tool] #${round} -> ${event.toolName}${detail}`, colorEnabled);
4149
- }
4150
- if (event.type === "tool-error") {
4151
- const elapsed2 = typeof event.elapsedMs === "number" ? ` ${event.elapsedMs}ms` : "";
4152
- return formatToolTraceLine(
4153
- `[nolo:tool] #${round} !! ${event.toolName}${elapsed2}: ${event.message ?? "failed"}`,
4154
- colorEnabled,
4155
- "error"
4156
- );
4157
- }
4158
- const elapsed = typeof event.elapsedMs === "number" ? ` ${event.elapsedMs}ms` : "";
4159
- if (event.type === "tool-result" && (event.toolName === "ask_user" || event.metadata?.uiAskChoice)) {
4160
- const block = formatUiAskChoiceBlock(event, colorEnabled);
4161
- if (block) return `${formatToolTraceLine(`[nolo:tool] #${round} <- ${event.toolName}${elapsed}`, colorEnabled)}${block}`;
3673
+ function sanitizeRunCardForNormal(lines) {
3674
+ const out = [];
3675
+ let errorIndent = null;
3676
+ for (const line of lines) {
3677
+ if (/^(log tail:?|日志尾部:?)$/i.test(line.trim())) {
3678
+ if (out.length > 0 && out[out.length - 1].trim() === "") out.pop();
3679
+ break;
3680
+ }
3681
+ if (/^\s*error\b/i.test(line)) {
3682
+ out.push(` error ${t("runDiagnosticsHidden")}`);
3683
+ errorIndent = line.length - line.trimStart().length;
3684
+ continue;
3685
+ }
3686
+ if (errorIndent !== null) {
3687
+ if (line.trim() === "") {
3688
+ errorIndent = null;
3689
+ out.push(line);
3690
+ continue;
3691
+ }
3692
+ const indent = line.length - line.trimStart().length;
3693
+ const isLabelRow = /^\s{2}[a-z][a-zA-Z0-9]*\s{2,}/.test(line);
3694
+ if (indent > errorIndent && !isLabelRow) continue;
3695
+ errorIndent = null;
3696
+ }
3697
+ out.push(line);
4162
3698
  }
4163
- const summary = event.summary ? ` ${event.summary}` : "";
4164
- return formatToolTraceLine(
4165
- `[nolo:tool] #${round} <- ${event.toolName}${elapsed}${summary}`,
4166
- colorEnabled
4167
- );
3699
+ return out;
3700
+ }
3701
+ var NORMAL_TOOL_GIST_MAX = 28;
3702
+ function gistClip(value, max = NORMAL_TOOL_GIST_MAX) {
3703
+ const oneLine = value.replace(/\s+/g, " ").trim();
3704
+ if (!oneLine) return "";
3705
+ return oneLine.length <= max ? oneLine : `${oneLine.slice(0, max - 1)}\u2026`;
3706
+ }
3707
+ function commandHeadGist(command) {
3708
+ const trimmed = command.replace(/\s+/g, " ").trim();
3709
+ if (!trimmed || /[|;&<>`$]/.test(trimmed)) return "";
3710
+ const tokens = trimmed.split(" ");
3711
+ if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0])) return "";
3712
+ if (["cd", "pushd", "popd", "source", "."].includes(tokens[0])) return "";
3713
+ return gistClip(tokens.slice(0, 2).join(" "), 24);
3714
+ }
3715
+ function pathBasenameGist(path) {
3716
+ const segments = path.split(/[\\/]/).filter((segment) => segment.length > 0);
3717
+ const base = segments.pop();
3718
+ return base ? gistClip(base) : "";
3719
+ }
3720
+ function normalToolGist(event) {
3721
+ const metadata = event.metadata ?? {};
3722
+ const path = typeof metadata.path === "string" ? metadata.path : "";
3723
+ if (path) return pathBasenameGist(path);
3724
+ const command = typeof metadata.command === "string" ? metadata.command : "";
3725
+ if (command) return commandHeadGist(command);
3726
+ return "";
4168
3727
  }
4169
3728
  function formatNormalToolLine(event, pending, colorEnabled) {
4170
3729
  if (event.type === "tool-call") return "";
@@ -4176,10 +3735,10 @@ function formatNormalToolLine(event, pending, colorEnabled) {
4176
3735
  if (block) return block;
4177
3736
  }
4178
3737
  if (event.type === "tool-result" && (toolName === "listAgents" || toolName === "startAgentRun" || toolName === "controlAgentRun")) {
4179
- return formatOrchestrationCardBlock(event, toolName, colorEnabled);
3738
+ return formatOrchestrationCardBlock(event, toolName, colorEnabled, { safe: true });
4180
3739
  }
4181
3740
  if (event.type === "tool-result" && toolName === "loadSkill") {
4182
- return formatLoadSkillBlock(event, colorEnabled) ?? "";
3741
+ return formatLoadSkillBlock(event, colorEnabled, { safe: true }) ?? "";
4183
3742
  }
4184
3743
  const label = toolLabel(toolName);
4185
3744
  if (readActionGate(event.metadata?.actionGate)) {
@@ -4194,150 +3753,8 @@ function formatNormalToolLine(event, pending, colorEnabled) {
4194
3753
  if (isFailedToolResult(event)) {
4195
3754
  return formatToolTraceLine(`\u25B8 ${label} \u2717 ${t("toolFailed")}`, colorEnabled, "error");
4196
3755
  }
4197
- return formatToolTraceLine(`\u25B8 ${label} \u2713`, colorEnabled);
4198
- }
4199
- function isReadToolName(name) {
4200
- if (!name) return false;
4201
- return name === "read" || name === "readFile" || name === "read_file" || name === "readWorkspaceFile";
4202
- }
4203
- function isSearchToolName(name) {
4204
- if (!name) return false;
4205
- 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";
4206
- }
4207
- function isRunToolName(name) {
4208
- if (!name) return false;
4209
- return name === "execShell" || name === "runCommand" || name === "run_command" || name === "launchProcess";
4210
- }
4211
- function isFetchToolName(name) {
4212
- if (!name) return false;
4213
- return name === "fetchWebpage" || name === "fetch_webpage";
4214
- }
4215
- function isWebSearchToolName(name) {
4216
- if (!name) return false;
4217
- return name === "exa_search" || name === "exaSearch";
4218
- }
4219
- function isRunResultFoldable(event) {
4220
- return Boolean(event.metadata?.actionGate) === false;
4221
- }
4222
- function formatSearchTreeBlockForCli(items, colorEnabled) {
4223
- if (items.length === 0) return "";
4224
- const { count, lines } = formatSearchTreeLines(items);
4225
- const titleText = toolLabel("codeSearch");
4226
- if (!colorEnabled) {
4227
- const headerLine2 = `\u2022 ${titleText} (${count})
4228
- `;
4229
- const treeLines2 = lines.map((l) => ` ${l.connector}${l.queryText}`).join("\n");
4230
- return `${headerLine2}${treeLines2}
4231
- `;
4232
- }
4233
- const bullet = themeText("\u2022", "chrome", true);
4234
- const title = styleCliText(titleText, "bold", true);
4235
- const countText = themeText(`(${count})`, "muted", true);
4236
- const headerLine = `${bullet} ${title} ${countText}
4237
- `;
4238
- const treeLines = lines.map((l) => {
4239
- const connector = themeText(` ${l.connector}`, "chrome", true);
4240
- const queryText = themeText(l.queryText, "muted", true);
4241
- return `${connector}${queryText}`;
4242
- }).join("\n");
4243
- return `${headerLine}${treeLines}
4244
- `;
4245
- }
4246
- function formatReadTreeBlockForCli(items, colorEnabled) {
4247
- if (items.length === 0) return "";
4248
- const { count, lines } = formatReadTreeLines(items);
4249
- const titleText = toolLabel("readFile");
4250
- if (!colorEnabled) {
4251
- const headerLine2 = `\u2022 ${titleText} (${count})
4252
- `;
4253
- const treeLines2 = lines.map((l) => ` ${l.connector}${l.pathWithRange}`).join("\n");
4254
- return `${headerLine2}${treeLines2}
4255
- `;
4256
- }
4257
- const bullet = themeText("\u2022", "chrome", true);
4258
- const title = styleCliText(titleText, "bold", true);
4259
- const countText = themeText(`(${count})`, "muted", true);
4260
- const headerLine = `${bullet} ${title} ${countText}
4261
- `;
4262
- const treeLines = lines.map((l) => {
4263
- const connector = themeText(` ${l.connector}`, "chrome", true);
4264
- const pathText = themeText(l.pathWithRange, "muted", true);
4265
- return `${connector}${pathText}`;
4266
- }).join("\n");
4267
- return `${headerLine}${treeLines}
4268
- `;
4269
- }
4270
- function formatRunTreeBlockForCli(items, colorEnabled) {
4271
- if (items.length === 0) return "";
4272
- const { count, lines } = formatRunTreeLines(items);
4273
- const titleText = toolLabel("execShell");
4274
- if (!colorEnabled) {
4275
- const headerLine2 = `\u2022 ${titleText} (${count})
4276
- `;
4277
- const treeLines2 = lines.map((l) => ` ${l.connector}${l.commandText}`).join("\n");
4278
- return `${headerLine2}${treeLines2}
4279
- `;
4280
- }
4281
- const bullet = themeText("\u2022", "chrome", true);
4282
- const title = styleCliText(titleText, "bold", true);
4283
- const countText = themeText(`(${count})`, "muted", true);
4284
- const headerLine = `${bullet} ${title} ${countText}
4285
- `;
4286
- const treeLines = lines.map((l) => {
4287
- const connector = themeText(` ${l.connector}`, "chrome", true);
4288
- const commandText = themeText(l.commandText, "muted", true);
4289
- return `${connector}${commandText}`;
4290
- }).join("\n");
4291
- return `${headerLine}${treeLines}
4292
- `;
4293
- }
4294
- function formatWebSearchTreeBlockForCli(items, colorEnabled) {
4295
- if (items.length === 0) return "";
4296
- const { count, lines } = formatSearchTreeLines(items);
4297
- const titleText = toolLabel("exa_search");
4298
- if (!colorEnabled) {
4299
- const headerLine2 = `\u2022 ${titleText} (${count})
4300
- `;
4301
- const treeLines2 = lines.map((l) => ` ${l.connector}${l.queryText}`).join("\n");
4302
- return `${headerLine2}${treeLines2}
4303
- `;
4304
- }
4305
- const bullet = themeText("\u2022", "chrome", true);
4306
- const title = styleCliText(titleText, "bold", true);
4307
- const countText = themeText(`(${count})`, "muted", true);
4308
- const headerLine = `${bullet} ${title} ${countText}
4309
- `;
4310
- const treeLines = lines.map((l) => {
4311
- const connector = themeText(` ${l.connector}`, "chrome", true);
4312
- const queryText = themeText(l.queryText, "muted", true);
4313
- return `${connector}${queryText}`;
4314
- }).join("\n");
4315
- return `${headerLine}${treeLines}
4316
- `;
4317
- }
4318
- function formatFetchTreeBlockForCli(items, colorEnabled) {
4319
- if (items.length === 0) return "";
4320
- const { count, lines } = formatFetchTreeLines(items);
4321
- const titleText = toolLabel("fetchWebpage");
4322
- if (!colorEnabled) {
4323
- const headerLine2 = `\u2022 ${titleText} (${count})
4324
- `;
4325
- const treeLines2 = lines.map((l) => ` ${l.connector}${l.urlText}`).join("\n");
4326
- return `${headerLine2}${treeLines2}
4327
- `;
4328
- }
4329
- const bullet = themeText("\u2022", "chrome", true);
4330
- const title = styleCliText(titleText, "bold", true);
4331
- const countText = themeText(`(${count})`, "muted", true);
4332
- const headerLine = `${bullet} ${title} ${countText}
4333
- `;
4334
- const treeLines = lines.map((l) => {
4335
- const connector = themeText(` ${l.connector}`, "chrome", true);
4336
- const urlText = themeText(l.urlText, "muted", true);
4337
- return `${connector}${urlText}`;
4338
- }).join("\n");
4339
- return `${headerLine}${treeLines}
4340
- `;
3756
+ const gist = normalToolGist(event);
3757
+ return formatToolTraceLine(gist ? `\u25B8 ${label} \xB7 ${gist} \u2713` : `\u25B8 ${label} \u2713`, colorEnabled);
4341
3758
  }
4342
3759
  function resolveLoadSkillName(event) {
4343
3760
  const metaName = typeof event.metadata?.name === "string" ? event.metadata.name : void 0;
@@ -4382,14 +3799,14 @@ function formatTodoListForCli(event, colorEnabled) {
4382
3799
  const text = [`\u2611 Todo (${todos.length})`, ...lines].join("\n") + "\n";
4383
3800
  return colorEnabled ? themeText(text, "chrome") : text;
4384
3801
  }
4385
- function formatLoadSkillBlock(event, colorEnabled) {
3802
+ function formatLoadSkillBlock(event, colorEnabled, opts) {
4386
3803
  if (event.type !== "tool-result" || event.toolName !== "loadSkill") return null;
4387
3804
  const skillName = resolveLoadSkillName(event);
4388
3805
  const content = typeof event.content === "string" ? event.content : "";
4389
3806
  const failed = /^Skill\s+"[^"]*"\s+not found/.test(content) || isFailedToolResult(event);
4390
3807
  const labelText = t("usedSkillLabel");
4391
3808
  if (failed) {
4392
- const message = clip(content.split("\n")[0] || t("toolFailed"), 96);
3809
+ const message = opts?.safe === true ? t("toolFailed") : clip(content.split("\n")[0] || t("toolFailed"), 96);
4393
3810
  return formatToolTraceLine(`\u25B8 ${labelText} (${skillName}) \u2717 ${message}`, colorEnabled, "error");
4394
3811
  }
4395
3812
  if (!colorEnabled) {
@@ -4402,326 +3819,63 @@ function formatLoadSkillBlock(event, colorEnabled) {
4402
3819
  return `${star} ${labelPart}: ${namePart}
4403
3820
  `;
4404
3821
  }
4405
- function formatCompactToolLine(event, pending, colorEnabled) {
4406
- const toolName = event.toolName || pending?.toolName || "tool";
4407
- const todoBlock = formatTodoListForCli(event, colorEnabled);
4408
- if (todoBlock) return todoBlock;
4409
- if (isReadToolName(toolName) && event.type === "tool-result") {
4410
- 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 || "";
4411
- return formatReadTreeBlockForCli([{ path: rawPath, metadata: event.metadata }], colorEnabled);
4412
- }
4413
- if (isSearchToolName(toolName) && event.type === "tool-result") {
4414
- 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 || "";
4415
- const rawPath = typeof event.metadata?.path === "string" ? event.metadata.path : void 0;
4416
- return formatSearchTreeBlockForCli([{ query: rawQuery, path: rawPath }], colorEnabled);
4417
- }
4418
- if (isFetchToolName(toolName) && event.type === "tool-result") {
4419
- const rawUrl = (typeof event.metadata?.url === "string" ? event.metadata.url : void 0) || event.argumentsPreview || pending?.argumentsPreview || "";
4420
- return formatFetchTreeBlockForCli([{ url: rawUrl }], colorEnabled);
4421
- }
4422
- if (isRunToolName(toolName) && event.type === "tool-result" && isRunResultFoldable(event)) {
4423
- const rawCommand = (typeof event.metadata?.command === "string" ? event.metadata.command : void 0) || event.argumentsPreview || pending?.argumentsPreview || "";
4424
- const exitCode = typeof event.metadata?.exitCode === "number" ? event.metadata.exitCode : void 0;
4425
- const timedOut = Boolean(event.metadata?.timedOut);
4426
- return formatRunTreeBlockForCli([{ command: rawCommand, exitCode, timedOut }], colorEnabled);
4427
- }
4428
- const rawArgs = clipPathAware(event.argumentsPreview || pending?.argumentsPreview || "", 72);
4429
- const rawLabel = toolLabel(toolName);
4430
- const label = rawArgs ? `${rawLabel} ${rawArgs}` : rawLabel;
4431
- if (event.type === "tool-error") {
4432
- const message = clip(event.message ?? t("toolFailed"), 96);
4433
- return formatToolTraceLine(`\u25B8 ${label} \u2717 ${message}`, colorEnabled, "error");
4434
- }
4435
- const loadSkillBlock = formatLoadSkillBlock(event, colorEnabled);
4436
- if (loadSkillBlock) return loadSkillBlock;
4437
- if (event.type === "tool-result" && (toolName === "listAgents" || toolName === "startAgentRun" || toolName === "controlAgentRun")) {
4438
- return formatOrchestrationCardBlock(event, toolName, colorEnabled);
4439
- }
4440
- if (event.type === "tool-result" && (event.toolName === "ask_user" || event.metadata?.uiAskChoice)) {
4441
- const block = formatUiAskChoiceBlock(event, colorEnabled);
4442
- if (block) return block;
4443
- }
4444
- const hint = compactResultHint(event);
4445
- const suffix = hint.inline ? ` ${hint.inline}` : "";
4446
- const failed = isFailedToolResult(event);
4447
- const marker = failed ? "\u2717" : isNeedsActionToolResult(event) ? "!" : "\u2713";
4448
- let mainLine;
4449
- if (!colorEnabled) {
4450
- mainLine = `\u25B8 ${label} ${marker}${suffix}
4451
- `;
4452
- } else {
4453
- const chromePointer = themeText("\u25B8", "chrome", true);
4454
- const mutedLabel = themeText(rawLabel, "muted", true);
4455
- const argsPart = rawArgs ? ` ${dimCliText(rawArgs, true)}` : "";
4456
- const statusToken = failed ? themeText("\u2717", "danger", true) : isNeedsActionToolResult(event) ? themeText("!", "warning", true) : themeText("\u2713", "success", true);
4457
- const suffixPart = hint.inline ? ` ${dimCliText(hint.inline, true)}` : "";
4458
- mainLine = `${chromePointer} ${mutedLabel}${argsPart} ${statusToken}${suffixPart}
4459
- `;
4460
- }
4461
- if (!hint.detail?.length) return mainLine;
4462
- const filePath = typeof event.metadata?.path === "string" ? event.metadata.path : event.argumentsPreview;
4463
- return `${mainLine}${formatEditDetailBlock(hint.detail, colorEnabled, filePath)}`;
4464
- }
4465
- function formatEditDetailBlock(lines, colorEnabled, filePath, env = process.env) {
4466
- if (!colorEnabled) {
4467
- return lines.map((line) => ` ${line.text}
4468
- `).join("");
4469
- }
4470
- const isTruecolor = supportsTruecolor(env);
4471
- const lang = isTruecolor ? detectCodeLangFromPath(filePath) : "unknown";
4472
- const brightness = resolveTuiBrightness(env);
4473
- const padTo = Math.max(...lines.map((line) => displayWidth(line.text))) + 1;
4474
- return lines.map((line) => ` ${renderDiffLine({
4475
- kind: line.kind,
4476
- text: line.text,
4477
- highlightedText: shouldHighlightEditLine(line, lang, isTruecolor) ? buildHighlightedEditLine(line, lang, brightness, env) : void 0,
4478
- padTo,
4479
- colorEnabled: true,
4480
- env
4481
- })}
4482
- `).join("");
4483
- }
4484
- function shouldHighlightEditLine(line, lang, isTruecolor) {
4485
- if (!isTruecolor || lang === "unknown") return false;
4486
- if (line.text.startsWith(" \u2026") || line.text.startsWith("\u2026")) return false;
4487
- return line.text.length >= 2;
4488
- }
4489
- function buildHighlightedEditLine(line, lang, brightness, env) {
4490
- const prefix = line.text.slice(0, 2);
4491
- const body = line.text.slice(2);
4492
- const prefixToken = line.kind === "added" ? "success" : line.kind === "removed" ? "danger" : "chrome";
4493
- const coloredPrefix = themeText(prefix, prefixToken, true, env);
4494
- const highlightedBody = highlightCodeLine(body, lang, brightness);
4495
- return `${coloredPrefix}${highlightedBody}`;
4496
- }
4497
- function createToolEventFormatter(mode, colorEnabled = resolveCliColorEnabled(), opts = {}) {
4498
- const suppressRunProgressCards = opts.suppressRunProgressCards === true;
3822
+ var TUI_TREE_MARKER = "TUI_TREE\n";
3823
+ var TUI_TREE_END = "";
3824
+ function createToolEventFormatter(colorEnabled = resolveCliColorEnabled(), opts = {}) {
4499
3825
  const pending = /* @__PURE__ */ new Map();
4500
- let readBuffer = [];
4501
- let searchBuffer = [];
4502
- let runBuffer = [];
4503
- let fetchBuffer = [];
4504
- let webSearchBuffer = [];
4505
- let statusFold = null;
4506
- const lastEmittedLogByRunId = /* @__PURE__ */ new Map();
4507
- const lastPrintedCardByRunId = /* @__PURE__ */ new Map();
4508
- const cardSubstance = (snapshot) => JSON.stringify([
4509
- snapshot.status,
4510
- snapshot.toolCallCount ?? -1,
4511
- snapshot.lastToolNames ?? [],
4512
- snapshot.lastAssistantText ?? "",
4513
- snapshot.errorMessage ?? "",
4514
- snapshot.logKey
4515
- ]);
4516
- const flushStatusFold = () => {
4517
- if (!statusFold) return "";
4518
- const fold = statusFold;
4519
- statusFold = null;
4520
- const substance = cardSubstance(fold);
4521
- if (lastPrintedCardByRunId.get(fold.runId) === substance) return "";
4522
- const prevLog = lastEmittedLogByRunId.get(fold.runId);
4523
- const changed = Boolean(fold.logKey) && fold.logKey !== prevLog;
4524
- if (suppressRunProgressCards) {
4525
- const terminal = isAgentRunTerminalStatus(fold.status);
4526
- if (!terminal && !fold.errorMessage && !changed) {
4527
- lastPrintedCardByRunId.set(fold.runId, substance);
4528
- return "";
4529
- }
4530
- }
4531
- lastPrintedCardByRunId.set(fold.runId, substance);
4532
- if (changed && runShowsLogTail(fold.status)) {
4533
- lastEmittedLogByRunId.set(fold.runId, fold.logKey);
4534
- }
4535
- return formatFoldedControlStatusCard({ ...fold, includeLogTail: changed }, colorEnabled);
4536
- };
4537
- const flushToolBuffers = () => {
4538
- let out = "";
4539
- if (readBuffer.length > 0) {
4540
- const items = readBuffer.map((evt) => {
4541
- const call = pending.get(evt.toolCallId);
4542
- 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 || "";
4543
- return { path: rawPath, metadata: evt.metadata };
4544
- });
4545
- for (const evt of readBuffer) pending.delete(evt.toolCallId);
4546
- readBuffer = [];
4547
- out += formatReadTreeBlockForCli(items, colorEnabled);
4548
- }
4549
- if (searchBuffer.length > 0) {
4550
- const items = searchBuffer.map((evt) => {
4551
- const call = pending.get(evt.toolCallId);
4552
- 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 || "";
4553
- const rawPath = typeof evt.metadata?.path === "string" ? evt.metadata.path : void 0;
4554
- return { query: rawQuery, path: rawPath };
4555
- });
4556
- for (const evt of searchBuffer) pending.delete(evt.toolCallId);
4557
- searchBuffer = [];
4558
- out += formatSearchTreeBlockForCli(items, colorEnabled);
4559
- }
4560
- if (runBuffer.length > 0) {
4561
- const items = runBuffer.map((evt) => {
4562
- const call = pending.get(evt.toolCallId);
4563
- const rawCommand = (typeof evt.metadata?.command === "string" ? evt.metadata.command : void 0) || evt.argumentsPreview || call?.argumentsPreview || "";
4564
- const exitCode = typeof evt.metadata?.exitCode === "number" ? evt.metadata.exitCode : void 0;
4565
- const timedOut = Boolean(evt.metadata?.timedOut);
4566
- return { command: rawCommand, exitCode, timedOut };
4567
- });
4568
- for (const evt of runBuffer) pending.delete(evt.toolCallId);
4569
- runBuffer = [];
4570
- out += formatRunTreeBlockForCli(items, colorEnabled);
4571
- }
4572
- if (fetchBuffer.length > 0) {
4573
- const items = fetchBuffer.map((evt) => {
4574
- const call = pending.get(evt.toolCallId);
4575
- const rawUrl = (typeof evt.metadata?.url === "string" ? evt.metadata.url : void 0) || evt.argumentsPreview || call?.argumentsPreview || "";
4576
- return { url: rawUrl };
4577
- });
4578
- for (const evt of fetchBuffer) pending.delete(evt.toolCallId);
4579
- fetchBuffer = [];
4580
- out += formatFetchTreeBlockForCli(items, colorEnabled);
4581
- }
4582
- if (webSearchBuffer.length > 0) {
4583
- const items = webSearchBuffer.map((evt) => {
4584
- const call = pending.get(evt.toolCallId);
4585
- 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 || "";
4586
- return { query: rawQuery };
4587
- });
4588
- for (const evt of webSearchBuffer) pending.delete(evt.toolCallId);
4589
- webSearchBuffer = [];
4590
- out += formatWebSearchTreeBlockForCli(items, colorEnabled);
4591
- }
4592
- return out;
4593
- };
4594
- const flushBuffers = () => `${flushStatusFold()}${flushToolBuffers()}`;
4595
- const bufferToolResult = (buffer, event) => {
4596
- const flushed = flushStatusFold();
4597
- buffer.push(event);
4598
- return flushed;
3826
+ let tree = null;
3827
+ const treeKind = (name) => isRunToolName(name) ? "Run" : isReadToolName(name) ? "Read" : name === "exa_search" ? "Search" : name === "fetchWebpage" ? "Fetch" : null;
3828
+ const treeLine = (kind, items) => {
3829
+ const label = kind === "Run" ? toolLabel("execShell") : kind === "Read" ? toolLabel("readFile") : kind === "Fetch" ? toolLabel("fetchWebpage") : toolLabel("exa_search");
3830
+ return `${TUI_TREE_MARKER}${label} (${items.length})
3831
+ ${items.map((item, i) => `${i === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 "}${item} \u2713`).join("\n")}${TUI_TREE_END}
3832
+ `;
4599
3833
  };
4600
- const formatter = (event) => {
4601
- if (mode === "hide") return "";
4602
- if (mode === "verbose") return formatVerboseToolEvent(event, colorEnabled);
4603
- if (mode === "normal") {
4604
- if (event.type === "tool-call") {
4605
- pending.set(event.toolCallId, {
4606
- toolName: event.toolName,
4607
- argumentsPreview: event.argumentsPreview
4608
- });
4609
- return "";
4610
- }
4611
- const call2 = pending.get(event.toolCallId);
4612
- pending.delete(event.toolCallId);
4613
- return formatNormalToolLine(event, call2, colorEnabled);
4614
- }
4615
- if (event.toolName === "controlAgentRun") {
4616
- if (event.type === "tool-call") {
4617
- pending.set(event.toolCallId, {
4618
- toolName: event.toolName,
4619
- argumentsPreview: event.argumentsPreview
4620
- });
4621
- return "";
4622
- }
4623
- if (event.type === "tool-result") {
4624
- const snapshot = parseControlAgentRunStatusEvent(event);
4625
- if (snapshot) {
4626
- let out = flushToolBuffers();
4627
- const open = statusFold;
4628
- const sameRun = open?.runId === snapshot.runId;
4629
- if (open && (!sameRun || open.status !== snapshot.status)) {
4630
- out += flushStatusFold();
4631
- }
4632
- statusFold = open && sameRun ? mergeRunSnapshot(open, snapshot) : snapshot;
4633
- pending.delete(event.toolCallId);
4634
- if (isAgentRunTerminalStatus(snapshot.status)) {
4635
- out += flushBuffers();
4636
- }
4637
- return out;
4638
- }
4639
- const flushed2 = flushBuffers();
4640
- const call2 = pending.get(event.toolCallId);
4641
- pending.delete(event.toolCallId);
4642
- return `${flushed2}${formatCompactToolLine(event, call2, colorEnabled)}`;
4643
- }
4644
- }
4645
- if (isReadToolName(event.toolName)) {
4646
- if (event.type === "tool-call") {
4647
- pending.set(event.toolCallId, {
4648
- toolName: event.toolName,
4649
- argumentsPreview: event.argumentsPreview
4650
- });
4651
- return "";
4652
- }
4653
- if (event.type === "tool-result") {
4654
- return bufferToolResult(readBuffer, event);
4655
- }
4656
- }
4657
- if (isSearchToolName(event.toolName)) {
4658
- if (event.type === "tool-call") {
4659
- pending.set(event.toolCallId, {
4660
- toolName: event.toolName,
4661
- argumentsPreview: event.argumentsPreview
4662
- });
4663
- return "";
4664
- }
4665
- if (event.type === "tool-result") {
4666
- return bufferToolResult(searchBuffer, event);
4667
- }
4668
- }
4669
- if (isRunToolName(event.toolName)) {
4670
- if (event.type === "tool-result" && !isRunResultFoldable(event)) {
4671
- const flushed2 = flushBuffers();
4672
- const call2 = pending.get(event.toolCallId);
4673
- pending.delete(event.toolCallId);
4674
- return `${flushed2}${formatCompactToolLine(event, call2, colorEnabled)}`;
4675
- }
4676
- if (event.type === "tool-call") {
4677
- pending.set(event.toolCallId, {
4678
- toolName: event.toolName,
4679
- argumentsPreview: event.argumentsPreview
4680
- });
4681
- return "";
4682
- }
4683
- if (event.type === "tool-result") {
4684
- return bufferToolResult(runBuffer, event);
4685
- }
4686
- }
4687
- if (isFetchToolName(event.toolName)) {
4688
- if (event.type === "tool-call") {
4689
- pending.set(event.toolCallId, {
4690
- toolName: event.toolName,
4691
- argumentsPreview: event.argumentsPreview
4692
- });
4693
- return "";
4694
- }
4695
- if (event.type === "tool-result") {
4696
- return bufferToolResult(fetchBuffer, event);
4697
- }
3834
+ const formatTreeEvent = (event, call) => {
3835
+ if (!opts.tuiTrees || event.type !== "tool-result") return null;
3836
+ if (isFailedToolResult(event) || event.metadata?.failed || event.metadata?.timedOut || readActionGate(event.metadata?.actionGate)) {
3837
+ tree = null;
3838
+ return null;
4698
3839
  }
4699
- if (isWebSearchToolName(event.toolName)) {
4700
- if (event.type === "tool-call") {
4701
- pending.set(event.toolCallId, {
4702
- toolName: event.toolName,
4703
- argumentsPreview: event.argumentsPreview
4704
- });
4705
- return "";
4706
- }
4707
- if (event.type === "tool-result") {
4708
- return bufferToolResult(webSearchBuffer, event);
4709
- }
3840
+ const name = event.toolName || call?.toolName || "tool";
3841
+ const kind = treeKind(name);
3842
+ if (!kind) {
3843
+ tree = null;
3844
+ return null;
4710
3845
  }
4711
- const flushed = flushBuffers();
3846
+ let item = "";
3847
+ const m = event.metadata ?? {};
3848
+ if (kind === "Run") {
3849
+ const command = typeof m.command === "string" ? m.command : "";
3850
+ item = command ? formatRunItemCommand(command, typeof m.exitCode === "number" ? m.exitCode : void 0, Boolean(m.timedOut)) : "command";
3851
+ }
3852
+ if (kind === "Read") item = formatReadItemPath(typeof m.path === "string" ? m.path : typeof m.filePath === "string" ? m.filePath : "file", m);
3853
+ 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);
3854
+ if (kind === "Fetch") item = formatFetchItemUrl(typeof m.url === "string" ? m.url : "webpage");
3855
+ if (!item) item = toolLabel(name);
3856
+ if (tree?.kind !== kind) tree = { kind, items: [] };
3857
+ tree.items.push(item);
3858
+ if (tree.items.length < 2) return formatNormalToolLine(event, call, colorEnabled);
3859
+ return treeLine(kind, tree.items);
3860
+ };
3861
+ const format = (event) => {
4712
3862
  if (event.type === "tool-call") {
4713
3863
  pending.set(event.toolCallId, {
4714
3864
  toolName: event.toolName,
4715
3865
  argumentsPreview: event.argumentsPreview
4716
3866
  });
4717
- return flushed;
3867
+ return "";
4718
3868
  }
4719
3869
  const call = pending.get(event.toolCallId);
4720
3870
  pending.delete(event.toolCallId);
4721
- return `${flushed}${formatCompactToolLine(event, call, colorEnabled)}`;
3871
+ const treeOutput = formatTreeEvent(event, call);
3872
+ if (treeOutput !== null) return treeOutput;
3873
+ return formatNormalToolLine(event, call, colorEnabled);
3874
+ };
3875
+ format.reset = () => {
3876
+ tree = null;
4722
3877
  };
4723
- formatter.flush = flushBuffers;
4724
- return formatter;
3878
+ return format;
4725
3879
  }
4726
3880
  function createSseToolEventAdapter(onEvent) {
4727
3881
  let round = 0;
@@ -4882,7 +4036,7 @@ ${this.text}
4882
4036
  0,
4883
4037
  Math.floor((Date.now() - this.startTime) / 1e3)
4884
4038
  );
4885
- const thinkingPart = this.thinkingHint ? `: ${truncateThinkingHint(this.thinkingHint, 60)}` : "";
4039
+ const thinkingPart = this.thinkingHint ? dimCliText(`: ${truncateThinkingHint(this.thinkingHint, 60)}`) : "";
4886
4040
  return `${themeColorSequence("accent")}${frame}\x1B[39m ${this.text}${thinkingPart} (${formatElapsed(elapsedSeconds)})`;
4887
4041
  }
4888
4042
  };
@@ -4939,10 +4093,8 @@ function createCliTurnOutput(params) {
4939
4093
  const { options } = params;
4940
4094
  const workingLabel = params.workingLabel ?? `${options.agentName} -> working`;
4941
4095
  const spinner = params.spinner ?? new Spinner(options.output, workingLabel, Boolean(options.activityReporter));
4942
- const toolDisplayMode = resolveToolDisplayMode(options.env);
4943
- const traceLocalTools = shouldEmitToolEvents(toolDisplayMode);
4944
- const formatToolEvent = createToolEventFormatter(toolDisplayMode, void 0, {
4945
- suppressRunProgressCards: typeof options.onAgentRunStatus === "function"
4096
+ const formatToolEvent = createToolEventFormatter(void 0, {
4097
+ tuiTrees: options.output.tuiTrees === true
4946
4098
  });
4947
4099
  const eventMode = resolveAgentEventMode(options);
4948
4100
  const showThinking = options.showThinking !== false;
@@ -4950,12 +4102,27 @@ function createCliTurnOutput(params) {
4950
4102
  let everStreamedAnyText = false;
4951
4103
  let printedAssistantLabel = false;
4952
4104
  let thinkState = createThinkParserState();
4105
+ let thinkingFirstAt = null;
4106
+ let thinkingLastAt = 0;
4107
+ const markThinkingActivity = () => {
4108
+ const now = Date.now();
4109
+ if (thinkingFirstAt === null) thinkingFirstAt = now;
4110
+ thinkingLastAt = now;
4111
+ };
4112
+ const writeThinkingTrace = () => {
4113
+ if (thinkingFirstAt === null) return;
4114
+ const seconds = Math.max(0, Math.round((thinkingLastAt - thinkingFirstAt) / 1e3));
4115
+ thinkingFirstAt = null;
4116
+ if (seconds < 1) return;
4117
+ options.output.write(`${dimCliText(t("thinkingTraceLine", formatElapsed(seconds)))}
4118
+ `);
4119
+ };
4953
4120
  let compactionEvent = null;
4954
4121
  const assistantLabelManaged = options.output.assistantLabelManaged === true;
4955
4122
  const writeToolOutput = (chunk) => {
4956
4123
  if (!chunk) return;
4957
4124
  if (typeof options.output.writeToolBlock === "function") {
4958
- options.output.writeToolBlock(chunk);
4125
+ if (!options.output.writeToolBlock(chunk)) formatToolEvent.reset?.();
4959
4126
  } else {
4960
4127
  options.output.write(chunk);
4961
4128
  }
@@ -4965,13 +4132,16 @@ function createCliTurnOutput(params) {
4965
4132
  });
4966
4133
  const writeVisibleAssistantChunk = (chunk) => {
4967
4134
  if (!chunk) return;
4135
+ formatToolEvent.reset?.();
4968
4136
  const parsed = processThinkChunk(chunk, thinkState);
4969
4137
  thinkState = parsed.state;
4970
4138
  if (!parsed.content && !parsed.reasoning) return;
4971
4139
  if (showThinking && parsed.reasoning) {
4140
+ markThinkingActivity();
4972
4141
  spinner.setThinkingHint(parsed.reasoning);
4973
4142
  }
4974
4143
  if (!parsed.content) return;
4144
+ writeThinkingTrace();
4975
4145
  spinner.stop();
4976
4146
  options.activityReporter?.(null);
4977
4147
  if (!printedAssistantLabel) {
@@ -4986,7 +4156,6 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
4986
4156
  renderWriter.push(parsed.content);
4987
4157
  };
4988
4158
  const handleToolEvent = (event) => {
4989
- if (!traceLocalTools) return;
4990
4159
  const chunk = eventMode === "jsonl" ? formatToolJsonEvent(event) : formatToolEvent(event);
4991
4160
  if (eventMode === "jsonl") {
4992
4161
  options.output.write(chunk);
@@ -5004,8 +4173,8 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
5004
4173
  if (chunk) {
5005
4174
  writeToolOutput(chunk);
5006
4175
  }
5007
- if ((toolDisplayMode === "compact" || toolDisplayMode === "pro" || toolDisplayMode === "normal") && event.type === "tool-call") {
5008
- const activeLabel = toolDisplayMode === "normal" ? formatConservativeActiveToolLabel(event) : formatActiveToolLabel(event);
4176
+ if (event.type === "tool-call") {
4177
+ const activeLabel = formatConservativeActiveToolLabel(event);
5009
4178
  spinner.show(activeLabel);
5010
4179
  options.activityReporter?.(activeLabel);
5011
4180
  }
@@ -5018,20 +4187,15 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
5018
4187
  };
5019
4188
  return {
5020
4189
  spinner,
5021
- toolDisplayMode,
5022
- traceLocalTools,
5023
4190
  eventMode,
5024
4191
  pushText(chunk) {
5025
- if (eventMode !== "jsonl" && formatToolEvent.flush) {
5026
- const pendingToolOutput = formatToolEvent.flush();
5027
- if (pendingToolOutput) {
5028
- writeToolOutput(pendingToolOutput);
5029
- }
5030
- }
5031
4192
  writeVisibleAssistantChunk(chunk);
5032
4193
  },
5033
4194
  pushThinking(chunk) {
5034
- if (showThinking) spinner.setThinkingHint(chunk);
4195
+ if (showThinking) {
4196
+ markThinkingActivity();
4197
+ spinner.setThinkingHint(chunk);
4198
+ }
5035
4199
  },
5036
4200
  handleToolEvent,
5037
4201
  /** 记录一条 compaction 观测事件(TUI 在 turn 结束时渲染一行 dim 摘要)。 */
@@ -5046,15 +4210,12 @@ ${options.agentName}${IDENTITY_LABEL_SEPARATOR}`);
5046
4210
  finish(fallbackContent) {
5047
4211
  spinner.stop();
5048
4212
  options.activityReporter?.(null);
4213
+ writeThinkingTrace();
5049
4214
  const flushedThink = flushThinkParser(thinkState);
5050
4215
  thinkState = flushedThink.state;
5051
4216
  if (flushedThink.content) {
5052
4217
  writeVisibleAssistantChunk(flushedThink.content);
5053
4218
  }
5054
- const pendingToolOutput = formatToolEvent.flush ? formatToolEvent.flush() : "";
5055
- if (pendingToolOutput) {
5056
- writeToolOutput(pendingToolOutput);
5057
- }
5058
4219
  if (streamedAssistantText) {
5059
4220
  renderWriter.flush();
5060
4221
  options.output.write("\n");
@@ -5266,6 +4427,10 @@ ${describeClientVersionTooOldFailure(message, error)}`);
5266
4427
  function resolveAuthToken2(env) {
5267
4428
  return resolvePlatformAuthToken(env);
5268
4429
  }
4430
+ function resolveFileWriteGateEnabled(env) {
4431
+ const raw = (env.NOLO_CLI_WRITE_GATE ?? "").trim().toLowerCase();
4432
+ return raw !== "off" && raw !== "0" && raw !== "false";
4433
+ }
5269
4434
  function isMachineBoundLocalhostCustomProvider(agentConfig) {
5270
4435
  const machineId = agentConfig?.runtimeBinding && typeof agentConfig.runtimeBinding === "object" ? String(agentConfig.runtimeBinding.machineId ?? "").trim() : "";
5271
4436
  const providerUrl = asTrimmedString(agentConfig?.customProviderUrl);
@@ -5357,7 +4522,16 @@ function isKnownServerPlatformAgent(options) {
5357
4522
  // packages/core/collapsedPaste.ts
5358
4523
  var COLLAPSE_PASTE_MIN_LINES = 8;
5359
4524
  var COLLAPSE_PASTE_MIN_CHARS = 400;
5360
- var COLLAPSED_PASTE_PLACEHOLDER_RE = /\[paste #(\d+) · (\d+) lines\]/g;
4525
+ var COLLAPSED_PASTE_PLACEHOLDER_RE = (
4526
+ // 兼容两种格式:旧 `[paste #N · L lines]` 与新 `[paste #N · L lines · preview]`。
4527
+ // preview 段用负向先行断言排除模型引用(`…; full content available via
4528
+ // readPastedText(pasteId=N)`):legacy 无 scope 的模型引用与新 chip 形状重叠,
4529
+ // 若被当作 chip 匹配,跨会话残留的引用会被错误展开/替换(破坏 durable
4530
+ // fallback 语义)。preview 与模型引用尾段在生成时都不会包含该标记原文之外
4531
+ // 的歧义,此处按"完整模型引用尾段"精确排除。
4532
+ /\[paste #(\d+) · (\d+) lines(?: · (?![^\]]*; full content available via readPastedText\(pasteId=\d+\))([^\]]*))?\]/g
4533
+ );
4534
+ var COLLAPSED_PASTE_PREVIEW_MAX_CHARS = 24;
5361
4535
  var COLLAPSED_PASTE_MODEL_REFERENCE_RE = /\[paste #(\d+)(?: scope:([a-zA-Z0-9_-]+))? · [^\]]+; full content available via readPastedText\(pasteId=(\d+)\)\]/g;
5362
4536
  function countTextLines(text) {
5363
4537
  if (text.length === 0) return 0;
@@ -5397,9 +4571,22 @@ function estimatePasteBytes(text) {
5397
4571
  }
5398
4572
  return bytes;
5399
4573
  }
4574
+ function buildCollapsedPastePreview(text) {
4575
+ const firstNonEmptyLine = text.split(/\r\n|\r|\n/).find((line) => line.trim().length > 0) ?? "";
4576
+ let preview = compactWhitespace(firstNonEmptyLine);
4577
+ preview = preview.replace(new RegExp("\\]|\\p{C}", "gu"), "").trim();
4578
+ if (preview.length === 0) return "";
4579
+ const chars = Array.from(preview);
4580
+ if (chars.length > COLLAPSED_PASTE_PREVIEW_MAX_CHARS) {
4581
+ return chars.slice(0, COLLAPSED_PASTE_PREVIEW_MAX_CHARS).join("") + "\u2026";
4582
+ }
4583
+ return preview;
4584
+ }
5400
4585
  function formatCollapsedPastePlaceholder(id, text) {
5401
4586
  const lines = countTextLines(text);
5402
- return `[paste #${id} \xB7 ${lines} lines]`;
4587
+ const preview = buildCollapsedPastePreview(text);
4588
+ if (!preview) return `[paste #${id} \xB7 ${lines} lines]`;
4589
+ return `[paste #${id} \xB7 ${lines} lines \xB7 ${preview}]`;
5403
4590
  }
5404
4591
  function generatePasteScope() {
5405
4592
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
@@ -5512,9 +4699,65 @@ function findCollapsedPasteSpanAt(buffer, pos, opts = {}) {
5512
4699
  // packages/cli/client/agentRun.ts
5513
4700
  import { ulid } from "ulid";
5514
4701
  async function loadRunLocalAgentTurn() {
5515
- const { runLocalAgentTurn } = await import("./agentRuntimeLocal-SIQYQGSK.js");
4702
+ const { runLocalAgentTurn } = await import("./agentRuntimeLocal-SBG7BDFQ.js");
5516
4703
  return runLocalAgentTurn;
5517
4704
  }
4705
+ 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();
4706
+ function extractEmbeddedErrorMessage(message) {
4707
+ const match = /"message"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(message);
4708
+ if (!match) return void 0;
4709
+ try {
4710
+ const decoded = JSON.parse(`"${match[1]}"`);
4711
+ if (typeof decoded !== "string" || !decoded.trim()) return void 0;
4712
+ const cleaned = decoded.replace(/[\u0000-\u001f\u007f]/g, "");
4713
+ return cleaned.trim() ? cleaned : void 0;
4714
+ } catch {
4715
+ return void 0;
4716
+ }
4717
+ }
4718
+ function parseEmbeddedBalanceDetails(message) {
4719
+ const jsonStart = message.indexOf('{"error"');
4720
+ if (jsonStart < 0) return void 0;
4721
+ try {
4722
+ let depth = 0;
4723
+ let inString = false;
4724
+ let escaped = false;
4725
+ let jsonEnd = -1;
4726
+ for (let i = jsonStart; i < message.length; i += 1) {
4727
+ const char = message[i];
4728
+ if (inString) {
4729
+ if (escaped) escaped = false;
4730
+ else if (char === "\\") escaped = true;
4731
+ else if (char === '"') inString = false;
4732
+ } else if (char === '"') {
4733
+ inString = true;
4734
+ } else if (char === "{") {
4735
+ depth += 1;
4736
+ } else if (char === "}" && --depth === 0) {
4737
+ jsonEnd = i + 1;
4738
+ break;
4739
+ }
4740
+ }
4741
+ if (jsonEnd < 0) return void 0;
4742
+ const parsed = JSON.parse(message.slice(jsonStart, jsonEnd));
4743
+ if (!parsed || typeof parsed !== "object") return void 0;
4744
+ const error = parsed.error;
4745
+ if (!error || typeof error !== "object") return void 0;
4746
+ const details = error.details;
4747
+ if (!details || typeof details !== "object") return void 0;
4748
+ const requiredBalance = details.requiredBalance;
4749
+ const currentBalance = details.currentBalance;
4750
+ if (typeof requiredBalance !== "number" || typeof currentBalance !== "number") {
4751
+ return void 0;
4752
+ }
4753
+ if (!Number.isFinite(requiredBalance) || !Number.isFinite(currentBalance) || requiredBalance <= 0) {
4754
+ return void 0;
4755
+ }
4756
+ return { required: String(requiredBalance), current: String(currentBalance) };
4757
+ } catch {
4758
+ return void 0;
4759
+ }
4760
+ }
5518
4761
  async function resolveCurrentMachineId(options) {
5519
4762
  return options.currentMachineIdResolver ? options.currentMachineIdResolver(options.env) : detectCurrentMachineId(options.env);
5520
4763
  }
@@ -5745,7 +4988,6 @@ function describeLocalRunFailure(message, rawError) {
5745
4988
  busyDetail = rawError.detail.trim();
5746
4989
  }
5747
4990
  if (/PLATFORM_LLM_BUSY|服务器紧张/.test(message)) {
5748
- const stripDebugNoise = (s) => s.replace(/\s*raw=".*"/g, "").replace(/\s*raw=\S+/g, "").replace(/\s*headers=\[[^\]]*\]/g, "").replace(/\s*headers=\S+/g, "").trim();
5749
4991
  const shown = stripDebugNoise(
5750
4992
  message.replace(/\s*\(PLATFORM_LLM_BUSY\)\s*$/, "")
5751
4993
  );
@@ -5756,7 +4998,18 @@ function describeLocalRunFailure(message, rawError) {
5756
4998
  if (/UPSTREAM_402|Insufficient Balance|余额不足|insufficient\s+balance/i.test(
5757
4999
  message
5758
5000
  )) {
5759
- return `${RUN_UNAVAILABLE_PREFIX} (${message}). ${NO_FALLBACK} Top up your balance, then send again (or say "\u7EE7\u7EED") \u2014 if a dialog was kept, context is preserved.
5001
+ const cleanedMessage = stripDebugNoise(message);
5002
+ const fallback = cleanedMessage.replace(
5003
+ /^[^:]*provider failed: HTTP \d{3}\s*/,
5004
+ ""
5005
+ );
5006
+ const balanceDetails = parseEmbeddedBalanceDetails(cleanedMessage);
5007
+ const shownMessage = balanceDetails ? t(
5008
+ "balanceInsufficientReason",
5009
+ balanceDetails.required,
5010
+ balanceDetails.current
5011
+ ) : extractEmbeddedErrorMessage(cleanedMessage) ?? fallback;
5012
+ return `[nolo] ${shownMessage}
5760
5013
  `;
5761
5014
  }
5762
5015
  const cls = classifyLocalRunError(message);
@@ -6071,6 +5324,8 @@ async function runLocalAgentTurnForCli(options, settings) {
6071
5324
  contextReferenceResolver: (reference) => canResolveCollapsedPasteReference(options.pastedTextStore, reference)
6072
5325
  } : {},
6073
5326
  continueDialogId: currentDialogId,
5327
+ fileWriteSessionId: currentDialogId,
5328
+ fileWriteGateEnabled: resolveFileWriteGateEnabled(options.env),
6074
5329
  spaceId: options.spaceId,
6075
5330
  category: options.category,
6076
5331
  inheritedFromDialogKey: options.inheritedFromDialogKey,
@@ -6096,11 +5351,13 @@ async function runLocalAgentTurnForCli(options, settings) {
6096
5351
  options.onLoopEvent?.(event);
6097
5352
  },
6098
5353
  ...options.abortSignal ? { abortSignal: options.abortSignal } : {},
6099
- ...turnOutput.traceLocalTools ? {
6100
- onToolEvent: (event) => {
6101
- turnOutput.handleToolEvent(event);
6102
- }
6103
- } : {},
5354
+ // 回合内注入(TUI 后台 run 唤醒直投):透传给 local loop。
5355
+ ...options.drainInjections ? { drainInjections: options.drainInjections } : {},
5356
+ // tool-gist-fold 后 onToolEvent 无条件挂载(不再受 traceLocalTools 开关
5357
+ // 控制,显示模式合并为单一 gist/折叠通道)——保留 alpha 的新形态。
5358
+ onToolEvent: (event) => {
5359
+ turnOutput.handleToolEvent(event);
5360
+ },
6104
5361
  ...!options.noStream ? {
6105
5362
  onTextDelta: (chunk) => {
6106
5363
  turnOutput.pushText(chunk);
@@ -6158,6 +5415,43 @@ async function runLocalAgentTurnForCli(options, settings) {
6158
5415
  };
6159
5416
  }
6160
5417
  }
5418
+ async function checkLocalAvailabilityBeforeHttpDispatch(options) {
5419
+ const adapter = resolveLocalRuntimeAdapter(options);
5420
+ if (!adapter || typeof adapter.loadAgentConfig !== "function") return null;
5421
+ let config;
5422
+ try {
5423
+ config = await adapter.loadAgentConfig(options.agentKey);
5424
+ } catch {
5425
+ return null;
5426
+ }
5427
+ if (!config || typeof config !== "object") return null;
5428
+ const baseRecord = config.rawRecord ?? config;
5429
+ const credentialKey = resolveCredentialKeyWithFallback(baseRecord);
5430
+ const agentLevelAt = baseRecord.nextAvailableAt;
5431
+ const agentLevelNextAvailableAt = typeof agentLevelAt === "number" && Number.isFinite(agentLevelAt) ? agentLevelAt : void 0;
5432
+ if (!credentialKey && agentLevelNextAvailableAt === void 0) return null;
5433
+ const env = options.env;
5434
+ const now = Date.now();
5435
+ const entry = credentialKey ? await readCredentialEntry(credentialKey, env, now).catch(() => void 0) : void 0;
5436
+ const entryAt = entry?.nextAvailableAt;
5437
+ const effectiveNextAvailableAt = typeof entryAt === "number" ? mergeAvailabilityDeadline(agentLevelNextAvailableAt, entryAt) : agentLevelNextAvailableAt;
5438
+ if (typeof effectiveNextAvailableAt !== "number") return null;
5439
+ const gateDecision = resolveCooldownGate(
5440
+ { nextAvailableAt: effectiveNextAvailableAt, lastProbeAt: entry?.lastProbeAt },
5441
+ now
5442
+ );
5443
+ if (gateDecision === "probe" && credentialKey) {
5444
+ await recordCredentialProbe(credentialKey, env, now).catch(() => void 0);
5445
+ return null;
5446
+ }
5447
+ if (gateDecision !== "blocked") return null;
5448
+ options.output.write(
5449
+ `[nolo] Agent ${options.agentName || options.agentKey} is temporarily unavailable (429 cooldown) until ${new Date(Number(effectiveNextAvailableAt)).toISOString()}.
5450
+ Dispatch aborted before reaching the server. Pick another agent via listAgents, or retry after the cooldown.
5451
+ `
5452
+ );
5453
+ return { exitCode: 1 };
5454
+ }
6161
5455
  async function runAgentTurn(options) {
6162
5456
  const authToken = resolveAuthToken2(options.env);
6163
5457
  const runtimeMode = resolveRequestedRuntimeMode(options);
@@ -6222,26 +5516,50 @@ async function runAgentTurn(options) {
6222
5516
  );
6223
5517
  return { exitCode: 1 };
6224
5518
  }
5519
+ const localBlock = await checkLocalAvailabilityBeforeHttpDispatch(options);
5520
+ if (localBlock) {
5521
+ return { exitCode: localBlock.exitCode };
5522
+ }
6225
5523
  return runHttpAgentTurn(options, authToken);
6226
5524
  }
6227
5525
 
6228
5526
  // packages/cli/agentRunCommand.ts
6229
5527
  import * as nodeFs from "node:fs";
6230
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
6231
- import { join as join2 } from "node:path";
6232
5528
 
6233
5529
  // packages/cli/client/autoModelRouter.ts
6234
5530
  var CLI_AUTO_ROUTE_AGENT_KEY = BUILTIN_NOLO_AGENT_KEY;
6235
5531
 
5532
+ // packages/agent-runtime/agentsMd.ts
5533
+ import { existsSync, readFileSync } from "node:fs";
5534
+ import { join } from "node:path";
5535
+ var AGENTS_MD_MAX_BYTES = 8192;
5536
+ var AGENTS_MD_CANDIDATES = ["AGENTS.md", "CLAUDE.md"];
5537
+ function readAgentsMdLayerFromDisk(cwd) {
5538
+ for (const name of AGENTS_MD_CANDIDATES) {
5539
+ const filePath = join(cwd, name);
5540
+ if (!existsSync(filePath)) continue;
5541
+ try {
5542
+ let content = readFileSync(filePath, "utf8").trim();
5543
+ if (!content) continue;
5544
+ if (Buffer.byteLength(content, "utf8") > AGENTS_MD_MAX_BYTES) {
5545
+ content = Buffer.from(content, "utf8").subarray(0, AGENTS_MD_MAX_BYTES).toString("utf8") + "\n\n<!-- AGENTS.md truncated -->";
5546
+ }
5547
+ return buildAgentsMdLayer(content, name);
5548
+ } catch {
5549
+ }
5550
+ }
5551
+ return null;
5552
+ }
5553
+
6236
5554
  // packages/cli/agentRunPrompts.ts
6237
- import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
6238
- import { dirname, extname, isAbsolute, join, relative as relativePath, resolve, sep } from "node:path";
5555
+ import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync, statSync } from "node:fs";
5556
+ import { dirname, extname, isAbsolute, join as join2, relative as relativePath, resolve, sep } from "node:path";
6239
5557
  function workflowRefToCandidatePath(cwd, ref) {
6240
5558
  const normalized = ref.trim();
6241
5559
  if (!normalized) return "";
6242
5560
  if (normalized.endsWith(".md") || normalized.includes("/") || normalized.includes("\\")) {
6243
5561
  const directPath = resolve(cwd, normalized);
6244
- if (existsSync(directPath)) return directPath;
5562
+ if (existsSync2(directPath)) return directPath;
6245
5563
  }
6246
5564
  const fileName = normalized.replace(/[^a-zA-Z0-9一-鿿]+/g, "-").replace(/^-+|-+$/g, "");
6247
5565
  return resolve(cwd, "docs", "workflows", `${fileName}.md`);
@@ -6254,21 +5572,21 @@ function skillRefToCandidatePath(cwd, ref) {
6254
5572
  if (!normalized) return "";
6255
5573
  if (normalized.endsWith(".md") || normalized.includes("/") || normalized.includes("\\")) {
6256
5574
  const directPath = resolve(cwd, normalized);
6257
- if (existsSync(directPath)) return directPath;
5575
+ if (existsSync2(directPath)) return directPath;
6258
5576
  }
6259
5577
  const fileName = normalized.replace(/[^a-zA-Z0-9一-鿿]+/g, "-").replace(/^-+|-+$/g, "");
6260
5578
  for (const dir of SKILL_SEARCH_DIRS) {
6261
5579
  const skillMdPath = resolve(cwd, dir, fileName, "SKILL.md");
6262
- if (existsSync(skillMdPath)) return skillMdPath;
5580
+ if (existsSync2(skillMdPath)) return skillMdPath;
6263
5581
  }
6264
5582
  return resolve(cwd, ".agents", "skills", fileName, "SKILL.md");
6265
5583
  }
6266
5584
  async function resolveWorkflowReference(ref, cwd = process.cwd()) {
6267
5585
  const path = workflowRefToCandidatePath(cwd, ref);
6268
- if (!path || !existsSync(path)) {
5586
+ if (!path || !existsSync2(path)) {
6269
5587
  throw new Error(`Workflow reference not found: ${ref}`);
6270
5588
  }
6271
- const markdown = readFileSync(path, "utf8");
5589
+ const markdown = readFileSync2(path, "utf8");
6272
5590
  const parsed = parseSkillDocProtocol(markdown);
6273
5591
  return {
6274
5592
  ref,
@@ -6285,8 +5603,8 @@ function inlineRelativeRefs(body, skillDir) {
6285
5603
  const absPath = resolve(skillDir, cleaned);
6286
5604
  const relative = relativePath(normalizedSkillDir, absPath);
6287
5605
  if (relative.startsWith("..") || isAbsolute(relative)) return match;
6288
- if (!existsSync(absPath) || !absPath.endsWith(".md")) return match;
6289
- const refContent = readFileSync(absPath, "utf8");
5606
+ if (!existsSync2(absPath) || !absPath.endsWith(".md")) return match;
5607
+ const refContent = readFileSync2(absPath, "utf8");
6290
5608
  return `
6291
5609
 
6292
5610
  ### ${label}
@@ -6297,8 +5615,8 @@ ${refContent}
6297
5615
  });
6298
5616
  }
6299
5617
  function listSkillScripts(skillDir) {
6300
- const scriptsDir = join(skillDir, "scripts");
6301
- if (!existsSync(scriptsDir) || !statSync(scriptsDir).isDirectory()) return null;
5618
+ const scriptsDir = join2(skillDir, "scripts");
5619
+ if (!existsSync2(scriptsDir) || !statSync(scriptsDir).isDirectory()) return null;
6302
5620
  const entries = readdirSync(scriptsDir).filter((e) => !e.startsWith("."));
6303
5621
  if (entries.length === 0) return null;
6304
5622
  return [
@@ -6325,10 +5643,10 @@ async function resolveSkillReference(ref, options = {}) {
6325
5643
  } else {
6326
5644
  const cwd = options.cwd ?? process.cwd();
6327
5645
  const path = skillRefToCandidatePath(cwd, ref);
6328
- if (!path || !existsSync(path)) {
5646
+ if (!path || !existsSync2(path)) {
6329
5647
  throw new Error(`Skill reference not found: ${ref}`);
6330
5648
  }
6331
- markdown = readFileSync(path, "utf8");
5649
+ markdown = readFileSync2(path, "utf8");
6332
5650
  filePath = path;
6333
5651
  skillDir = dirname(path);
6334
5652
  }
@@ -6433,8 +5751,8 @@ function prependSubjectDialogMarker(message, subjectDialogKey) {
6433
5751
  function normalizeCliImageInput(input) {
6434
5752
  if (/^(https?:|data:|file:)/i.test(input)) return input;
6435
5753
  const absolutePath = resolve(input);
6436
- if (!existsSync(absolutePath)) return input;
6437
- const base64 = readFileSync(absolutePath).toString("base64");
5754
+ if (!existsSync2(absolutePath)) return input;
5755
+ const base64 = readFileSync2(absolutePath).toString("base64");
6438
5756
  return `data:${imageMimeTypeForPath(absolutePath)};base64,${base64}`;
6439
5757
  }
6440
5758
  function imageMimeTypeForPath(path) {
@@ -6627,16 +5945,16 @@ var buildCjkTokens = (text) => {
6627
5945
  }
6628
5946
  return tokens;
6629
5947
  };
6630
- var tokenize2 = (text) => {
5948
+ var tokenize = (text) => {
6631
5949
  const normalized = text.toLowerCase();
6632
5950
  const wordTokens = normalized.split(/[\s,.;:!?()[\]{}"'`,。!?:;、]+/).map((token) => token.trim()).filter((token) => token.length >= 2);
6633
5951
  return [...wordTokens, ...buildCjkTokens(normalized)];
6634
5952
  };
6635
5953
  var keywordScore = (query, item) => {
6636
- const queryTokens = new Set(tokenize2(query));
5954
+ const queryTokens = new Set(tokenize(query));
6637
5955
  if (queryTokens.size === 0) return 0;
6638
5956
  const haystack = /* @__PURE__ */ new Set([
6639
- ...tokenize2(item.content),
5957
+ ...tokenize(item.content),
6640
5958
  ...(item.tags ?? []).map((tag) => tag.toLowerCase()),
6641
5959
  item.patternKey?.toLowerCase() ?? ""
6642
5960
  ]);
@@ -6938,6 +6256,21 @@ var resolveCliMemory = async (input) => {
6938
6256
  function resolvePositiveMs(value, fallback) {
6939
6257
  return parsePositiveFiniteNumberOrFallback(value, fallback);
6940
6258
  }
6259
+ function resolveRunOutcome(input) {
6260
+ switch (input.kind) {
6261
+ case "stall":
6262
+ return { status: "failed", exitCode: 1 };
6263
+ case "timeout":
6264
+ return { status: "timeout", exitCode: 124 };
6265
+ case "result": {
6266
+ const failed = input.isStalledOrTruncated || input.exitCode !== 0;
6267
+ if (!failed) {
6268
+ return { status: "done", exitCode: 0 };
6269
+ }
6270
+ return { status: "failed", exitCode: input.exitCode !== 0 ? input.exitCode : 1 };
6271
+ }
6272
+ }
6273
+ }
6941
6274
  async function resolveAgentRunAgentKey(args) {
6942
6275
  if (!args.agentInput.trim() || args.agentInput.startsWith("agent-")) {
6943
6276
  return void 0;
@@ -6973,11 +6306,14 @@ async function runAgentRunCommand(args, deps) {
6973
6306
  deps.stallTimeoutMs ?? env.NOLO_LOCAL_RUN_STALL_TIMEOUT_MS,
6974
6307
  5 * 6e4
6975
6308
  );
6309
+ const stallEnvExplicitlySet = typeof env.NOLO_LOCAL_RUN_STALL_TIMEOUT_MS === "string" && env.NOLO_LOCAL_RUN_STALL_TIMEOUT_MS.trim().length > 0;
6310
+ const armStallWatchdog = hasRegistry || stallEnvExplicitlySet;
6311
+ const armTimeoutWatchdog = typeof parsed.timeoutMs === "number" && parsed.timeoutMs > 0;
6976
6312
  let timedOut = false;
6977
6313
  let stalled = false;
6978
6314
  let timeoutTimer;
6979
6315
  let stallTimer;
6980
- const activityTracker = hasRegistry ? createRunActivityTracker(childRunId, {
6316
+ const activityTracker = armStallWatchdog ? createRunActivityTracker(childRunId ?? "__foreground__", {
6981
6317
  env,
6982
6318
  homedir: deps.homedir,
6983
6319
  fs: deps.fs,
@@ -6990,7 +6326,7 @@ async function runAgentRunCommand(args, deps) {
6990
6326
  activityTracker?.dispose();
6991
6327
  };
6992
6328
  let rejectOnWatchdogFailure;
6993
- const watchdogFailure = hasRegistry ? new Promise((_, reject) => {
6329
+ const watchdogFailure = armStallWatchdog || armTimeoutWatchdog ? new Promise((_, reject) => {
6994
6330
  rejectOnWatchdogFailure = reject;
6995
6331
  }) : void 0;
6996
6332
  const raceWithWatchdog = (work) => watchdogFailure ? Promise.race([work, watchdogFailure]) : work;
@@ -7000,7 +6336,15 @@ async function runAgentRunCommand(args, deps) {
7000
6336
  } catch {
7001
6337
  }
7002
6338
  };
7003
- if (hasRegistry) {
6339
+ const finalizeWatchdogOutcome = (outcome, note) => {
6340
+ if (!hasRegistry) return;
6341
+ (deps.finalizeRunRecord ?? finalizeRunRecord)(
6342
+ childRunId,
6343
+ { status: outcome.status, exitCode: outcome.exitCode, note },
6344
+ { env, homedir: deps.homedir, fs: deps.fs, now: deps.now }
6345
+ );
6346
+ };
6347
+ if (armStallWatchdog) {
7004
6348
  stallTimer = setInterval(() => {
7005
6349
  if (timedOut || stalled) return;
7006
6350
  const activity = activityTracker?.getActivity();
@@ -7018,31 +6362,25 @@ async function runAgentRunCommand(args, deps) {
7018
6362
  const note = `stalled: no progress for ${stallTimeoutMs}ms`;
7019
6363
  output.write(`[nolo] local run ${note}
7020
6364
  `);
7021
- (deps.finalizeRunRecord ?? finalizeRunRecord)(
7022
- childRunId,
7023
- { status: "failed", note },
7024
- { env, homedir: deps.homedir, fs: deps.fs, now: deps.now }
7025
- );
6365
+ const outcome = resolveRunOutcome({ kind: "stall" });
6366
+ finalizeWatchdogOutcome(outcome, note);
7026
6367
  rejectOnWatchdogFailure?.(new Error(`[nolo] local run ${note}`));
7027
- exitFromWatchdog(1);
6368
+ exitFromWatchdog(outcome.exitCode);
7028
6369
  }
7029
6370
  }, Math.min(stallTimeoutMs, 1e4));
7030
- if (typeof parsed.timeoutMs === "number" && parsed.timeoutMs > 0) {
7031
- timeoutTimer = setTimeout(() => {
7032
- timedOut = true;
7033
- clearWatchdogs();
7034
- const note = `timed out after ${parsed.timeoutMs}ms`;
7035
- output.write(`[nolo] local run ${note}
6371
+ }
6372
+ if (armTimeoutWatchdog) {
6373
+ timeoutTimer = setTimeout(() => {
6374
+ timedOut = true;
6375
+ clearWatchdogs();
6376
+ const note = `timed out after ${parsed.timeoutMs}ms`;
6377
+ output.write(`[nolo] local run ${note}
7036
6378
  `);
7037
- (deps.finalizeRunRecord ?? finalizeRunRecord)(
7038
- childRunId,
7039
- { status: "timeout", note },
7040
- { env, homedir: deps.homedir, fs: deps.fs, now: deps.now }
7041
- );
7042
- rejectOnWatchdogFailure?.(new Error(`[nolo] local run ${note}`));
7043
- exitFromWatchdog(124);
7044
- }, parsed.timeoutMs);
7045
- }
6379
+ const outcome = resolveRunOutcome({ kind: "timeout" });
6380
+ finalizeWatchdogOutcome(outcome, note);
6381
+ rejectOnWatchdogFailure?.(new Error(`[nolo] local run ${note}`));
6382
+ exitFromWatchdog(outcome.exitCode);
6383
+ }, parsed.timeoutMs);
7046
6384
  }
7047
6385
  const wantsFallbackSuggestions = parsed.fallbackAgentKeys && parsed.fallbackAgentKeys.length > 0;
7048
6386
  const rawAgentInput = resolveRawAgentInput(args, deps.commandPath) ?? parsed.agentKey;
@@ -7197,22 +6535,8 @@ async function runAgentRunCommand(args, deps) {
7197
6535
  let memoryOverlayLayer = null;
7198
6536
  let memoryUseGuidanceLayer = null;
7199
6537
  if (!isSubtask) {
7200
- const AGENTS_MD_MAX = 8192;
7201
- for (const name of ["AGENTS.md", "CLAUDE.md"]) {
7202
- const agentsMdPath = join2(cliCwd, name);
7203
- if (existsSync2(agentsMdPath)) {
7204
- try {
7205
- let mdContent = readFileSync2(agentsMdPath, "utf8").trim();
7206
- if (!mdContent) continue;
7207
- if (Buffer.byteLength(mdContent, "utf8") > AGENTS_MD_MAX) {
7208
- mdContent = Buffer.from(mdContent, "utf8").subarray(0, AGENTS_MD_MAX).toString("utf8") + "\n\n<!-- AGENTS.md truncated -->";
7209
- }
7210
- scopedLayers.push(buildAgentsMdLayer(mdContent, name));
7211
- break;
7212
- } catch {
7213
- }
7214
- }
7215
- }
6538
+ const agentsMdLayer = readAgentsMdLayerFromDisk(cliCwd);
6539
+ if (agentsMdLayer) scopedLayers.push(agentsMdLayer);
7216
6540
  skillContentBlocks.push(...buildSkillContextBlocks(skillReferences));
7217
6541
  scopedLayers.push(buildSkillDiscoveryContextLayer(cliCwd));
7218
6542
  if (!deps.memoryRecallDisabled) {
@@ -7403,12 +6727,16 @@ async function runAgentRunCommand(args, deps) {
7403
6727
  if (typeof childRunId === "string" && childRunId.length > 0) {
7404
6728
  const isStalledOrTruncated = result.emptyAssistantFallbackReason === "length_truncated" || result.emptyAssistantFallbackReason === "stream_truncated" || result.emptyAssistantFallbackReason === "repetition_loop" || result.emptyAssistantFallbackReason === "stagnant_tool_calls";
7405
6729
  const truncationNote = isStalledOrTruncated ? { note: `empty assistant output: ${result.emptyAssistantFallbackReason}` } : {};
7406
- const finalStatus = isStalledOrTruncated || result.exitCode !== 0 ? "failed" : "done";
6730
+ const outcome = resolveRunOutcome({
6731
+ kind: "result",
6732
+ exitCode: result.exitCode,
6733
+ isStalledOrTruncated
6734
+ });
7407
6735
  await (deps.finalizeRunRecord ?? finalizeRunRecord)(
7408
6736
  childRunId,
7409
6737
  {
7410
- status: finalStatus,
7411
- exitCode: result.exitCode,
6738
+ status: outcome.status,
6739
+ exitCode: outcome.exitCode,
7412
6740
  dialogId: result.dialogId,
7413
6741
  ...truncationNote
7414
6742
  },
@@ -7480,8 +6808,6 @@ export {
7480
6808
  getActiveThemeMode,
7481
6809
  setActiveThemeMode,
7482
6810
  setActiveBrightness,
7483
- getActiveDensity,
7484
- setActiveDensity,
7485
6811
  detectSystemBrightnessFromEnv,
7486
6812
  resolveTuiBrightness,
7487
6813
  resolveTuiThemeMode,
@@ -7494,8 +6820,9 @@ export {
7494
6820
  themeText,
7495
6821
  tuiRenderThemeFingerprint,
7496
6822
  setMathRenderingEnabled,
6823
+ polishBreathInsertsBlankBetween,
7497
6824
  formatAssistantDisplay,
7498
- normalizeToolDisplayMode,
6825
+ TUI_TREE_MARKER,
7499
6826
  COLLAPSED_PASTE_PLACEHOLDER_RE,
7500
6827
  shouldCollapsePaste,
7501
6828
  createCollapsedPasteStore,
@@ -7507,6 +6834,7 @@ export {
7507
6834
  expandRangeToCollapsedPasteChips,
7508
6835
  findCollapsedPasteSpanAt,
7509
6836
  runAgentTurn,
6837
+ readAgentsMdLayerFromDisk,
7510
6838
  resolveWorkflowReference,
7511
6839
  resolveSkillReference,
7512
6840
  buildSkillContextBlocks,
@@ -7514,6 +6842,7 @@ export {
7514
6842
  normalizeCliImageInput,
7515
6843
  inspectLocalRunWorkspace,
7516
6844
  resolveCliMemory,
6845
+ resolveRunOutcome,
7517
6846
  runAgentRunCommand,
7518
6847
  isBalanceExhaustedError
7519
6848
  };