nolo-cli 0.19.0 → 0.24.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/{_executeModel-X5PCIZN6.js → _executeModel-ARCMGGMY.js} +46 -44
  2. package/{action-LT7BRFLK.js → action-5MNAXR5B.js} +7 -6
  3. package/{addContentAction-PL3KKBDH.js → addContentAction-UNSYTVTB.js} +5 -5
  4. package/{addDialogAgentAction-FCMSKYAF.js → addDialogAgentAction-LJGNP2AO.js} +5 -5
  5. package/{agentDeleteCommand-2BZDQV36.js → agentDeleteCommand-C5PIEBMZ.js} +27 -26
  6. package/{agentEmailCommands-2QJDGRMB.js → agentEmailCommands-QTGQ3ZAD.js} +57 -55
  7. package/{agentListCommands-6VEPTKBI.js → agentListCommands-LRHBS3A5.js} +30 -26
  8. package/{agentMachineCommands-NVVHNWYI.js → agentMachineCommands-4PXIT4BP.js} +25 -24
  9. package/{agentRecordCommands-4GGRDMD4.js → agentRecordCommands-ZZPTYTYR.js} +52 -50
  10. package/{agentRunCommand-XOLQNKBZ.js → agentRunCommand-7ZTPZNUX.js} +55 -54
  11. package/{agentRunControl-Y5AFH5PQ.js → agentRunControl-SNUKXN6J.js} +6 -2
  12. package/{agentRuntimeLocal-7WYWCGL4.js → agentRuntimeLocal-QOYY5UV2.js} +19 -18
  13. package/{agentSlice-EAXPGEYV.js → agentSlice-J3W3RX2I.js} +5 -5
  14. package/{appDeleteCommands-77KR2RJ4.js → appDeleteCommands-7NS46XDH.js} +23 -22
  15. package/{appDeployCommands-K7CAHGBI.js → appDeployCommands-RSRNQ67U.js} +23 -22
  16. package/{appDeployStatusCommands-4OEKLTBT.js → appDeployStatusCommands-EF4RSGC6.js} +23 -22
  17. package/{appGetCommands-VM2WDLAZ.js → appGetCommands-YA7JWYUX.js} +23 -22
  18. package/{appListCommands-GX6BBA6U.js → appListCommands-WM2ON6JW.js} +23 -22
  19. package/{authCommand-DY6UUL6O.js → authCommand-HJP7FURK.js} +12 -13
  20. package/{authCommands-XTBV7OFZ.js → authCommands-NYZM2B2I.js} +4 -5
  21. package/{chunk-MKA6QE5E.js → chunk-2IPEVBUO.js} +126 -68
  22. package/{chunk-OWOHNGCN.js → chunk-2MBTWINN.js} +42 -3
  23. package/{chunk-K6EUAOW3.js → chunk-35RYGII3.js} +1 -1
  24. package/{chunk-TRT4I4UD.js → chunk-4POUK2BV.js} +2 -2
  25. package/{chunk-LLWKHDG4.js → chunk-4ULSC37S.js} +1 -3
  26. package/{chunk-EDV7EBOI.js → chunk-4ZH6GUJF.js} +2151 -1500
  27. package/{chunk-MVQ4TBSD.js → chunk-54VHTARN.js} +1 -1
  28. package/{chunk-L4F3I4SR.js → chunk-5HQQ4LUU.js} +4 -6
  29. package/{chunk-Z4NR32XR.js → chunk-5RGU3J7P.js} +13 -0
  30. package/{chunk-7BUYEZ6U.js → chunk-7H3UTGPM.js} +12 -72
  31. package/{chunk-RQN4SEKL.js → chunk-7W6GFNJL.js} +1 -1
  32. package/{chunk-HEGV7BH3.js → chunk-AQZCWJOG.js} +1 -1
  33. package/{chunk-3ND52WIL.js → chunk-ATWUOTJP.js} +180 -24
  34. package/chunk-CF7S2RYZ.js +376 -0
  35. package/{chunk-I2ZJKTG5.js → chunk-CGVRC2TB.js} +7 -7
  36. package/{chunk-UAIVG4J6.js → chunk-CHSCAUZN.js} +1 -8
  37. package/{chunk-KFEVY3ST.js → chunk-D34RI6NI.js} +18 -8
  38. package/{chunk-ROWQEJRP.js → chunk-DXJS7VSG.js} +3 -2
  39. package/{chunk-MHSGJW4Z.js → chunk-EHOYZRTI.js} +44 -14
  40. package/{chunk-XRZJGPFI.js → chunk-FON47ACC.js} +4 -4
  41. package/{chunk-SCTYAHYK.js → chunk-H2NAWOLH.js} +217 -141
  42. package/{chunk-MPVYDS7I.js → chunk-H6ODMJR3.js} +3 -3
  43. package/{chunk-R35XMF6F.js → chunk-H73ZV2GL.js} +352 -30
  44. package/{chunk-4T5F7YZQ.js → chunk-I6RJGORZ.js} +1 -1
  45. package/{chunk-OK6YSWLH.js → chunk-IICW77GI.js} +1 -1
  46. package/{chunk-VDXCXCXH.js → chunk-IUDMBCXC.js} +1 -1
  47. package/{chunk-AHCY2S2I.js → chunk-JADNODCQ.js} +1 -1
  48. package/{chunk-DFCFMCY6.js → chunk-JBLY6HQP.js} +2 -2
  49. package/{chunk-UGUW3FHG.js → chunk-JMSCXQUG.js} +2 -2
  50. package/{chunk-N54HIJVJ.js → chunk-KFUCLS7Z.js} +101 -9
  51. package/{chunk-FQZZLA3C.js → chunk-KXKQO4Q6.js} +17 -0
  52. package/{chunk-3Q7WHGCB.js → chunk-L65QKSVJ.js} +1 -1
  53. package/{chunk-3ZX7PERL.js → chunk-LALVWNE4.js} +20 -7
  54. package/{chunk-PJSV3IZ5.js → chunk-M3TMVJKG.js} +1 -1
  55. package/{chunk-REA4JLBH.js → chunk-M5OZCOBV.js} +7 -6
  56. package/{chunk-JLA4FXYC.js → chunk-MALVZUYL.js} +1 -1
  57. package/{chunk-GFUIQ4RY.js → chunk-MXFQHRSS.js} +1 -1
  58. package/{chunk-LSFAWXKC.js → chunk-N7J63Q6C.js} +1 -0
  59. package/{chunk-6Y7A3OQQ.js → chunk-NRY4GCKJ.js} +2 -0
  60. package/{chunk-G5U6LDLG.js → chunk-NVHPMDSZ.js} +6 -6
  61. package/{chunk-23FZYPLC.js → chunk-OJFYT3ZQ.js} +842 -1060
  62. package/{chunk-ELT65PZW.js → chunk-OXLLFZNF.js} +1 -1
  63. package/{chunk-CZ6NYQTV.js → chunk-P4QWLZGU.js} +2 -2
  64. package/{chunk-5MIDPSSK.js → chunk-PB7G5MAM.js} +3 -3
  65. package/{chunk-HWW2M4SN.js → chunk-QLVWFXZQ.js} +5 -4
  66. package/{chunk-VYHDJEQD.js → chunk-QNLLGS37.js} +136 -78
  67. package/{chunk-XHG22OEX.js → chunk-ROJI6DRT.js} +2 -2
  68. package/{chunk-BV4VEE3W.js → chunk-ROYOKSX4.js} +243 -354
  69. package/{chunk-VNAEBGDK.js → chunk-RZNYL4LW.js} +123 -26
  70. package/{chunk-RVOUXDFU.js → chunk-S6KVFOUG.js} +6 -34
  71. package/{chunk-V3ED5AWK.js → chunk-S77SCVBU.js} +27 -16
  72. package/{chunk-UBHAWFQ6.js → chunk-S7RWIPDI.js} +42 -19
  73. package/{chunk-B5TOXZAK.js → chunk-SIZQB7BD.js} +1 -1
  74. package/{chunk-DFFIZ25G.js → chunk-SLOGKB7M.js} +4 -1
  75. package/{chunk-FXUSIQC2.js → chunk-SROR5TSM.js} +1 -1
  76. package/{chunk-PIZYJVHQ.js → chunk-TN4YHAI3.js} +4 -4
  77. package/{chunk-IYEXFJPC.js → chunk-TW35GDNW.js} +64 -57
  78. package/chunk-UZ6XXCVR.js +50 -0
  79. package/{chunk-DKZFOK24.js → chunk-UZH44DWK.js} +7 -288
  80. package/{chunk-YGW4G5W5.js → chunk-X546QUDT.js} +61 -12
  81. package/chunk-YYLHWIW6.js +48 -0
  82. package/{chunk-SWDPIPOY.js → chunk-ZGVW7MSZ.js} +1 -1
  83. package/{chunk-34WPV75U.js → chunk-ZUXIXYJI.js} +1 -1
  84. package/{chunk-VC6OZXO5.js → chunk-ZWJOGMKH.js} +2 -26
  85. package/{cliExecutor-DNE7TCC4.js → cliExecutor-K3F7DMRO.js} +2 -2
  86. package/{codingSkills-36KN5NQT.js → codingSkills-EN6Z6G6U.js} +4 -4
  87. package/{createAgentAutomationAction-GNFF524X.js → createAgentAutomationAction-MKQWN4VQ.js} +19 -18
  88. package/{createDialogAction-RB55KCLO.js → createDialogAction-YWIZPLFS.js} +22 -20
  89. package/{createPageAction-Y7343GLU.js → createPageAction-74TTEIPC.js} +20 -19
  90. package/{db-W3O47YGF.js → db-W5UHK4P3.js} +150 -0
  91. package/{dbSlice-CGSRFJN3.js → dbSlice-5BKDURDL.js} +4 -4
  92. package/{dialogCommands-IAZK6YHQ.js → dialogCommands-MJIP32FL.js} +24 -23
  93. package/{dialogSlice-UQAXF23P.js → dialogSlice-KLLVH4WI.js} +24 -18
  94. package/{docCreateCommands-I2EWZGCI.js → docCreateCommands-5DN472U6.js} +24 -27
  95. package/{docDeleteCommands-IZ45UZKG.js → docDeleteCommands-HE76LBN4.js} +25 -24
  96. package/{docReadCommands-R6Z4QJYU.js → docReadCommands-XVGZSCBS.js} +24 -23
  97. package/{docStore-5HOJ4D7D.js → docStore-SPH3D6BT.js} +20 -19
  98. package/{docUpdateCommands-2LRBKQPY.js → docUpdateCommands-P7IAWUAD.js} +24 -27
  99. package/{fetchMessages-BMGVZVSE.js → fetchMessages-W4IKHPCS.js} +2 -3
  100. package/{getPricing-G7DLAST6.js → getPricing-WENPBVWH.js} +3 -3
  101. package/{handleSendMessageAction-Q4HY35WX.js → handleSendMessageAction-ZU6WJVL7.js} +23 -20
  102. package/index.js +74 -74
  103. package/{localDialogRead-4H3QJFLW.js → localDialogRead-JXTAHW2E.js} +2 -2
  104. package/{machineCommands-PKBPQKTY.js → machineCommands-NI76PVHK.js} +59 -57
  105. package/{machineWsRunDispatch-UZAW4OXJ.js → machineWsRunDispatch-W3G6NJVQ.js} +51 -49
  106. package/{models-DJFSJ7SW.js → models-DB27UAE3.js} +2 -2
  107. package/package.json +1 -1
  108. package/{read-3FMPZPER.js → read-F3L3T2WJ.js} +2 -1
  109. package/{readDocTool-VSYHKK3V.js → readDocTool-FOHWVA4R.js} +1 -1
  110. package/{readlineWorkspace-Y2RDOFZG.js → readlineWorkspace-BDH4G477.js} +880 -425
  111. package/{removeDialogAgentAction-OAGA2G3U.js → removeDialogAgentAction-QCFGIUIH.js} +8 -7
  112. package/{runAgentClientLoop-NBPIKJ6J.js → runAgentClientLoop-ZPKMXCM5.js} +45 -38
  113. package/{setDialogExtraReferencesAction-JZEXA5SL.js → setDialogExtraReferencesAction-DK4CKERU.js} +5 -5
  114. package/{setPrimaryDialogAgentAction-4ZUQQKDG.js → setPrimaryDialogAgentAction-SJSO6N27.js} +8 -7
  115. package/{settingSlice-7MNKHZ6R.js → settingSlice-XNM5AFPU.js} +6 -5
  116. package/{spaceCommands-DHCZ7J5I.js → spaceCommands-3GGBJRQR.js} +25 -24
  117. package/{spaceSlice-ZXLLG3CR.js → spaceSlice-47Z6XLFQ.js} +21 -18
  118. package/{streamAgentChatTurn-L3YW6LSB.js → streamAgentChatTurn-VT5K5JSD.js} +140 -98
  119. package/switchDialogAgentAction-4OAC6QRN.js +61 -0
  120. package/{tableCommands-BEQAGE4I.js → tableCommands-HEQYT2KP.js} +1 -1
  121. package/{toolApiClient-QI3YBNWB.js → toolApiClient-ISM4ZQX4.js} +2 -2
  122. package/{tools-ECGXR5QF.js → tools-L7RCHAPT.js} +36 -33
  123. package/{tuiSummaryLlmCaller-OMSCNHXA.js → tuiSummaryLlmCaller-3DYOLTVN.js} +6 -6
  124. package/{updateCommands-XTW55TOT.js → updateCommands-HTCOBXCA.js} +2 -2
  125. package/{updateDialogTitleAction-HQ2EUDFT.js → updateDialogTitleAction-KMPVPQ4A.js} +28 -27
  126. package/chunk-DL6EPNIK.js +0 -50
  127. package/chunk-V5R4NZP2.js +0 -78
  128. package/chunk-X4Q4UZEY.js +0 -26
  129. package/queryRunOverlay-O4LOMMPO.js +0 -161
  130. package/runOverlayPresentation-ZO4VCWEU.js +0 -11
  131. package/types-ZSTJ7MPR.js +0 -7
  132. package/{chunk-X7W4TNB4.js → chunk-CMKUBIGW.js} +3 -3
  133. package/{runtimeDoctorCommands-E2OUORHK.js → runtimeDoctorCommands-HSU632DY.js} +3 -3
@@ -3,23 +3,9 @@ import {
3
3
  normalizeDialogRecord,
4
4
  readDialogSnapshot,
5
5
  sortDialogs
6
- } from "./chunk-V3ED5AWK.js";
7
- import {
8
- listFavoriteAgentIdsAcrossServers,
9
- listLocalCachedAgents,
10
- listRemoteAgents,
11
- listRemoteAgentsAcrossServers
12
- } from "./chunk-HWW2M4SN.js";
13
- import "./chunk-ID4G2MAR.js";
14
- import {
15
- listUserRecordsFromServers
16
- } from "./chunk-HEGV7BH3.js";
17
- import {
18
- buildOverlayPresentation
19
- } from "./chunk-V5R4NZP2.js";
6
+ } from "./chunk-S77SCVBU.js";
20
7
  import {
21
8
  ANSI_ESCAPE_REGEX,
22
- CLI_AUTO_TIER_AGENT_KEYS,
23
9
  CLI_AUTO_TIER_AGENT_KEY_TABLE,
24
10
  CLI_IMAGE_AGENT_KEY,
25
11
  COLLAPSED_PASTE_PLACEHOLDER_RE,
@@ -45,14 +31,15 @@ import {
45
31
  getActiveDensity,
46
32
  getActiveThemeName,
47
33
  isBalanceExhaustedError,
34
+ isQuotaExhaustedError,
48
35
  normalizeToolDisplayMode,
49
36
  padOrTruncateToWidth,
50
37
  releaseCollapsedPaste,
51
38
  releaseCollapsedPasteReferences,
39
+ renderSurfaceLine,
52
40
  renderTokenStatus,
53
41
  replaceCollapsedPastesWithReferences,
54
42
  resolveAgentContextWindow,
55
- resolveCliAutoFallbackTier,
56
43
  resolveCliColorEnabled,
57
44
  resolveSkillReference,
58
45
  resolveTuiBrightness,
@@ -68,141 +55,143 @@ import {
68
55
  themeColorSequence,
69
56
  themeText,
70
57
  truncateAnsi,
58
+ userSurfaceBackgroundSequence,
71
59
  visibleWidth,
72
60
  wrapTextToLines,
73
61
  wrapTranscriptLine
74
- } from "./chunk-BV4VEE3W.js";
62
+ } from "./chunk-ROYOKSX4.js";
75
63
  import "./chunk-DZ3XJVET.js";
64
+ import "./chunk-6HYVJV7B.js";
76
65
  import {
77
- getReadableCliDb
78
- } from "./chunk-WFHXMLHZ.js";
66
+ listFavoriteAgentIdsAcrossServers,
67
+ listLocalCachedAgents,
68
+ listRemoteAgents,
69
+ listRemoteAgentsAcrossServers,
70
+ normalizeListedAgent
71
+ } from "./chunk-QLVWFXZQ.js";
72
+ import "./chunk-ID4G2MAR.js";
79
73
  import {
80
- deleteDbRecord,
81
- queryUserRecords,
82
- readDbRecord
83
- } from "./chunk-DFCFMCY6.js";
74
+ listUserRecordsFromServers,
75
+ readLiveDbRecordAfterTombstoneMerge
76
+ } from "./chunk-AQZCWJOG.js";
84
77
  import {
85
78
  createCliLocalRuntimeAdapter,
86
79
  initCliLocale,
87
- isQuotaExhaustedError,
88
80
  parseCliLocale,
89
81
  readTimestamp,
90
82
  setCliLocale,
91
83
  t
92
- } from "./chunk-23FZYPLC.js";
93
- import "./chunk-OK6YSWLH.js";
94
- import "./chunk-SWDPIPOY.js";
84
+ } from "./chunk-OJFYT3ZQ.js";
85
+ import "./chunk-IICW77GI.js";
86
+ import {
87
+ getReadableCliDb
88
+ } from "./chunk-WFHXMLHZ.js";
89
+ import {
90
+ deleteDbRecord,
91
+ queryUserRecords,
92
+ readDbRecord
93
+ } from "./chunk-JBLY6HQP.js";
94
+ import "./chunk-ZGVW7MSZ.js";
95
95
  import {
96
+ NOLO_DEFAULT_AGENT_KEY,
96
97
  resolveCliAgentKeyInput
97
98
  } from "./chunk-VHBWHNVT.js";
98
99
  import "./chunk-LTRXGFMS.js";
99
- import "./chunk-MVQ4TBSD.js";
100
- import "./chunk-6HYVJV7B.js";
100
+ import "./chunk-54VHTARN.js";
101
101
  import "./chunk-JEXVIMYZ.js";
102
102
  import {
103
103
  prepareTools
104
- } from "./chunk-CZ6NYQTV.js";
105
- import "./chunk-FXUSIQC2.js";
106
- import {
107
- expandEnabledPacks
108
- } from "./chunk-EDV7EBOI.js";
104
+ } from "./chunk-P4QWLZGU.js";
105
+ import "./chunk-SROR5TSM.js";
106
+ import "./chunk-4ZH6GUJF.js";
109
107
  import "./chunk-RQSOAMPJ.js";
110
- import "./chunk-3ZX7PERL.js";
108
+ import "./chunk-I6RJGORZ.js";
109
+ import "./chunk-LALVWNE4.js";
111
110
  import "./chunk-KQHGZWSV.js";
112
- import "./chunk-4T5F7YZQ.js";
113
111
  import "./chunk-3LY4F7SV.js";
114
112
  import "./chunk-VF4K2QE6.js";
115
- import "./chunk-G5U6LDLG.js";
116
- import {
117
- initialRunOverlayState,
118
- reduceRunOverlay
119
- } from "./chunk-DL6EPNIK.js";
120
- import "./chunk-OWOHNGCN.js";
121
- import "./chunk-JLA4FXYC.js";
113
+ import "./chunk-NVHPMDSZ.js";
114
+ import "./chunk-MALVZUYL.js";
122
115
  import "./chunk-VP4WJWKW.js";
123
116
  import "./chunk-63W5N6P3.js";
124
117
  import "./chunk-WJRJDX2W.js";
125
- import "./chunk-LM6IYQ3F.js";
126
- import "./chunk-IYEXFJPC.js";
118
+ import "./chunk-TW35GDNW.js";
127
119
  import {
128
120
  extractReferenceKeysFromMessage
129
- } from "./chunk-SCTYAHYK.js";
121
+ } from "./chunk-H2NAWOLH.js";
130
122
  import {
131
123
  buildBuiltinSummaryContent
132
124
  } from "./chunk-XOIF2TNF.js";
133
- import "./chunk-B5TOXZAK.js";
134
125
  import "./chunk-MRC4Q34M.js";
135
- import "./chunk-REA4JLBH.js";
126
+ import "./chunk-SIZQB7BD.js";
127
+ import "./chunk-M5OZCOBV.js";
128
+ import "./chunk-YYLHWIW6.js";
136
129
  import "./chunk-CWMSB67P.js";
137
- import "./chunk-XHG22OEX.js";
138
- import "./chunk-Z4NR32XR.js";
130
+ import "./chunk-ROJI6DRT.js";
131
+ import "./chunk-5RGU3J7P.js";
139
132
  import "./chunk-M76ECQRD.js";
140
- import "./chunk-3Q7WHGCB.js";
133
+ import "./chunk-L65QKSVJ.js";
141
134
  import {
142
135
  buildSkillDiscoveryContextBlock
143
136
  } from "./chunk-7OBMZCRD.js";
144
- import "./chunk-7BUYEZ6U.js";
145
- import "./chunk-VC6OZXO5.js";
137
+ import "./chunk-7H3UTGPM.js";
138
+ import {
139
+ expandEnabledPacks
140
+ } from "./chunk-CF7S2RYZ.js";
141
+ import "./chunk-ZWJOGMKH.js";
146
142
  import "./chunk-WZSRQNQG.js";
147
143
  import {
148
144
  buildLocalWorkspaceOpenAiTools,
149
145
  buildLocalWorkspaceToolset,
150
146
  getProcessRegistry
151
- } from "./chunk-R35XMF6F.js";
147
+ } from "./chunk-H73ZV2GL.js";
152
148
  import "./chunk-ZNFJWEN4.js";
153
- import "./chunk-N54HIJVJ.js";
149
+ import "./chunk-KFUCLS7Z.js";
154
150
  import "./chunk-OIQPORYI.js";
155
151
  import {
156
152
  readCommandActionGatePayload,
157
153
  resolveAgentImageInputSupport
158
- } from "./chunk-YGW4G5W5.js";
159
- import "./chunk-LSFAWXKC.js";
154
+ } from "./chunk-X546QUDT.js";
155
+ import "./chunk-N7J63Q6C.js";
160
156
  import {
161
157
  buildCurrentTimeBlock,
162
158
  buildIdentityBlock,
163
159
  buildRuntimeGuidanceBlocks
164
- } from "./chunk-34WPV75U.js";
165
- import "./chunk-KFEVY3ST.js";
160
+ } from "./chunk-ZUXIXYJI.js";
161
+ import "./chunk-D34RI6NI.js";
166
162
  import {
167
163
  resolvePlatformAuthToken
168
- } from "./chunk-MHSGJW4Z.js";
169
- import "./chunk-DKZFOK24.js";
164
+ } from "./chunk-EHOYZRTI.js";
165
+ import "./chunk-UZH44DWK.js";
166
+ import "./chunk-2MBTWINN.js";
170
167
  import {
171
168
  DEFAULT_CONTEXT_WINDOW,
172
169
  estimateTokenCount,
173
170
  getModelContextWindow,
174
171
  planCompression,
175
172
  serializeMessageContent
176
- } from "./chunk-I2ZJKTG5.js";
173
+ } from "./chunk-CGVRC2TB.js";
177
174
  import {
178
175
  clipCompactText
179
176
  } from "./chunk-5MMAK75Q.js";
180
177
  import "./chunk-5CS33IBL.js";
181
178
  import "./chunk-JZPBVBIY.js";
182
- import "./chunk-UAIVG4J6.js";
179
+ import "./chunk-CHSCAUZN.js";
183
180
  import "./chunk-ZHXJ6M7T.js";
184
- import {
185
- toErrorMessage
186
- } from "./chunk-HNMXYYJR.js";
187
- import "./chunk-ELT65PZW.js";
188
181
  import "./chunk-AL2V7U3E.js";
189
182
  import "./chunk-4PWB7JRR.js";
190
183
  import {
191
184
  canonicalizeToolNames
192
185
  } from "./chunk-ZZ2MH7LE.js";
193
- import "./chunk-5MIDPSSK.js";
194
- import {
195
- extractCustomId
196
- } from "./chunk-DFFIZ25G.js";
186
+ import "./chunk-PB7G5MAM.js";
197
187
  import "./chunk-3ASDTTEI.js";
198
188
  import {
199
189
  compactWhitespace
200
190
  } from "./chunk-DWLEOOGR.js";
201
191
  import {
202
192
  checkStaleRun,
203
- queryRunRecords,
204
193
  readRunRecord
205
- } from "./chunk-VNAEBGDK.js";
194
+ } from "./chunk-RZNYL4LW.js";
206
195
  import {
207
196
  clipText,
208
197
  formatDuration,
@@ -213,17 +202,21 @@ import {
213
202
  resolveRunLabel,
214
203
  runShowsLogTail,
215
204
  shortRunId
216
- } from "./chunk-FQZZLA3C.js";
217
- import "./chunk-X7W4TNB4.js";
218
- import "./chunk-ATNTHIZI.js";
205
+ } from "./chunk-KXKQO4Q6.js";
206
+ import "./chunk-CMKUBIGW.js";
219
207
  import "./chunk-JBTJAPUF.js";
208
+ import "./chunk-ATNTHIZI.js";
209
+ import "./chunk-LM6IYQ3F.js";
210
+ import {
211
+ toErrorMessage
212
+ } from "./chunk-HNMXYYJR.js";
220
213
  import {
221
214
  runSelfUpdate
222
- } from "./chunk-K6EUAOW3.js";
215
+ } from "./chunk-35RYGII3.js";
223
216
  import {
224
217
  saveProfileAgentSelection,
225
218
  saveProfileLocale
226
- } from "./chunk-ROWQEJRP.js";
219
+ } from "./chunk-DXJS7VSG.js";
227
220
  import {
228
221
  readPipeText,
229
222
  spawnProcess
@@ -237,27 +230,31 @@ import {
237
230
  import {
238
231
  DEFAULT_NOLO_SERVER_URL
239
232
  } from "./chunk-OLZBQWZU.js";
240
- import "./chunk-LLWKHDG4.js";
241
- import "./chunk-MKA6QE5E.js";
242
- import "./chunk-UGUW3FHG.js";
243
- import "./chunk-RVOUXDFU.js";
233
+ import "./chunk-4ULSC37S.js";
234
+ import "./chunk-2IPEVBUO.js";
235
+ import "./chunk-JMSCXQUG.js";
236
+ import "./chunk-S6KVFOUG.js";
244
237
  import "./chunk-Y5GCAMGP.js";
238
+ import "./chunk-UZ6XXCVR.js";
245
239
  import "./chunk-KX6YBIHG.js";
246
- import "./chunk-XRZJGPFI.js";
247
- import "./chunk-6Y7A3OQQ.js";
240
+ import "./chunk-OXLLFZNF.js";
241
+ import "./chunk-FON47ACC.js";
242
+ import "./chunk-NRY4GCKJ.js";
248
243
  import "./chunk-WWC7I6TA.js";
249
244
  import "./chunk-SKDNBYZK.js";
250
245
  import "./chunk-I42VC5KR.js";
251
246
  import {
252
247
  asTrimmedLowercaseString
253
248
  } from "./chunk-QSJ3HFEF.js";
254
- import "./chunk-X4Q4UZEY.js";
255
- import "./chunk-3ND52WIL.js";
249
+ import "./chunk-ATWUOTJP.js";
256
250
  import "./chunk-XMLRJUU5.js";
257
251
  import "./chunk-R5V5G73M.js";
258
252
  import "./chunk-GBRG75BQ.js";
259
253
  import "./chunk-3EUW3WEO.js";
260
254
  import "./chunk-U6VC4MU4.js";
255
+ import {
256
+ extractCustomId
257
+ } from "./chunk-SLOGKB7M.js";
261
258
  import "./chunk-KUG52IAP.js";
262
259
  import "./chunk-LCBAMY2M.js";
263
260
  import "./chunk-4SN6J65J.js";
@@ -526,6 +523,7 @@ async function compactDialog(options) {
526
523
  dialogKey
527
524
  );
528
525
  let summaryGenerated = false;
526
+ let compactedMessageCount = 0;
529
527
  if (options.summaryLlmCaller) {
530
528
  const allMsgs = await readDialogMessages(
531
529
  fetchImpl,
@@ -580,6 +578,7 @@ async function compactDialog(options) {
580
578
  current.compressionCount = compressionCount + 1;
581
579
  current.referenceKeys = Array.from(extractedKeys);
582
580
  summaryGenerated = true;
581
+ compactedMessageCount = plan.compressCount;
583
582
  console.log(
584
583
  `[nolo] compact: compressed ${plan.compressCount} messages into summary (len: ${newSummary.trim().length})`
585
584
  );
@@ -602,7 +601,8 @@ async function compactDialog(options) {
602
601
  dialogId: extractCustomId(next.dbKey),
603
602
  dialogKey: next.dbKey,
604
603
  spaceId: typeof next.spaceId === "string" ? next.spaceId : void 0,
605
- summaryGenerated
604
+ summaryGenerated,
605
+ compactedMessageCount
606
606
  };
607
607
  }
608
608
 
@@ -612,7 +612,7 @@ var DIALOG_CHECKED = "\u25C9";
612
612
  var DIALOG_UNCHECKED = "\u25CB";
613
613
  function renderDialogTitle(title, colorEnabled = resolveCliColorEnabled()) {
614
614
  if (!colorEnabled) return title;
615
- return `\x1B[1m${themeColorSequence("accent")}${title}\x1B[0m`;
615
+ return `${themeColorSequence("accent")}${title}\x1B[0m`;
616
616
  }
617
617
  function renderDialogRow(args, colorEnabled = resolveCliColorEnabled()) {
618
618
  const marker = args.focused ? DIALOG_CURSOR : " ";
@@ -620,7 +620,7 @@ function renderDialogRow(args, colorEnabled = resolveCliColorEnabled()) {
620
620
  const detail = args.detail ? ` ${themeText(args.detail, "muted", colorEnabled)}` : "";
621
621
  const row = `${marker} ${checkbox}${args.label}${detail}`;
622
622
  if (!args.focused || !colorEnabled) return row;
623
- return `${surfaceBackgroundSequence()}${themeColorSequence("accent")}\x1B[1m${row}\x1B[0m`;
623
+ return `${surfaceBackgroundSequence()}${themeColorSequence("accent")}${row}\x1B[0m`;
624
624
  }
625
625
  function renderDialogOverflow(text, colorEnabled = resolveCliColorEnabled()) {
626
626
  return themeText(` ${text}`, "chrome", colorEnabled);
@@ -1328,7 +1328,7 @@ function renderTabBar(questions, activeIndex, colorEnabled) {
1328
1328
  const tabs = questions.map((q, i) => {
1329
1329
  const label = `Q${i + 1}`;
1330
1330
  if (i === activeIndex) {
1331
- return colorEnabled ? `${themeColorSequence("accent")}\x1B[1m ${label} \x1B[0m` : `[${label}]`;
1331
+ return colorEnabled ? `${themeColorSequence("accent")} ${label} \x1B[0m` : `[${label}]`;
1332
1332
  }
1333
1333
  return colorEnabled ? themeText(` ${label} `, "muted", colorEnabled) : ` ${label} `;
1334
1334
  });
@@ -1395,7 +1395,7 @@ function renderAskChoiceFrame(state) {
1395
1395
  const plainRow = `${plainPrefix}${qs.otherText}`;
1396
1396
  if (focused && colorEnabled) {
1397
1397
  lines.push(
1398
- `\x1B[1m${themeColorSequence("accent")}${plainRow}\x1B[0m`
1398
+ `${themeColorSequence("accent")}${plainRow}\x1B[0m`
1399
1399
  );
1400
1400
  } else {
1401
1401
  lines.push(plainRow);
@@ -2159,6 +2159,7 @@ function createRunRegistryPoller(deps) {
2159
2159
  return;
2160
2160
  }
2161
2161
  const alive = /* @__PURE__ */ new Set();
2162
+ const polled = [];
2162
2163
  for (const run of active) {
2163
2164
  alive.add(run.runId);
2164
2165
  let record;
@@ -2172,6 +2173,7 @@ function createRunRegistryPoller(deps) {
2172
2173
  continue;
2173
2174
  }
2174
2175
  if (!record) continue;
2176
+ polled.push(record);
2175
2177
  const snapshot = snapshotFromRunRecord(record, at);
2176
2178
  const mark = fingerprint(snapshot);
2177
2179
  if (lastEmitted.get(run.runId) === mark) continue;
@@ -2184,6 +2186,12 @@ function createRunRegistryPoller(deps) {
2184
2186
  for (const runId of [...lastReconciledAt.keys()]) {
2185
2187
  if (!alive.has(runId)) lastReconciledAt.delete(runId);
2186
2188
  }
2189
+ if (polled.length > 0 && deps.onRecordsPolled) {
2190
+ try {
2191
+ deps.onRecordsPolled(polled);
2192
+ } catch {
2193
+ }
2194
+ }
2187
2195
  };
2188
2196
  return {
2189
2197
  ensureRunning() {
@@ -2199,6 +2207,163 @@ function createRunRegistryPoller(deps) {
2199
2207
  };
2200
2208
  }
2201
2209
 
2210
+ // packages/core/chat/internalTurnEvent.ts
2211
+ function normalizeRunCompletionShape(record) {
2212
+ const runId = String(record.runId ?? record.id ?? "");
2213
+ const agentKey = String(record.agentKey ?? record.agent ?? "");
2214
+ const status = String(record.status ?? "done");
2215
+ const counters = record.activity?.counters;
2216
+ return {
2217
+ runId,
2218
+ agentKey,
2219
+ ...typeof record.agentName === "string" ? { agentName: record.agentName } : {},
2220
+ status,
2221
+ ...typeof record.exitCode === "number" ? { exitCode: record.exitCode } : {},
2222
+ ...typeof record.parentDialogId === "string" ? { parentDialogId: record.parentDialogId } : {},
2223
+ ...typeof record.dialogId === "string" ? { dialogId: record.dialogId } : {},
2224
+ ...typeof record.ephemeral === "boolean" ? { ephemeral: record.ephemeral } : {},
2225
+ ...record.startedAt !== void 0 ? { startedAt: record.startedAt } : {},
2226
+ ...record.endedAt !== void 0 ? { endedAt: record.endedAt } : {},
2227
+ ...typeof record.note === "string" ? { note: record.note } : {},
2228
+ ...typeof record.error === "string" ? { error: record.error } : {},
2229
+ ...typeof record.ack === "boolean" ? { ack: record.ack } : {},
2230
+ ...counters ? {
2231
+ activity: {
2232
+ counters: {
2233
+ toolCalls: typeof counters.toolCalls === "number" ? counters.toolCalls : 0,
2234
+ llmCalls: typeof counters.llmCalls === "number" ? counters.llmCalls : 0,
2235
+ fileEdits: typeof counters.fileEdits === "number" ? counters.fileEdits : 0
2236
+ }
2237
+ }
2238
+ } : {}
2239
+ };
2240
+ }
2241
+ function createTurnRequest(input) {
2242
+ if (typeof input === "string") {
2243
+ return {
2244
+ event: { kind: "user", text: input },
2245
+ text: input
2246
+ };
2247
+ }
2248
+ if ("event" in input && typeof input.event === "object" && typeof input.text === "string") {
2249
+ return input;
2250
+ }
2251
+ const event = input;
2252
+ return {
2253
+ event,
2254
+ text: event.text
2255
+ };
2256
+ }
2257
+
2258
+ // packages/cli/tui/runCompletionWatcher.ts
2259
+ var WAKE_NOTE_MAX_CHARS = 300;
2260
+ function createRunCompletionWatcher(deps) {
2261
+ const now = deps.now ?? (() => Date.now());
2262
+ const createdAt = now();
2263
+ const lastStatusByRunId = /* @__PURE__ */ new Map();
2264
+ const notifiedRunIds = /* @__PURE__ */ new Set();
2265
+ const describeRun = (record) => {
2266
+ const lines = [
2267
+ `runId: ${record.runId}`,
2268
+ `agent: ${resolveRunLabel(record)}`,
2269
+ `status: ${record.status}`
2270
+ ];
2271
+ if (typeof record.exitCode === "number") {
2272
+ lines.push(`exitCode: ${record.exitCode}`);
2273
+ }
2274
+ if (record.dialogId) {
2275
+ lines.push(`childDialogId: ${record.dialogId}`);
2276
+ } else if (record.ephemeral) {
2277
+ lines.push(`ephemeral: true (no persisted child dialog)`);
2278
+ } else {
2279
+ lines.push(`childDialogId: missing (result unpersisted or ephemeral)`);
2280
+ }
2281
+ const duration = formatRunAge(
2282
+ {
2283
+ startedAt: readTimestamp(record.startedAt),
2284
+ finishedAt: readTimestamp(record.endedAt ?? record.finishedAt)
2285
+ },
2286
+ now()
2287
+ );
2288
+ if (duration) lines.push(`duration: ${duration}`);
2289
+ const recordError = "error" in record && typeof record.error === "string" ? record.error : void 0;
2290
+ const note = typeof record.note === "string" ? clipText(record.note, WAKE_NOTE_MAX_CHARS) : typeof recordError === "string" ? clipText(recordError, WAKE_NOTE_MAX_CHARS) : "";
2291
+ if (note) lines.push(`note: ${note}`);
2292
+ const counters = record.activity?.counters;
2293
+ if (counters && typeof counters.toolCalls === "number" && typeof counters.llmCalls === "number" && typeof counters.fileEdits === "number") {
2294
+ lines.push(
2295
+ `activity: ${counters.toolCalls} tool calls \xB7 ${counters.llmCalls} llm calls \xB7 ${counters.fileEdits} edits`
2296
+ );
2297
+ }
2298
+ return lines;
2299
+ };
2300
+ const buildWakeMessage = (finished) => {
2301
+ const lines = [
2302
+ `\u3010\u540E\u53F0 run \u7EC8\u6001\u901A\u77E5\u3011\u4F60\u6D3E\u51FA\u7684 ${finished.length} \u6761\u540E\u53F0 run \u5DF2\u5230\u8FBE\u7EC8\u6001\uFF1A`
2303
+ ];
2304
+ for (const record of finished) {
2305
+ lines.push("", ...describeRun(record));
2306
+ }
2307
+ lines.push(
2308
+ "",
2309
+ '\u4EE5\u4E0A\u662F\u4F60\u901A\u8FC7 startAgentRun \u6D3E\u51FA\u7684\u540E\u53F0 run \u7684\u7EC8\u6001\u901A\u77E5\uFF08\u7CFB\u7EDF\u5185\u90E8\u4E8B\u4EF6\uFF0C\u4E0D\u662F\u7528\u6237\u6D88\u606F\uFF09\u3002\u8BF7\u9605\u8BFB\u4E0A\u9762\u7684\u6458\u8981\u5E76\u81EA\u5DF1\u51B3\u5B9A\u4E0B\u4E00\u6B65\uFF1A\u6C47\u603B\u7ED3\u679C\u3001\u7EE7\u7EED\u540E\u7EED\u5DE5\u4F5C\u3001\u6216\u5411\u7528\u6237\u6C47\u62A5\u7ED3\u8BBA\u3002\u9700\u8981\u5B8C\u6574\u8F93\u51FA\u65F6\u7528 controlAgentRun(action:"status", runId, tailLines:30) \u62C9\u53D6\u5BF9\u5E94 run \u7684\u65E5\u5FD7\u3002'
2310
+ );
2311
+ return lines.join("\n");
2312
+ };
2313
+ return {
2314
+ observe(records) {
2315
+ const finished = [];
2316
+ const currentDialogId = deps.getCurrentDialogId();
2317
+ for (const rawRecord of records) {
2318
+ try {
2319
+ if (!rawRecord || typeof rawRecord.runId !== "string" || !rawRecord.runId) continue;
2320
+ const record = rawRecord;
2321
+ if (notifiedRunIds.has(record.runId)) continue;
2322
+ if (record.ack === true) {
2323
+ notifiedRunIds.add(record.runId);
2324
+ continue;
2325
+ }
2326
+ const status = record.status;
2327
+ if (typeof status !== "string") continue;
2328
+ if (record.parentDialogId !== currentDialogId) continue;
2329
+ const previous = lastStatusByRunId.get(record.runId);
2330
+ lastStatusByRunId.set(record.runId, status);
2331
+ if (!isAgentRunTerminalStatus(status)) continue;
2332
+ if (previous === void 0) {
2333
+ const startedMs = readTimestamp(record.startedAt);
2334
+ if (startedMs === void 0 || startedMs < createdAt) continue;
2335
+ } else if (isAgentRunTerminalStatus(previous)) {
2336
+ continue;
2337
+ }
2338
+ notifiedRunIds.add(record.runId);
2339
+ finished.push(record);
2340
+ } catch {
2341
+ continue;
2342
+ }
2343
+ }
2344
+ if (finished.length === 0) return;
2345
+ const shapes = finished.map((r) => normalizeRunCompletionShape(r));
2346
+ const summaryText = buildWakeMessage(finished);
2347
+ const event = {
2348
+ kind: "child-run-completed",
2349
+ runs: shapes,
2350
+ text: summaryText
2351
+ };
2352
+ deps.onWake(event);
2353
+ },
2354
+ markAcknowledged(runId) {
2355
+ if (runId) notifiedRunIds.add(runId);
2356
+ },
2357
+ isAcknowledged(runId) {
2358
+ return Boolean(runId && notifiedRunIds.has(runId));
2359
+ },
2360
+ dispose() {
2361
+ lastStatusByRunId.clear();
2362
+ notifiedRunIds.clear();
2363
+ }
2364
+ };
2365
+ }
2366
+
2202
2367
  // packages/ai/agent/utils/sortUtils.ts
2203
2368
  function sortAgentsFavoriteOwnedPublic(items) {
2204
2369
  const map = /* @__PURE__ */ new Map();
@@ -2245,7 +2410,7 @@ function sortAgentsFavoriteOwnedPublic(items) {
2245
2410
  }
2246
2411
 
2247
2412
  // packages/cli/tui/agentCatalog.ts
2248
- var DEFAULT_TUI_AGENT_KEY = "agent-pub-01NOLOAPPBLD000000019KCKT0";
2413
+ var DEFAULT_TUI_AGENT_KEY = NOLO_DEFAULT_AGENT_KEY;
2249
2414
  function formatAgentSourceLabel(entry) {
2250
2415
  if (entry.kind === "platform" || entry.apiSource === "platform") return t("agentSourcePlatform");
2251
2416
  if (entry.apiSource === "cli") {
@@ -2300,7 +2465,7 @@ function listedAgentToCatalogEntry(agent) {
2300
2465
  ...agent.cliProvider ? { cliProvider: agent.cliProvider } : {}
2301
2466
  };
2302
2467
  }
2303
- function mergeCatalogEntries(currentKey, platformAgents, privateAgents, favoritedAtByKey = {}) {
2468
+ function mergeCatalogEntries(currentKey, privateAgents, favoritedAtByKey = {}) {
2304
2469
  const seen = /* @__PURE__ */ new Set();
2305
2470
  const merged = [];
2306
2471
  const push = (entry) => {
@@ -2309,12 +2474,9 @@ function mergeCatalogEntries(currentKey, platformAgents, privateAgents, favorite
2309
2474
  const favoritedAt = favoritedAtByKey[entry.key];
2310
2475
  merged.push(favoritedAt ? { ...entry, favoritedAt } : entry);
2311
2476
  };
2312
- const current = [...platformAgents, ...privateAgents].find((entry) => entry.key === currentKey) ?? null;
2477
+ const current = privateAgents.find((entry) => entry.key === currentKey) ?? null;
2313
2478
  if (current) push(current);
2314
- for (const entry of platformAgents) {
2315
- if (entry.key !== currentKey) push(entry);
2316
- }
2317
- const sortablePrivate = privateAgents.map((entry) => ({
2479
+ const sortablePrivate = privateAgents.filter((entry) => favoritedAtByKey[entry.key] !== void 0).map((entry) => ({
2318
2480
  key: entry.key,
2319
2481
  favoritedAt: favoritedAtByKey[entry.key],
2320
2482
  isOwned: true,
@@ -2322,7 +2484,7 @@ function mergeCatalogEntries(currentKey, platformAgents, privateAgents, favorite
2322
2484
  }));
2323
2485
  const sortedKeys = sortAgentsFavoriteOwnedPublic(sortablePrivate);
2324
2486
  const sortedKeyOrder = new Map(sortedKeys.map((item, i) => [item.key, i]));
2325
- const sortedPrivate = [...privateAgents].sort(
2487
+ const sortedPrivate = privateAgents.filter((entry) => favoritedAtByKey[entry.key] !== void 0).sort(
2326
2488
  (a, b) => (sortedKeyOrder.get(a.key) ?? 0) - (sortedKeyOrder.get(b.key) ?? 0)
2327
2489
  );
2328
2490
  for (const entry of sortedPrivate) {
@@ -2362,7 +2524,6 @@ async function loadAgentCatalog(args) {
2362
2524
  }
2363
2525
  const entries = mergeCatalogEntries(
2364
2526
  args.currentKey,
2365
- resolveCatalogPlatformAgents(env),
2366
2527
  rawData.privateAgents,
2367
2528
  rawData.favoritedAtByKey
2368
2529
  );
@@ -2374,7 +2535,6 @@ function refreshAgentCatalogInBackground(args, env, cacheKey) {
2374
2535
  agentCatalogRefreshInFlight = fetchRawCatalogData(args, env).then((rawData) => {
2375
2536
  const entries = mergeCatalogEntries(
2376
2537
  args.currentKey,
2377
- resolveCatalogPlatformAgents(env),
2378
2538
  rawData.privateAgents,
2379
2539
  rawData.favoritedAtByKey
2380
2540
  );
@@ -2384,9 +2544,15 @@ function refreshAgentCatalogInBackground(args, env, cacheKey) {
2384
2544
  agentCatalogRefreshInFlight = null;
2385
2545
  });
2386
2546
  }
2547
+ async function prefillCatalogFromLocalDb(_args) {
2548
+ }
2387
2549
  function prefetchAgentCatalog(args) {
2388
- void loadAgentCatalog({ ...args, currentKey: "" }).catch(() => {
2389
- });
2550
+ void (async () => {
2551
+ await prefillCatalogFromLocalDb({ env: args.env, getDb: args.getDb }).catch(() => {
2552
+ });
2553
+ void loadAgentCatalog({ ...args, currentKey: "" }).catch(() => {
2554
+ });
2555
+ })();
2390
2556
  }
2391
2557
  async function fetchRawCatalogData(args, env) {
2392
2558
  const fetchImpl = args.fetchImpl ?? fetch;
@@ -2398,7 +2564,7 @@ async function fetchRawCatalogData(args, env) {
2398
2564
  }
2399
2565
  const serverUrl = resolveServerUrl(env);
2400
2566
  const serverUrls = resolveServerCandidates([], env, serverUrl);
2401
- let privateAgents = [];
2567
+ let listedAgents = [];
2402
2568
  const favoritesPromise = listFavoriteAgentIdsAcrossServers({
2403
2569
  authToken,
2404
2570
  fetchImpl,
@@ -2412,15 +2578,14 @@ async function fetchRawCatalogData(args, env) {
2412
2578
  serverUrls,
2413
2579
  userId
2414
2580
  });
2415
- privateAgents = remoteResult.agents.map(listedAgentToCatalogEntry);
2581
+ listedAgents = remoteResult.agents;
2416
2582
  } catch {
2417
2583
  try {
2418
2584
  const db = await getReadableCliDb({ write: () => {
2419
2585
  } });
2420
- const cached = await listLocalCachedAgents({ db, userId });
2421
- privateAgents = cached.map(listedAgentToCatalogEntry);
2586
+ listedAgents = await listLocalCachedAgents({ db, userId });
2422
2587
  } catch {
2423
- privateAgents = (await listRemoteAgents({
2588
+ listedAgents = await listRemoteAgents({
2424
2589
  authToken,
2425
2590
  fallbackFetchImpl,
2426
2591
  fetchImpl,
@@ -2428,10 +2593,47 @@ async function fetchRawCatalogData(args, env) {
2428
2593
  userId,
2429
2594
  queryUserRecords,
2430
2595
  readDbRecord
2431
- })).map(listedAgentToCatalogEntry);
2596
+ });
2432
2597
  }
2433
2598
  }
2599
+ const privateAgents = listedAgents.map(listedAgentToCatalogEntry);
2434
2600
  const favoritedAtByKey = await favoritesPromise;
2601
+ for (const agent of listedAgents) {
2602
+ const favoritedAt = [agent.privateKey, agent.publicKey, agent.id].map((key) => favoritedAtByKey[key]).find((value) => value !== void 0);
2603
+ if (favoritedAt !== void 0) favoritedAtByKey[agent.privateKey] = favoritedAt;
2604
+ }
2605
+ const existingKeys = /* @__PURE__ */ new Set();
2606
+ for (const agent of listedAgents) {
2607
+ existingKeys.add(agent.privateKey);
2608
+ existingKeys.add(agent.publicKey);
2609
+ existingKeys.add(agent.id);
2610
+ }
2611
+ await Promise.all(
2612
+ Object.keys(favoritedAtByKey).map(async (favKey) => {
2613
+ if (existingKeys.has(favKey)) return;
2614
+ try {
2615
+ const favRead = await readLiveDbRecordAfterTombstoneMerge({
2616
+ authToken,
2617
+ dbKey: favKey,
2618
+ fallbackFetchImpl,
2619
+ fetchImpl,
2620
+ serverUrls
2621
+ });
2622
+ const record = favRead.record;
2623
+ if (!record || record.type && record.type !== "agent") return;
2624
+ const norm = normalizeListedAgent(record);
2625
+ if (!norm) return;
2626
+ if (existingKeys.has(norm.privateKey) || existingKeys.has(norm.publicKey) || existingKeys.has(norm.id)) {
2627
+ return;
2628
+ }
2629
+ existingKeys.add(norm.privateKey);
2630
+ existingKeys.add(norm.publicKey);
2631
+ existingKeys.add(norm.id);
2632
+ privateAgents.push(listedAgentToCatalogEntry(norm));
2633
+ } catch {
2634
+ }
2635
+ })
2636
+ );
2435
2637
  return { privateAgents, favoritedAtByKey };
2436
2638
  }
2437
2639
  function renderAgentCatalogList(entries, currentKey) {
@@ -3096,7 +3298,7 @@ function renderWelcome(state, frame = 0, maxFrames = 0, columns) {
3096
3298
  const widestSceneCol = sceneArt.split("\n").reduce((max, line) => Math.max(max, displayWidth(stripAnsi(line))), 0);
3097
3299
  if (columns < widestSceneCol) sceneArt = "";
3098
3300
  }
3099
- const versionLine = colorEnabled ? `\x1B[1m${themeColorSequence("accent")}nolo\x1B[0m ${state.cliVersion ?? ""} | server ${state.serverUrl}`.replace(" |", " |") : `nolo ${state.cliVersion ?? ""} | server ${state.serverUrl}`.replace(" |", " |");
3301
+ const versionLine = colorEnabled ? `${themeColorSequence("accent")}nolo\x1B[0m ${state.cliVersion ?? ""} | server ${state.serverUrl}`.replace(" |", " |") : `nolo ${state.cliVersion ?? ""} | server ${state.serverUrl}`.replace(" |", " |");
3100
3302
  const body = sceneArt ? [sceneArt, versionLine, t("welcomeHint"), ""] : [versionLine, t("welcomeHint"), ""];
3101
3303
  return body.join("\n");
3102
3304
  }
@@ -3760,7 +3962,16 @@ function handleTuiInput(input, state) {
3760
3962
  };
3761
3963
  }
3762
3964
  return {
3763
- nextState: state,
3965
+ nextState: {
3966
+ ...state,
3967
+ dialogId: void 0,
3968
+ dialogKey: void 0,
3969
+ dialogLabel: t("newDialog"),
3970
+ attachedDocs: [],
3971
+ attachedSkills: [],
3972
+ attachedImages: [],
3973
+ turnTokens: void 0
3974
+ },
3764
3975
  output: t("clearingDialog"),
3765
3976
  action: { type: "clear", dialogId: state.dialogId }
3766
3977
  };
@@ -4127,52 +4338,65 @@ var initialChatQueueState = {
4127
4338
  function reduceChatQueue(state, event) {
4128
4339
  switch (event.type) {
4129
4340
  case "turn-start":
4130
- if (state.running) return state;
4131
- return { ...state, running: true, lastDrainError: null };
4132
- case "turn-end": {
4133
- if (!state.running) return state;
4134
- if (event.aborted) {
4135
- return {
4136
- ...state,
4137
- running: false,
4138
- queue: [],
4139
- lastDrainError: null
4140
- };
4141
- }
4341
+ if (state.running && state.lastDrainError === null) return state;
4342
+ return {
4343
+ ...state,
4344
+ running: true,
4345
+ lastDrainError: null
4346
+ };
4347
+ case "turn-end":
4142
4348
  return {
4143
4349
  ...state,
4144
4350
  running: false,
4145
- ...event.ok ? {} : { lastDrainError: "previous turn failed" }
4351
+ queue: event.aborted ? [] : state.queue,
4352
+ lastDrainError: !event.ok && !event.aborted ? "previous turn failed" : state.lastDrainError
4146
4353
  };
4147
- }
4148
4354
  case "enqueue": {
4149
- const text = event.text;
4150
- if (!text) return state;
4151
- return { ...state, queue: [...state.queue, text], lastDrainError: null };
4355
+ const req = createTurnRequest(event.text);
4356
+ if (!req.text.trim() && req.event.kind === "user") {
4357
+ return state;
4358
+ }
4359
+ return {
4360
+ ...state,
4361
+ queue: [...state.queue, req]
4362
+ };
4152
4363
  }
4153
- case "dequeue": {
4364
+ case "dequeue":
4154
4365
  if (state.queue.length === 0) return state;
4155
- return { ...state, queue: state.queue.slice(1) };
4156
- }
4366
+ return {
4367
+ ...state,
4368
+ queue: state.queue.slice(1)
4369
+ };
4157
4370
  case "clear":
4158
- if (state.queue.length === 0 && !state.lastDrainError) return state;
4159
- return { ...state, queue: [], lastDrainError: null };
4371
+ if (state.queue.length === 0 && state.lastDrainError === null) return state;
4372
+ return {
4373
+ ...state,
4374
+ queue: [],
4375
+ lastDrainError: null
4376
+ };
4160
4377
  case "pause-drain":
4161
4378
  if (state.drainPaused) return state;
4162
- return { ...state, drainPaused: true };
4379
+ return {
4380
+ ...state,
4381
+ drainPaused: true
4382
+ };
4163
4383
  case "resume-drain":
4164
4384
  if (!state.drainPaused) return state;
4165
- return { ...state, drainPaused: false };
4385
+ return {
4386
+ ...state,
4387
+ drainPaused: false
4388
+ };
4166
4389
  case "drain-error":
4167
- return { ...state, lastDrainError: event.message };
4168
- default: {
4169
- const _exhaustive = event;
4390
+ return {
4391
+ ...state,
4392
+ lastDrainError: event.message || null
4393
+ };
4394
+ default:
4170
4395
  return state;
4171
- }
4172
4396
  }
4173
4397
  }
4174
- function shouldDrainAfterTurnEnd(state, prevEndedOk) {
4175
- return !state.running && !state.drainPaused && state.queue.length > 0 && prevEndedOk;
4398
+ function shouldDrainAfterTurnEnd(state, cleanTurnEnd) {
4399
+ return cleanTurnEnd && !state.running && !state.drainPaused && state.queue.length > 0;
4176
4400
  }
4177
4401
  function applyChatQueueEvent(state, event) {
4178
4402
  const prevQueueLen = state.queue.length;
@@ -4191,7 +4415,8 @@ function applyChatQueueEvent(state, event) {
4191
4415
  }
4192
4416
  if (event.type === "turn-end" && !event.aborted && event.ok) {
4193
4417
  if (shouldDrainAfterTurnEnd(next, true)) {
4194
- outgoing.push({ type: "drain-ready", text: next.queue[0] });
4418
+ const head = next.queue[0];
4419
+ outgoing.push({ type: "drain-ready", text: head.text, request: head });
4195
4420
  }
4196
4421
  }
4197
4422
  return { state: next, outgoing };
@@ -4273,7 +4498,8 @@ function projectChatQueueStatus({
4273
4498
  }) {
4274
4499
  const preview = [];
4275
4500
  for (let i = 0; i < Math.min(maxPreview, state.queue.length); i++) {
4276
- const text = state.queue[i] ?? "";
4501
+ const item = state.queue[i];
4502
+ const text = typeof item === "string" ? item : item?.text ?? "";
4277
4503
  preview.push(text.length > previewCharLimit ? text.slice(0, previewCharLimit) + "\u2026" : text);
4278
4504
  }
4279
4505
  let composerPlaceholderKey = "default";
@@ -4312,10 +4538,19 @@ function createChatQueueTuiBinding(runTurn) {
4312
4538
  isCompactDialogSlashCommand: (s) => s === "/compact"
4313
4539
  });
4314
4540
  };
4315
- const enqueue = (text) => {
4316
- runtime.send({ type: "enqueue", text });
4541
+ const enqueue = (input) => {
4542
+ runtime.send({ type: "enqueue", text: input });
4317
4543
  return projectChatQueueStatus({ state: runtime.getState() });
4318
4544
  };
4545
+ const enqueueAndMaybeRun = async (input) => {
4546
+ enqueue(input);
4547
+ const status = runtime.getState();
4548
+ if (!status.running && !status.drainPaused) {
4549
+ await notifyTurnEnd({ ok: true, aborted: false });
4550
+ return true;
4551
+ }
4552
+ return false;
4553
+ };
4319
4554
  const notifyTurnStart = () => {
4320
4555
  runtime.send({ type: "turn-start" });
4321
4556
  };
@@ -4338,23 +4573,22 @@ function createChatQueueTuiBinding(runTurn) {
4338
4573
  while (true) {
4339
4574
  const status = runtime.getState();
4340
4575
  if (!status.running && !status.drainPaused && status.queue.length > 0 && lastOk) {
4341
- const text = status.queue[0];
4576
+ const req = status.queue[0];
4342
4577
  runtime.send({ type: "turn-start" });
4343
4578
  runtime.send({ type: "dequeue" });
4344
4579
  let turnOutcome;
4345
4580
  try {
4346
- turnOutcome = await runTurn(text);
4581
+ turnOutcome = await runTurn(req);
4347
4582
  } catch {
4348
4583
  turnOutcome = { ok: false, aborted: false };
4349
4584
  }
4350
- const { outcome: cascadeOutcome, mode: cascadeMode } = consumePreempt(turnOutcome);
4351
- runtime.send({ type: "turn-end", ...cascadeOutcome });
4352
- if (cascadeMode === "stop") {
4585
+ const consumed = consumePreempt(turnOutcome);
4586
+ const effectiveTurnOutcome = consumed.outcome;
4587
+ runtime.send({ type: "turn-end", ...effectiveTurnOutcome });
4588
+ if (consumed.mode === "stop") {
4353
4589
  runtime.send({ type: "drain-error", message: "" });
4354
4590
  }
4355
- lastOk = cascadeOutcome.ok && !cascadeOutcome.aborted;
4356
- if (cascadeOutcome.aborted) break;
4357
- if (!lastOk) break;
4591
+ lastOk = effectiveTurnOutcome.ok && !effectiveTurnOutcome.aborted;
4358
4592
  } else {
4359
4593
  break;
4360
4594
  }
@@ -4362,11 +4596,11 @@ function createChatQueueTuiBinding(runTurn) {
4362
4596
  };
4363
4597
  const drainHeadForManualTurn = () => {
4364
4598
  const status = runtime.getState();
4365
- if (status.running || status.drainPaused || status.queue.length === 0) return null;
4366
- const text = status.queue[0];
4599
+ if (status.running || status.queue.length === 0) return null;
4600
+ const head = status.queue[0];
4367
4601
  runtime.send({ type: "turn-start" });
4368
4602
  runtime.send({ type: "dequeue" });
4369
- return text;
4603
+ return head;
4370
4604
  };
4371
4605
  const preemptForDrain = () => {
4372
4606
  const status = runtime.getState();
@@ -4383,7 +4617,7 @@ function createChatQueueTuiBinding(runTurn) {
4383
4617
  const snapshotAndClearQueue = () => {
4384
4618
  const status = runtime.getState();
4385
4619
  if (status.queue.length === 0) return null;
4386
- const merged = status.queue.join("\n");
4620
+ const merged = status.queue.map((req) => req.text).join("\n");
4387
4621
  runtime.send({ type: "clear" });
4388
4622
  return merged;
4389
4623
  };
@@ -4398,6 +4632,7 @@ function createChatQueueTuiBinding(runTurn) {
4398
4632
  return {
4399
4633
  resolveSubmit,
4400
4634
  enqueue,
4635
+ enqueueAndMaybeRun,
4401
4636
  notifyTurnStart,
4402
4637
  notifyTurnEnd,
4403
4638
  drainHeadForManualTurn,
@@ -4411,9 +4646,22 @@ function createChatQueueTuiBinding(runTurn) {
4411
4646
  };
4412
4647
  }
4413
4648
 
4649
+ // packages/cli/tui/terminalNotification.ts
4650
+ function shouldEmitTerminalBell(decision) {
4651
+ return !decision.wasAborted && !decision.streamInterrupted && decision.exitCode === 0 && decision.interactive;
4652
+ }
4653
+ function emitTerminalBell(output) {
4654
+ try {
4655
+ output.write("\x07");
4656
+ } catch {
4657
+ }
4658
+ }
4659
+
4414
4660
  // packages/cli/tui/tuiHistory.ts
4415
4661
  var MAX_TUI_HISTORY_TURNS = 500;
4416
4662
  var turnLineCache = /* @__PURE__ */ new WeakMap();
4663
+ var turnLineCountCache = /* @__PURE__ */ new WeakMap();
4664
+ var renderCacheMissCount = 0;
4417
4665
  function createTurnHistory() {
4418
4666
  return {
4419
4667
  turns: [],
@@ -4432,6 +4680,7 @@ function startTurn(history, role) {
4432
4680
  }
4433
4681
  history.currentRole = role;
4434
4682
  history.currentContent = "";
4683
+ resetStreamingTurnCache();
4435
4684
  }
4436
4685
  function appendToCurrentTurn(history, chunk) {
4437
4686
  history.currentContent += chunk;
@@ -4444,6 +4693,7 @@ function finalizeCurrentTurn(history) {
4444
4693
  });
4445
4694
  history.currentRole = null;
4446
4695
  history.currentContent = "";
4696
+ resetStreamingTurnCache();
4447
4697
  if (history.turns.length > MAX_TUI_HISTORY_TURNS) {
4448
4698
  history.turns = history.turns.slice(history.turns.length - MAX_TUI_HISTORY_TURNS);
4449
4699
  }
@@ -4467,23 +4717,33 @@ function styleAssistantTurn(content, colorEnabled) {
4467
4717
  });
4468
4718
  return styledLines.join("\n");
4469
4719
  }
4720
+ function fillUserBubbleRow(row, surfaceSeq, contentWidth) {
4721
+ const visible = visibleWidth(row);
4722
+ if (visible > contentWidth) {
4723
+ const truncated = truncateAnsi(row, contentWidth);
4724
+ const padAfter = Math.max(0, contentWidth - visibleWidth(truncated));
4725
+ return `${surfaceSeq}${truncated}${" ".repeat(padAfter)}\x1B[0m`;
4726
+ }
4727
+ return renderSurfaceLine({ text: row, surface: surfaceSeq, padTo: contentWidth });
4728
+ }
4470
4729
  function renderTurnBlock(role, content, contentWidth, colorEnabled) {
4730
+ content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
4471
4731
  const lines = [];
4472
4732
  if (role === "user") {
4473
4733
  const logicalLines = content.split("\n");
4474
4734
  const accentSeq = colorEnabled ? themeColorSequence("accent") : "";
4475
- const chromeSeq = colorEnabled ? themeColorSequence("chrome") : "";
4735
+ const firstPrefix = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
4736
+ const multilinePrefix = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
4737
+ const hangingIndent = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
4738
+ const surfaceSeq = colorEnabled ? userSurfaceBackgroundSequence() : "";
4476
4739
  for (let i = 0; i < logicalLines.length; i++) {
4477
4740
  const line = logicalLines[i];
4478
- let styledLine;
4479
- if (colorEnabled) {
4480
- const prefix = i === 0 ? `${accentSeq}\u276F ` : `${chromeSeq}\u2502 `;
4481
- styledLine = `${prefix}\x1B[1m${accentSeq}${line}`;
4482
- } else {
4483
- const prefix = i === 0 ? "\u276F " : " ";
4484
- styledLine = `${prefix}${line}`;
4485
- }
4486
- lines.push(...wrapTranscriptLine(styledLine, contentWidth, " "));
4741
+ const prefix = i === 0 ? firstPrefix : multilinePrefix;
4742
+ const styledLine = `${prefix}${line}`;
4743
+ const rows = wrapTranscriptLine(styledLine, contentWidth, hangingIndent);
4744
+ lines.push(
4745
+ ...surfaceSeq ? rows.map((row) => fillUserBubbleRow(row, surfaceSeq, contentWidth)) : rows
4746
+ );
4487
4747
  }
4488
4748
  } else {
4489
4749
  const styledEntry = styleAssistantTurn(content, colorEnabled);
@@ -4493,57 +4753,184 @@ function renderTurnBlock(role, content, contentWidth, colorEnabled) {
4493
4753
  }
4494
4754
  return lines;
4495
4755
  }
4496
- function buildCopyViewLines(history) {
4497
- const turns = [...history.turns];
4498
- if (history.currentRole !== null) {
4499
- turns.push({ role: history.currentRole, content: history.currentContent });
4756
+ var streamingTurnCache = null;
4757
+ function resetStreamingTurnCache() {
4758
+ streamingTurnCache = null;
4759
+ }
4760
+ function renderPrefixTurnBlock(role, content, contentWidth, colorEnabled) {
4761
+ content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
4762
+ if (role === "user") {
4763
+ return renderTurnBlock(role, content, contentWidth, colorEnabled);
4500
4764
  }
4765
+ const highlighted = colorEnabled ? formatAssistantDisplay(content, { trimEdges: false }) : stripAnsi(formatAssistantDisplay(content, { trimEdges: false }));
4766
+ const rawLines = highlighted.split("\n");
4767
+ const styledLines = rawLines.map((line, idx) => {
4768
+ if (idx === 0 && !line.startsWith("[nolo]")) {
4769
+ const anchorPrefix = colorEnabled ? `${themeColorSequence("chrome")}\u25C8\x1B[39m ` : "\u25C8 ";
4770
+ return `${anchorPrefix}${line}`;
4771
+ }
4772
+ return line.startsWith("[nolo]") && colorEnabled ? themeText(line, "chrome", true) : line;
4773
+ });
4501
4774
  const lines = [];
4502
- for (const [index, turn] of turns.entries()) {
4503
- if (index > 0) lines.push("");
4504
- const normalized = stripAnsi(turn.content).replace(/\r\n/g, "\n").replace(/\r/g, "\n");
4505
- lines.push(...normalized.split("\n"));
4775
+ for (const logicalLine of styledLines) {
4776
+ lines.push(...wrapTranscriptLine(logicalLine, contentWidth));
4506
4777
  }
4507
4778
  return lines;
4508
4779
  }
4509
- function buildHistoryLines(history, contentWidth) {
4510
- const colorEnabled = resolveCliColorEnabled();
4780
+ function renderTailTurnBlock(role, content, contentWidth, colorEnabled) {
4781
+ content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
4782
+ const lines = [];
4783
+ if (role === "user") {
4784
+ const surfaceSeq = colorEnabled ? userSurfaceBackgroundSequence() : "";
4785
+ const accentSeq = colorEnabled ? themeColorSequence("accent") : "";
4786
+ const multilinePrefix = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
4787
+ const hangingIndent = colorEnabled ? `${accentSeq}\x1B[1m\u2503 ` : "\u2503 ";
4788
+ for (const rawLine of content.split("\n")) {
4789
+ const styledLine = `${multilinePrefix}${rawLine}`;
4790
+ const rows = wrapTranscriptLine(styledLine, contentWidth, hangingIndent);
4791
+ lines.push(
4792
+ ...surfaceSeq ? rows.map((row) => fillUserBubbleRow(row, surfaceSeq, contentWidth)) : rows
4793
+ );
4794
+ }
4795
+ } else {
4796
+ const highlighted = colorEnabled ? formatAssistantDisplay(content) : stripAnsi(formatAssistantDisplay(content));
4797
+ const rawLines = highlighted.split("\n");
4798
+ const styledLines = rawLines.map((line) => {
4799
+ return line.startsWith("[nolo]") && colorEnabled ? themeText(line, "chrome", true) : line;
4800
+ });
4801
+ for (const logicalLine of styledLines) {
4802
+ lines.push(...wrapTranscriptLine(logicalLine, contentWidth));
4803
+ }
4804
+ }
4805
+ return lines;
4806
+ }
4807
+ function getStreamingTurnLines(role, content, contentWidth, colorEnabled, density, surface) {
4808
+ if (streamingTurnCache && (streamingTurnCache.role !== role || streamingTurnCache.contentWidth !== contentWidth || streamingTurnCache.colorEnabled !== colorEnabled || streamingTurnCache.density !== density || streamingTurnCache.surface !== surface || !content.startsWith(streamingTurnCache.fullContent.slice(0, streamingTurnCache.prefixLength)))) {
4809
+ streamingTurnCache = null;
4810
+ }
4811
+ if (!streamingTurnCache) {
4812
+ streamingTurnCache = {
4813
+ role,
4814
+ contentWidth,
4815
+ colorEnabled,
4816
+ density,
4817
+ surface,
4818
+ fullContent: content,
4819
+ prefixLength: 0,
4820
+ prefixLines: []
4821
+ };
4822
+ }
4823
+ if (content.length > streamingTurnCache.fullContent.length) {
4824
+ let searchPos = streamingTurnCache.prefixLength;
4825
+ let candidateCut = -1;
4826
+ while (true) {
4827
+ const idx = content.indexOf("\n\n", searchPos);
4828
+ if (idx === -1) break;
4829
+ const cut = idx + 1;
4830
+ searchPos = idx + 2;
4831
+ const prefixSub = content.slice(0, cut);
4832
+ const fenceCount = (prefixSub.match(/^```/gm) || []).length;
4833
+ if (fenceCount % 2 === 0) {
4834
+ candidateCut = cut;
4835
+ break;
4836
+ }
4837
+ }
4838
+ if (candidateCut > streamingTurnCache.prefixLength) {
4839
+ const candidatePrefix = content.slice(0, candidateCut);
4840
+ const candidateTail = content.slice(candidateCut);
4841
+ const candPrefixLines = renderPrefixTurnBlock(role, candidatePrefix, contentWidth, colorEnabled);
4842
+ const candTailLines = renderTailTurnBlock(role, candidateTail, contentWidth, colorEnabled);
4843
+ const candCombined = [...candPrefixLines, ...candTailLines];
4844
+ const fullCheckLines = renderTurnBlock(role, content, contentWidth, colorEnabled);
4845
+ if (JSON.stringify(candCombined) === JSON.stringify(fullCheckLines)) {
4846
+ streamingTurnCache.prefixLength = candidateCut;
4847
+ streamingTurnCache.prefixLines = candPrefixLines;
4848
+ streamingTurnCache.fullContent = content;
4849
+ } else {
4850
+ streamingTurnCache.fullContent = content;
4851
+ }
4852
+ } else {
4853
+ streamingTurnCache.fullContent = content;
4854
+ }
4855
+ }
4856
+ if (streamingTurnCache.prefixLength === 0) {
4857
+ return renderTurnBlock(role, content, contentWidth, colorEnabled);
4858
+ }
4859
+ const tailContent = content.slice(streamingTurnCache.prefixLength);
4860
+ const tailLines = renderTailTurnBlock(role, tailContent, contentWidth, colorEnabled);
4861
+ return [...streamingTurnCache.prefixLines, ...tailLines];
4862
+ }
4863
+ var assistantPlainLinesCache = /* @__PURE__ */ new Map();
4864
+ function getAssistantPlainLines(content) {
4865
+ let plainLines = assistantPlainLinesCache.get(content);
4866
+ if (plainLines !== void 0) {
4867
+ return plainLines;
4868
+ }
4869
+ if (!/[\r\x00#|\-*_~`>+\[\]()•☐☑]|\b\d+\./.test(content)) {
4870
+ plainLines = content.trim().split("\n");
4871
+ } else {
4872
+ plainLines = stripAnsi(formatAssistantDisplay(content)).split("\n");
4873
+ }
4874
+ if (assistantPlainLinesCache.size > 2e3) {
4875
+ const firstKey = assistantPlainLinesCache.keys().next().value;
4876
+ if (firstKey !== void 0) assistantPlainLinesCache.delete(firstKey);
4877
+ }
4878
+ assistantPlainLinesCache.set(content, plainLines);
4879
+ return plainLines;
4880
+ }
4881
+ function countTurnLines(role, content, contentWidth) {
4882
+ content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
4883
+ let count = 0;
4884
+ if (role === "user") {
4885
+ for (const line of content.split("\n")) {
4886
+ count += wrapTranscriptLine(`\u2503 ${line}`, contentWidth, "\u2503 ").length;
4887
+ }
4888
+ } else {
4889
+ const plainLines = getAssistantPlainLines(content);
4890
+ for (let i = 0; i < plainLines.length; i++) {
4891
+ const line = plainLines[i];
4892
+ const wrapped = i === 0 && !line.startsWith("[nolo]") ? wrapTranscriptLine(`\u25C8 ${line}`, contentWidth) : wrapTranscriptLine(line, contentWidth);
4893
+ count += wrapped.length;
4894
+ }
4895
+ }
4896
+ return count;
4897
+ }
4898
+ function buildTurnOffsets(history, contentWidth) {
4511
4899
  const density = getActiveDensity();
4512
- const wrapped = [];
4900
+ const entries = [];
4901
+ let offset = 0;
4513
4902
  for (let i = 0; i < history.turns.length; i++) {
4514
4903
  const turn = history.turns[i];
4515
- if (density === "spacious" && (i > 0 || turn.role === "user")) {
4516
- wrapped.push("");
4517
- }
4518
- const cached = turnLineCache.get(turn);
4519
- if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.density === density) {
4520
- wrapped.push(...cached.lines);
4904
+ const separatorAbove = density === "spacious" && (i > 0 || turn.role === "user") ? 1 : 0;
4905
+ offset += separatorAbove;
4906
+ const cached = turnLineCountCache.get(turn);
4907
+ let lineCount;
4908
+ if (cached && cached.width === contentWidth) {
4909
+ lineCount = cached.count;
4521
4910
  } else {
4522
- const lines = renderTurnBlock(turn.role, turn.content, contentWidth, colorEnabled);
4523
- turnLineCache.set(turn, {
4524
- width: contentWidth,
4525
- color: colorEnabled,
4526
- density,
4527
- lines
4528
- });
4529
- wrapped.push(...lines);
4911
+ lineCount = countTurnLines(turn.role, turn.content, contentWidth);
4912
+ turnLineCountCache.set(turn, { width: contentWidth, count: lineCount });
4530
4913
  }
4914
+ entries.push({ startRow: offset, lineCount, separatorAbove });
4915
+ offset += lineCount;
4531
4916
  }
4532
- if (history.currentRole !== null && history.currentContent) {
4533
- const i = history.turns.length;
4534
- if (density === "spacious" && (i > 0 || history.currentRole === "user")) {
4535
- wrapped.push("");
4536
- }
4537
- wrapped.push(
4538
- ...renderTurnBlock(
4539
- history.currentRole,
4540
- history.currentContent,
4541
- contentWidth,
4542
- colorEnabled
4543
- )
4544
- );
4917
+ return { entries, totalLines: offset };
4918
+ }
4919
+ function currentTurnSeparator(history, density) {
4920
+ return density === "spacious" && (history.turns.length > 0 || history.currentRole === "user") ? 1 : 0;
4921
+ }
4922
+ function buildCopyViewLines(history) {
4923
+ const turns = [...history.turns];
4924
+ if (history.currentRole !== null) {
4925
+ turns.push({ role: history.currentRole, content: history.currentContent });
4926
+ }
4927
+ const lines = [];
4928
+ for (const [index, turn] of turns.entries()) {
4929
+ if (index > 0) lines.push("");
4930
+ const normalized = stripAnsi(turn.content).replace(/\r\n/g, "\n").replace(/\r/g, "\n");
4931
+ lines.push(...normalized.split("\n"));
4545
4932
  }
4546
- return wrapped;
4933
+ return lines;
4547
4934
  }
4548
4935
  function renderHistory(output, history, inputLines) {
4549
4936
  const tty = output;
@@ -4552,8 +4939,28 @@ function renderHistory(output, history, inputLines) {
4552
4939
  const columns = tty.columns ?? 80;
4553
4940
  const visibleHeight = Math.max(1, rows - inputLines);
4554
4941
  const contentWidth = Math.max(1, columns - 1);
4555
- const lines = buildHistoryLines(history, contentWidth);
4556
- const totalLines = lines.length;
4942
+ const colorEnabled = resolveCliColorEnabled();
4943
+ const density = getActiveDensity();
4944
+ const surface = colorEnabled ? userSurfaceBackgroundSequence() : "";
4945
+ const { entries, totalLines: finalizedLines } = buildTurnOffsets(
4946
+ history,
4947
+ contentWidth
4948
+ );
4949
+ let totalLines = finalizedLines;
4950
+ let currentStart = -1;
4951
+ let currentLines = [];
4952
+ if (history.currentRole !== null && history.currentContent) {
4953
+ currentLines = getStreamingTurnLines(
4954
+ history.currentRole,
4955
+ history.currentContent,
4956
+ contentWidth,
4957
+ colorEnabled,
4958
+ density,
4959
+ surface
4960
+ );
4961
+ currentStart = finalizedLines + currentTurnSeparator(history, density);
4962
+ totalLines = currentStart + currentLines.length;
4963
+ }
4557
4964
  if (history.followBottom) {
4558
4965
  history.scrollTop = Math.max(0, totalLines - visibleHeight);
4559
4966
  } else {
@@ -4564,19 +4971,71 @@ function renderHistory(output, history, inputLines) {
4564
4971
  }
4565
4972
  history.hasMoreAbove = history.scrollTop > 0;
4566
4973
  history.hasMoreBelow = history.scrollTop + visibleHeight < totalLines;
4567
- const visibleStart = history.scrollTop;
4568
- const visibleEnd = Math.min(totalLines, visibleStart + visibleHeight);
4569
- const visibleLines = lines.slice(visibleStart, visibleEnd);
4974
+ const winStart = history.scrollTop;
4975
+ const winEnd = Math.min(totalLines, winStart + visibleHeight);
4976
+ const visibleLines = new Array(visibleHeight).fill("");
4977
+ for (let i = 0; i < entries.length; i++) {
4978
+ const entry = entries[i];
4979
+ if (entry.separatorAbove > 0) {
4980
+ const sepRow = entry.startRow - 1;
4981
+ if (sepRow >= winStart && sepRow < winEnd) {
4982
+ visibleLines[sepRow - winStart] = "";
4983
+ }
4984
+ }
4985
+ const turnStart = entry.startRow;
4986
+ const turnEnd = turnStart + entry.lineCount;
4987
+ if (turnEnd <= winStart || turnStart >= winEnd) continue;
4988
+ const turn = history.turns[i];
4989
+ const cached = turnLineCache.get(turn);
4990
+ let lines;
4991
+ if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.density === density && cached.surface === surface) {
4992
+ lines = cached.lines;
4993
+ } else {
4994
+ renderCacheMissCount += 1;
4995
+ lines = renderTurnBlock(turn.role, turn.content, contentWidth, colorEnabled);
4996
+ turnLineCache.set(turn, {
4997
+ width: contentWidth,
4998
+ color: colorEnabled,
4999
+ density,
5000
+ surface,
5001
+ lines
5002
+ });
5003
+ }
5004
+ const interStart = Math.max(turnStart, winStart);
5005
+ const interEnd = Math.min(turnEnd, winEnd);
5006
+ for (let r = interStart; r < interEnd; r++) {
5007
+ visibleLines[r - winStart] = lines[r - turnStart] ?? "";
5008
+ }
5009
+ }
5010
+ if (currentStart >= 0) {
5011
+ const separatorAbove = currentTurnSeparator(history, density);
5012
+ if (separatorAbove > 0) {
5013
+ const sepRow = currentStart - 1;
5014
+ if (sepRow >= winStart && sepRow < winEnd) {
5015
+ visibleLines[sepRow - winStart] = "";
5016
+ }
5017
+ }
5018
+ const currentEnd = currentStart + currentLines.length;
5019
+ if (currentEnd > winStart && currentStart < winEnd) {
5020
+ const interStart = Math.max(currentStart, winStart);
5021
+ const interEnd = Math.min(currentEnd, winEnd);
5022
+ for (let r = interStart; r < interEnd; r++) {
5023
+ visibleLines[r - winStart] = currentLines[r - currentStart] ?? "";
5024
+ }
5025
+ }
5026
+ }
4570
5027
  let frame = "";
4571
5028
  for (let i = 0; i < visibleHeight; i++) {
4572
5029
  const line = visibleLines[i] ?? "";
4573
5030
  const padded = padOrTruncateToWidth(line, contentWidth);
4574
5031
  const thumb = renderScrollbarRow(i, visibleHeight, totalLines, history.scrollTop);
5032
+ const scrollbarPrefix = colorEnabled ? themeColorSequence("chrome") : "";
5033
+ const scrollbarSuffix = colorEnabled ? "\x1B[39m" : "";
4575
5034
  frame += `\x1B[${i + 1};1H`;
4576
5035
  frame += "\x1B[2K";
4577
5036
  frame += padded;
4578
5037
  frame += `\x1B[${columns}G`;
4579
- frame += thumb;
5038
+ frame += `${scrollbarPrefix}${thumb}${scrollbarSuffix}`;
4580
5039
  }
4581
5040
  const mainBottom = Math.max(1, rows - inputLines);
4582
5041
  frame += `\x1B[${mainBottom};1H`;
@@ -4603,7 +5062,11 @@ function applyScrollAction(history, action, output, inputLines) {
4603
5062
  const columns = tty.columns ?? 80;
4604
5063
  const visibleHeight = Math.max(1, rows - inputLines);
4605
5064
  const contentWidth = Math.max(1, columns - 1);
4606
- const totalLines = buildHistoryLines(history, contentWidth).length;
5065
+ const { totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
5066
+ let totalLines = finalizedLines;
5067
+ if (history.currentRole !== null && history.currentContent) {
5068
+ totalLines += currentTurnSeparator(history, getActiveDensity()) + countTurnLines(history.currentRole, history.currentContent, contentWidth);
5069
+ }
4607
5070
  const maxScrollTop = Math.max(0, totalLines - visibleHeight);
4608
5071
  history.followBottom = false;
4609
5072
  switch (action) {
@@ -5211,70 +5674,21 @@ ${content}`;
5211
5674
  return null;
5212
5675
  }
5213
5676
  var autoRouteByDialog = /* @__PURE__ */ new Map();
5214
- function toOverlayStatus(status) {
5215
- switch (status) {
5216
- case "running":
5217
- return "running";
5218
- case "done":
5219
- return "done";
5220
- case "failed":
5221
- case "timeout":
5222
- case "killed":
5223
- return "failed";
5224
- case "orphaned":
5225
- return "orphaned";
5226
- default:
5227
- return "running";
5228
- }
5229
- }
5230
- function buildTuiRunOverlay(parentDialogId, reported) {
5231
- if (!parentDialogId) return null;
5232
- let runs;
5233
- try {
5234
- runs = queryRunRecords({ parentDialogId }, { env: process.env }).runs;
5235
- } catch {
5236
- return null;
5237
- }
5238
- if (runs.length === 0) return null;
5239
- if (reported) {
5240
- runs = runs.filter((run) => reported.get(run.runId) !== run.status);
5241
- for (const run of runs) reported.set(run.runId, run.status);
5242
- if (runs.length === 0) return null;
5243
- }
5244
- let overlay = initialRunOverlayState;
5245
- for (const run of runs) {
5246
- overlay = reduceRunOverlay(overlay, {
5247
- type: "run-state-chg",
5248
- runId: run.runId,
5249
- info: {
5250
- name: run.agentName ?? run.agentKey ?? run.runId,
5251
- status: toOverlayStatus(run.status),
5252
- batchId: run.batchId,
5253
- parentDialogId: run.parentDialogId,
5254
- ...run.status === "failed" && run.note ? { errorMessage: run.note } : {}
5255
- }
5256
- });
5257
- }
5258
- return buildOverlayPresentation(overlay);
5259
- }
5260
5677
  async function runAgentChat(scriptDir, state, message, env, output, agentRunner = runAgentTurn, options = {}) {
5261
5678
  let effectiveAgentKey = state.agentKey;
5262
5679
  let effectiveAgentName = state.agentName;
5263
5680
  const continueId = state.dialogId;
5264
5681
  const cachedRoute = continueId ? autoRouteByDialog.get(continueId) : void 0;
5682
+ const hasImages = options.imageUrls && options.imageUrls.length > 0;
5265
5683
  if (cachedRoute && !options.explicitAgentSwitch) {
5266
5684
  effectiveAgentKey = cachedRoute.agentKey;
5267
5685
  effectiveAgentName = cachedRoute.agentName;
5268
5686
  } else if (!continueId && env.NOLO_AUTO_ROUTE !== "0" && state.agentKey === DEFAULT_TUI_AGENT_KEY) {
5269
- const authToken = resolvePlatformAuthToken(env);
5270
- const route = authToken ? await classifyCliAutoRoute(message, {
5687
+ const route = classifyCliAutoRoute(message, {
5271
5688
  serverUrl: state.serverUrl,
5272
- authToken
5273
- }) : {
5274
- agentKey: CLI_AUTO_TIER_AGENT_KEYS[resolveCliAutoFallbackTier(message)],
5275
- tier: resolveCliAutoFallbackTier(message),
5276
- classified: false
5277
- };
5689
+ authToken: resolvePlatformAuthToken(env),
5690
+ hasImages
5691
+ });
5278
5692
  effectiveAgentKey = route.agentKey;
5279
5693
  effectiveAgentName = `auto\u2192${route.tier}`;
5280
5694
  if (effectiveAgentKey !== state.agentKey) {
@@ -5285,7 +5699,6 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
5285
5699
  );
5286
5700
  }
5287
5701
  }
5288
- const hasImages = options.imageUrls && options.imageUrls.length > 0;
5289
5702
  const userSelectedAgent = state.agentKey !== DEFAULT_TUI_AGENT_KEY;
5290
5703
  const visionProbeKey = hasImages && userSelectedAgent ? state.agentKey : effectiveAgentKey;
5291
5704
  if (hasImages && effectiveAgentKey !== CLI_IMAGE_AGENT_KEY) {
@@ -5398,18 +5811,22 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
5398
5811
  // inside a TUI turn are stamped with the current conversation. Previously
5399
5812
  // this factory only existed when pasted text was present, which meant a
5400
5813
  // plain (no-paste) turn had no injection point for parentDialogId and the
5401
- // run-overlay could never see runs spawned this turn.
5814
+ // run-completion watcher could never attribute runs spawned this turn.
5402
5815
  ...options.pastedTextStore?.items.size ? { pastedTextStore: options.pastedTextStore } : {},
5403
5816
  localRuntimeAdapterFactory: (factoryEnv, factoryOptions) => createCliLocalRuntimeAdapter({
5404
5817
  env: factoryEnv,
5405
5818
  cwd: factoryOptions?.cwd ?? state.cwd,
5406
5819
  ...options.pastedTextStore ? { pastedTextStore: options.pastedTextStore } : {},
5407
5820
  // Stamp spawned background runs with the current TUI dialog so the
5408
- // run-overlay can filter runs belonging to this conversation.
5821
+ // run-completion watcher can attribute terminal-state wakes to this
5822
+ // conversation.
5409
5823
  ...state.dialogId ? { parentDialogId: state.dialogId } : {},
5410
5824
  ...options.activityReporter ? { activityReporter: options.activityReporter } : {}
5411
5825
  }),
5412
5826
  ...options.activityReporter ? { activityReporter: options.activityReporter } : {},
5827
+ // 转发 dock 订阅:runAgentTurn 的输出层靠它判断「有面板」从而抑制
5828
+ // transcript 的进展卡片;dock 本身也靠它接收模型轮询带回来的快照。
5829
+ ...options.onAgentRunStatus ? { onAgentRunStatus: options.onAgentRunStatus } : {},
5413
5830
  ...skillAllowedTools !== void 0 ? { allowedToolNames: skillAllowedTools } : {},
5414
5831
  ...contextBlockScopes.length > 0 ? { contextBlockScopes } : {}
5415
5832
  });
@@ -5514,9 +5931,9 @@ function waitForActionGate(rl, input, output, gate, spawnRunner) {
5514
5931
  });
5515
5932
  });
5516
5933
  }
5517
- function persistAgentSelection(state, env) {
5934
+ function persistAgentSelection(state, env, saveSelection = saveProfileAgentSelection) {
5518
5935
  try {
5519
- saveProfileAgentSelection({
5936
+ saveSelection({
5520
5937
  agentKey: state.agentKey,
5521
5938
  agentName: state.agentName
5522
5939
  });
@@ -5696,12 +6113,20 @@ async function startTuiWorkspace(options) {
5696
6113
  }
5697
6114
  });
5698
6115
  const activityReporter = (label) => activityIndicator.report(label);
5699
- const reportedRunStatuses = /* @__PURE__ */ new Map();
6116
+ let runWakeHandler = null;
6117
+ const runCompletionWatcher = createRunCompletionWatcher({
6118
+ getCurrentDialogId: () => state.dialogId ?? null,
6119
+ onWake: (text) => runWakeHandler?.(text)
6120
+ });
5700
6121
  const runRegistryPoller = createRunRegistryPoller({
5701
6122
  getDockedRuns: () => activityIndicator.getAgentRuns(),
5702
6123
  update: (snapshot) => activityIndicator.updateAgentRun(snapshot),
5703
- readRecord: (runId) => readRunRecord(runId),
5704
- reconcile: (runId) => checkStaleRun(runId)
6124
+ // 显式传 env:resolveNoloHome 只认传入 env 的 NOLO_HOME,不传则永远读
6125
+ // ~/.nolo——设了 NOLO_HOME 的环境(dev、测试)会读错目录。run 记录读取
6126
+ // 与 reconcile 的调用点也是同样写法。
6127
+ readRecord: (runId) => readRunRecord(runId, { env: process.env }),
6128
+ reconcile: (runId) => checkStaleRun(runId, { env: process.env }),
6129
+ onRecordsPolled: (records) => runCompletionWatcher.observe(records)
5705
6130
  });
5706
6131
  let explicitAgentSwitch = false;
5707
6132
  let copyViewExitResolver = null;
@@ -5864,11 +6289,17 @@ async function startTuiWorkspace(options) {
5864
6289
  void maybeAutoRefreshTheme();
5865
6290
  }, AUTO_THEME_POLL_MS);
5866
6291
  }
5867
- const runOneAgentTurn = async (message, imageUrls, actionGateHandler, confirmDestructiveAction) => {
6292
+ const runOneAgentTurn = async (inputMsg, imageUrls, actionGateHandler, confirmDestructiveAction) => {
6293
+ const req = createTurnRequest(inputMsg);
6294
+ if (req.event.kind === "child-run-completed") {
6295
+ for (const r of req.event.runs) {
6296
+ runCompletionWatcher.markAcknowledged(r.runId);
6297
+ }
6298
+ }
6299
+ const message = req.text;
5868
6300
  forcedStop = false;
5869
6301
  turnEpoch += 1;
5870
6302
  const myEpoch = turnEpoch;
5871
- const turnParentDialogId = state.dialogId;
5872
6303
  history.followBottom = true;
5873
6304
  startTurn(history, "user");
5874
6305
  appendToCurrentTurn(history, message);
@@ -5879,12 +6310,12 @@ async function startTuiWorkspace(options) {
5879
6310
  const agentOutput = isInteractiveInput(input) ? createHistoryOutputStream(history, () => {
5880
6311
  scheduleRender();
5881
6312
  }) : output;
5882
- const requestUserChoice = isInteractiveInput(input) && dialogHost ? async (req) => {
6313
+ const requestUserChoice = isInteractiveInput(input) && dialogHost ? async (req2) => {
5883
6314
  modalOwnsKeyboard = true;
5884
6315
  try {
5885
6316
  return await dialogHost.run(
5886
6317
  (anchor) => runAskChoiceDialog({
5887
- request: req,
6318
+ request: req2,
5888
6319
  input,
5889
6320
  output,
5890
6321
  ...anchor
@@ -5934,7 +6365,8 @@ async function startTuiWorkspace(options) {
5934
6365
  ...runResult.dialogId ? {
5935
6366
  dialogId: runResult.dialogId,
5936
6367
  dialogKey: nextDialogKey,
5937
- dialogLabel: runResult.title || runResult.dialogId
6368
+ dialogLabel: runResult.title || runResult.dialogId,
6369
+ ...runResult.title ? { dialogTitle: runResult.title } : {}
5938
6370
  } : {},
5939
6371
  ...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {}
5940
6372
  };
@@ -5943,6 +6375,14 @@ async function startTuiWorkspace(options) {
5943
6375
  }
5944
6376
  const wasAborted = activeTurnAbort.signal.aborted;
5945
6377
  activeTurnAbort = null;
6378
+ if (shouldEmitTerminalBell({
6379
+ wasAborted,
6380
+ streamInterrupted: runResult.streamInterrupted,
6381
+ exitCode: runResult.exitCode,
6382
+ interactive: isInteractiveInput(input)
6383
+ })) {
6384
+ emitTerminalBell(output);
6385
+ }
5946
6386
  explicitAgentSwitch = false;
5947
6387
  if (isInteractiveInput(input)) {
5948
6388
  finalizeCurrentTurn(history);
@@ -5964,7 +6404,8 @@ async function startTuiWorkspace(options) {
5964
6404
  ...runResult.dialogId ? {
5965
6405
  dialogId: runResult.dialogId,
5966
6406
  dialogKey: nextDialogKey,
5967
- dialogLabel: runResult.title || runResult.dialogId
6407
+ dialogLabel: runResult.title || runResult.dialogId,
6408
+ ...runResult.title ? { dialogTitle: runResult.title } : {}
5968
6409
  } : {},
5969
6410
  ...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {},
5970
6411
  ...runResult.contextWindow ? { contextWindow: runResult.contextWindow } : {},
@@ -5985,14 +6426,6 @@ async function startTuiWorkspace(options) {
5985
6426
  emitCommandOutput(t("dialogNotSavedHint"));
5986
6427
  }
5987
6428
  }
5988
- if (!wasAborted) {
5989
- const overlayText = buildTuiRunOverlay(turnParentDialogId, reportedRunStatuses);
5990
- if (overlayText) {
5991
- emitCommandOutput(`
5992
- \u4F60\u7684 run \u8FDB\u5C55\uFF1A
5993
- ${overlayText}`);
5994
- }
5995
- }
5996
6429
  return { ok: !wasAborted, aborted: wasAborted };
5997
6430
  } finally {
5998
6431
  activityIndicator.stop();
@@ -6027,6 +6460,17 @@ ${overlayText}`);
6027
6460
  renderHistoryToOutput();
6028
6461
  if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
6029
6462
  };
6463
+ const persistExplicitAgentSwitch = (previousAgentKey) => {
6464
+ if (state.agentKey === previousAgentKey) return false;
6465
+ if (state.dialogId) autoRouteByDialog.delete(state.dialogId);
6466
+ explicitAgentSwitch = true;
6467
+ persistAgentSelection(
6468
+ state,
6469
+ options.env ?? process.env,
6470
+ options.saveAgentSelection
6471
+ );
6472
+ return true;
6473
+ };
6030
6474
  const runSubmittedLine = async (line, actionGateHandler, confirmDestructiveAction) => {
6031
6475
  if (!line.trim()) return false;
6032
6476
  const result = handleTuiInput(line, state);
@@ -6045,9 +6489,7 @@ ${overlayText}`);
6045
6489
  emitCommandOutput(result.output);
6046
6490
  }
6047
6491
  if (state.agentKey !== previousAgentKey) {
6048
- if (state.dialogId) autoRouteByDialog.delete(state.dialogId);
6049
- explicitAgentSwitch = true;
6050
- persistAgentSelection(state, options.env ?? process.env);
6492
+ persistExplicitAgentSwitch(previousAgentKey);
6051
6493
  }
6052
6494
  if (result.action?.type === "exit") return true;
6053
6495
  if (result.action?.type === "clear") {
@@ -6098,6 +6540,7 @@ ${overlayText}`);
6098
6540
  if (result.action?.type === "compact") {
6099
6541
  const runner = options.compactRunner ?? compactDialog;
6100
6542
  const authToken = resolvePlatformAuthToken(options.env ?? {});
6543
+ const compactStart = Date.now();
6101
6544
  try {
6102
6545
  const compactResult = await runner({
6103
6546
  serverUrl: state.serverUrl,
@@ -6105,20 +6548,45 @@ ${overlayText}`);
6105
6548
  dialogId: result.action.dialogId,
6106
6549
  summaryLlmCaller: options.summaryLlmCaller
6107
6550
  });
6551
+ const elapsedSec = ((Date.now() - compactStart) / 1e3).toFixed(1);
6108
6552
  state = {
6109
6553
  ...state,
6110
6554
  dialogId: compactResult.dialogId,
6111
6555
  dialogKey: compactResult.dialogKey,
6112
- dialogLabel: compactResult.dialogId
6556
+ dialogLabel: compactResult.dialogId,
6557
+ dialogTitle: state.dialogTitle,
6558
+ // Compact forks into a fresh dialog that only inherits the summary,
6559
+ // not the full message history. Drop usage-derived context so the
6560
+ // composer chip falls back to the default CLI surface estimate and
6561
+ // the context percentage visibly drops. Mirrors the /clear reset.
6562
+ turnTokens: void 0,
6563
+ estimatedContextTokens: estimateDefaultCliContextTokens({
6564
+ cwd: state.cwd,
6565
+ agentKey: state.agentKey,
6566
+ agentName: state.agentKey === DEFAULT_TUI_AGENT_KEY && (options.env ?? process.env).NOLO_AUTO_ROUTE !== "0" ? "DeepSeek V4 Flash" : state.agentName,
6567
+ model: state.agentKey === DEFAULT_TUI_AGENT_KEY && (options.env ?? process.env).NOLO_AUTO_ROUTE !== "0" ? "deepseek-v4-flash" : void 0
6568
+ })
6113
6569
  };
6114
- output.write(
6115
- `${t(
6116
- compactResult.summaryGenerated ? "compactDone" : "compactDoneNoSummary",
6117
- result.action.dialogId,
6118
- compactResult.dialogId
6119
- )}
6120
- `
6570
+ const elapsed = `${elapsedSec}s`;
6571
+ const message = compactResult.summaryGenerated ? compactResult.compactedMessageCount > 0 ? t(
6572
+ "compactSuccessWithCount",
6573
+ result.action.dialogId,
6574
+ compactResult.dialogId,
6575
+ elapsed,
6576
+ String(compactResult.compactedMessageCount)
6577
+ ) : t(
6578
+ "compactSuccess",
6579
+ result.action.dialogId,
6580
+ compactResult.dialogId,
6581
+ elapsed
6582
+ ) : t(
6583
+ "compactForked",
6584
+ result.action.dialogId,
6585
+ compactResult.dialogId,
6586
+ elapsed
6121
6587
  );
6588
+ output.write(`${message}
6589
+ `);
6122
6590
  } catch (error) {
6123
6591
  output.write(
6124
6592
  `[nolo] Compact failed: ${toErrorMessage(error)}
@@ -6282,6 +6750,7 @@ ${overlayText}`);
6282
6750
  dialogId: pickResult.dialog.id,
6283
6751
  dialogKey: pickResult.dialog.dbKey,
6284
6752
  dialogLabel: pickResult.dialog.title || pickResult.dialog.id,
6753
+ dialogTitle: pickResult.dialog.title,
6285
6754
  turnTokens: void 0
6286
6755
  };
6287
6756
  clearCollapsedPasteStore(pasteStore);
@@ -6418,12 +6887,6 @@ ${err.message}` : ""}`
6418
6887
  resolveCliColorEnabled()
6419
6888
  );
6420
6889
  }
6421
- if (history.hasMoreAbove || history.hasMoreBelow) {
6422
- const scrollHints = [];
6423
- if (history.hasMoreAbove) scrollHints.push("\u25B2 PgUp");
6424
- if (history.hasMoreBelow) scrollHints.push("\u25BC PgDn");
6425
- base += dimCliText(` \xB7 \u2195 ${scrollHints.join("/")}`, resolveCliColorEnabled());
6426
- }
6427
6890
  return base;
6428
6891
  },
6429
6892
  getActivityLines: () => activityIndicator.getActivityLines(resolveCliColorEnabled()),
@@ -6476,6 +6939,7 @@ ${err.message}` : ""}`
6476
6939
  autoThemeTimer = null;
6477
6940
  }
6478
6941
  runRegistryPoller.dispose();
6942
+ runCompletionWatcher.dispose();
6479
6943
  activityIndicator.dispose();
6480
6944
  resolveDone?.();
6481
6945
  clearCollapsedPasteStore(pasteStore);
@@ -6486,6 +6950,83 @@ ${err.message}` : ""}`
6486
6950
  output.write("\x1B[?25h\x1B[?2026l");
6487
6951
  input.setRawMode?.(false);
6488
6952
  };
6953
+ const buildInteractiveTurnHandlers = () => {
6954
+ const actionGateHandler = async (gate) => {
6955
+ modalOwnsKeyboard = true;
6956
+ try {
6957
+ return await waitForRawActionGate(input, output, gate, spawnRunner, {
6958
+ beforeSubprocess: () => fixedInput.pause(),
6959
+ afterSubprocess: () => fixedInput.resumeFromSubprocess(),
6960
+ registerToken: (handler) => {
6961
+ rawActionGateTokenHandler = handler;
6962
+ }
6963
+ });
6964
+ } finally {
6965
+ modalOwnsKeyboard = false;
6966
+ }
6967
+ };
6968
+ const confirmDestructiveAction = async (request) => {
6969
+ modalOwnsKeyboard = true;
6970
+ try {
6971
+ return await dialogHost.run(
6972
+ (anchor) => runConfirmDialog({
6973
+ request,
6974
+ input,
6975
+ output,
6976
+ ...anchor
6977
+ })
6978
+ );
6979
+ } finally {
6980
+ modalOwnsKeyboard = false;
6981
+ }
6982
+ };
6983
+ return { actionGateHandler, confirmDestructiveAction };
6984
+ };
6985
+ const runIdleTextTurn = async (inputMsg) => {
6986
+ const req = createTurnRequest(inputMsg);
6987
+ const { actionGateHandler, confirmDestructiveAction } = buildInteractiveTurnHandlers();
6988
+ const binding = ensureChatQueueBinding(actionGateHandler, confirmDestructiveAction);
6989
+ binding.notifyTurnStart();
6990
+ busy = true;
6991
+ fixedInput.enterOutputMode(req.text);
6992
+ try {
6993
+ const outcome = await runOneAgentTurn(
6994
+ req,
6995
+ [],
6996
+ actionGateHandler,
6997
+ confirmDestructiveAction
6998
+ );
6999
+ await binding.notifyTurnEnd(outcome);
7000
+ } catch (err) {
7001
+ await binding.notifyTurnEnd({ ok: false, aborted: false });
7002
+ emitCommandOutput(
7003
+ `${t("turnFailed")}${err instanceof Error && err.message ? `
7004
+ ${err.message}` : ""}`
7005
+ );
7006
+ } finally {
7007
+ busy = false;
7008
+ }
7009
+ refreshGitStatus();
7010
+ flushPendingRender();
7011
+ fixedInput.exitOutputMode(buffer, cursorPos);
7012
+ };
7013
+ runWakeHandler = (event) => {
7014
+ if (done) return;
7015
+ if (busy || fixedInput.isPaused() || copyViewExitResolver) {
7016
+ const { actionGateHandler, confirmDestructiveAction } = buildInteractiveTurnHandlers();
7017
+ ensureChatQueueBinding(actionGateHandler, confirmDestructiveAction).enqueue(event);
7018
+ if (fixedInput.active && !fixedInput.isPaused()) {
7019
+ fixedInput.repaint(buffer, cursorPos);
7020
+ }
7021
+ return;
7022
+ }
7023
+ void runIdleTextTurn(event).catch((err) => {
7024
+ emitCommandOutput(
7025
+ `${t("turnFailed")}${err instanceof Error && err.message ? `
7026
+ ${err.message}` : ""}`
7027
+ );
7028
+ });
7029
+ };
6489
7030
  const handleInputToken = async (sequence) => {
6490
7031
  if (done) return;
6491
7032
  if (copyViewExitResolver) {
@@ -6619,18 +7160,41 @@ ${merged}` : merged;
6619
7160
  if (busyLock) {
6620
7161
  const trimmedText = submittedText.trim();
6621
7162
  const busySlashCommand = trimmedText.split(/\s+/)[0]?.toLowerCase();
6622
- const isBusyLocalSlash = busySlashCommand === "/context" || busySlashCommand === "/ctx" || busySlashCommand === "/switch";
7163
+ const isBusyLocalSlash = busySlashCommand === "/context" || busySlashCommand === "/ctx" || busySlashCommand === "/switch" || busySlashCommand === "/theme" || busySlashCommand === "/density" || busySlashCommand === "/runtime" || busySlashCommand === "/tools" || busySlashCommand === "/tasks" || busySlashCommand === "/jobs" || busySlashCommand === "/procs" || busySlashCommand === "/agents" || busySlashCommand === "/doc" || busySlashCommand === "/skill" || busySlashCommand === "/customize" || busySlashCommand === "/login" || busySlashCommand === "/profile" || busySlashCommand === "/version";
6623
7164
  if (isBusyLocalSlash) {
7165
+ releaseCollapsedPasteReferences(submittedText, pasteStore);
7166
+ buffer = "";
7167
+ cursorPos = 0;
7168
+ if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
6624
7169
  const beforeAgentKey = state.agentKey;
6625
7170
  const res = handleTuiInput(submittedText, state);
6626
- if (res.action) {
7171
+ if (res.action?.type === "theme-refresh") {
7172
+ state = res.nextState;
7173
+ const detected2 = await detectTerminalBackground({
7174
+ stdin: input,
7175
+ stdout: output,
7176
+ allowSystemFallback: true
7177
+ });
7178
+ let refreshMsg = "";
7179
+ if (detected2 && applyDetectedBackground(detected2)) {
7180
+ refreshMsg = t("themeRefreshed", detected2.brightness);
7181
+ } else if (detected2) {
7182
+ refreshMsg = t("themeRefreshed", detected2.brightness);
7183
+ } else {
7184
+ refreshMsg = t("themeRefreshFailed");
7185
+ }
7186
+ if (refreshMsg) {
7187
+ output.write(`${refreshMsg}
7188
+ `);
7189
+ }
7190
+ } else if (res.action) {
6627
7191
  output.write(
6628
7192
  "Model picker isn't available while a reply is running. Use `/switch <name>` to switch now (takes effect on the next turn), or wait for the reply to finish.\n"
6629
7193
  );
6630
7194
  } else {
6631
7195
  state = res.nextState;
6632
7196
  let msg = res.output;
6633
- if (busySlashCommand === "/switch" && res.nextState.agentKey !== beforeAgentKey) {
7197
+ if (busySlashCommand === "/switch" && persistExplicitAgentSwitch(beforeAgentKey)) {
6634
7198
  const hint = "Note: the new model takes effect on the next turn. Switching models may consume more tokens because the conversation context is re-sent to the new model.";
6635
7199
  msg = msg ? `${msg}
6636
7200
  ${hint}` : hint;
@@ -6640,43 +7204,10 @@ ${hint}` : hint;
6640
7204
  `);
6641
7205
  }
6642
7206
  }
6643
- releaseCollapsedPasteReferences(submittedText, pasteStore);
6644
- buffer = "";
6645
- cursorPos = 0;
6646
- if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
6647
7207
  return;
6648
7208
  }
6649
- const binding = ensureChatQueueBinding(
6650
- async (gate) => {
6651
- modalOwnsKeyboard = true;
6652
- try {
6653
- return await waitForRawActionGate(input, output, gate, spawnRunner, {
6654
- beforeSubprocess: () => fixedInput.pause(),
6655
- afterSubprocess: () => fixedInput.resumeFromSubprocess(),
6656
- registerToken: (handler) => {
6657
- rawActionGateTokenHandler = handler;
6658
- }
6659
- });
6660
- } finally {
6661
- modalOwnsKeyboard = false;
6662
- }
6663
- },
6664
- async (request) => {
6665
- modalOwnsKeyboard = true;
6666
- try {
6667
- return await dialogHost.run(
6668
- (anchor) => runConfirmDialog({
6669
- request,
6670
- input,
6671
- output,
6672
- ...anchor
6673
- })
6674
- );
6675
- } finally {
6676
- modalOwnsKeyboard = false;
6677
- }
6678
- }
6679
- );
7209
+ const { actionGateHandler, confirmDestructiveAction } = buildInteractiveTurnHandlers();
7210
+ const binding = ensureChatQueueBinding(actionGateHandler, confirmDestructiveAction);
6680
7211
  const decision = binding.resolveSubmit({
6681
7212
  text: submittedText,
6682
7213
  isRunning: true
@@ -6693,62 +7224,13 @@ ${hint}` : hint;
6693
7224
  return;
6694
7225
  }
6695
7226
  if (!submittedText.trim() && chatQueueBinding && chatQueueBinding.queueLength() > 0) {
6696
- const actionGateHandler = async (gate) => {
6697
- modalOwnsKeyboard = true;
6698
- try {
6699
- return await waitForRawActionGate(input, output, gate, spawnRunner, {
6700
- beforeSubprocess: () => fixedInput.pause(),
6701
- afterSubprocess: () => fixedInput.resumeFromSubprocess(),
6702
- registerToken: (handler) => {
6703
- rawActionGateTokenHandler = handler;
6704
- }
6705
- });
6706
- } finally {
6707
- modalOwnsKeyboard = false;
6708
- }
6709
- };
6710
- const confirmDestructiveAction = async (request) => {
6711
- modalOwnsKeyboard = true;
6712
- try {
6713
- return await dialogHost.run(
6714
- (anchor) => runConfirmDialog({
6715
- request,
6716
- input,
6717
- output,
6718
- ...anchor
6719
- })
6720
- );
6721
- } finally {
6722
- modalOwnsKeyboard = false;
6723
- }
6724
- };
7227
+ const { actionGateHandler, confirmDestructiveAction } = buildInteractiveTurnHandlers();
6725
7228
  const manualBinding = ensureChatQueueBinding(actionGateHandler, confirmDestructiveAction);
6726
7229
  const drainedText = manualBinding.drainHeadForManualTurn();
6727
7230
  if (drainedText !== null) {
6728
- busy = true;
6729
7231
  buffer = "";
6730
7232
  cursorPos = 0;
6731
- fixedInput.enterOutputMode(drainedText);
6732
- try {
6733
- const outcome = await runOneAgentTurn(
6734
- drainedText,
6735
- [],
6736
- actionGateHandler,
6737
- confirmDestructiveAction
6738
- );
6739
- await manualBinding.notifyTurnEnd(outcome);
6740
- } catch (err) {
6741
- await manualBinding.notifyTurnEnd({ ok: false, aborted: false });
6742
- emitCommandOutput(
6743
- `${t("turnFailed")}${err instanceof Error && err.message ? `
6744
- ${err.message}` : ""}`
6745
- );
6746
- } finally {
6747
- busy = false;
6748
- }
6749
- refreshGitStatus();
6750
- flushPendingRender();
6751
- fixedInput.exitOutputMode(buffer, cursorPos);
7233
+ await runIdleTextTurn(drainedText);
6752
7234
  return;
6753
7235
  }
6754
7236
  }
@@ -6758,37 +7240,11 @@ ${err.message}` : ""}`
6758
7240
  fixedInput.enterOutputMode(submittedText);
6759
7241
  let shouldExit = false;
6760
7242
  try {
7243
+ const { actionGateHandler, confirmDestructiveAction } = buildInteractiveTurnHandlers();
6761
7244
  shouldExit = await runSubmittedLine(
6762
7245
  submittedText,
6763
- async (gate) => {
6764
- modalOwnsKeyboard = true;
6765
- try {
6766
- return await waitForRawActionGate(input, output, gate, spawnRunner, {
6767
- beforeSubprocess: () => fixedInput.pause(),
6768
- afterSubprocess: () => fixedInput.resumeFromSubprocess(),
6769
- registerToken: (handler) => {
6770
- rawActionGateTokenHandler = handler;
6771
- }
6772
- });
6773
- } finally {
6774
- modalOwnsKeyboard = false;
6775
- }
6776
- },
6777
- async (request) => {
6778
- modalOwnsKeyboard = true;
6779
- try {
6780
- return await dialogHost.run(
6781
- (anchor) => runConfirmDialog({
6782
- request,
6783
- input,
6784
- output,
6785
- ...anchor
6786
- })
6787
- );
6788
- } finally {
6789
- modalOwnsKeyboard = false;
6790
- }
6791
- }
7246
+ actionGateHandler,
7247
+ confirmDestructiveAction
6792
7248
  );
6793
7249
  } finally {
6794
7250
  busy = false;
@@ -6871,7 +7327,6 @@ export {
6871
7327
  applyOutputChunkToCurrentTurn,
6872
7328
  applyScrollAction,
6873
7329
  applyTerminalOutputToText,
6874
- buildTuiRunOverlay,
6875
7330
  buildWindowTitle,
6876
7331
  countPhysicalLines,
6877
7332
  createFixedInput,