nolo-cli 0.8.0-alpha.21 → 0.8.0-alpha.23

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 (112) hide show
  1. package/{_executeModel-42U3VOVZ.js → _executeModel-YXTTYRXS.js} +44 -43
  2. package/{action-TLI3V62L.js → action-QM2ONPYZ.js} +9 -9
  3. package/{addContentAction-57RSIIMR.js → addContentAction-UXY3GM53.js} +8 -8
  4. package/{addDialogAgentAction-G3VWEA6E.js → addDialogAgentAction-MUBYOG65.js} +10 -10
  5. package/{agentDeleteCommand-5DD2IM3J.js → agentDeleteCommand-4NO7Y6UI.js} +28 -27
  6. package/{agentEmailCommands-6FACJBU4.js → agentEmailCommands-NPP5TGZV.js} +60 -58
  7. package/{agentListCommands-I6KZYCIG.js → agentListCommands-IP5BNB5W.js} +32 -30
  8. package/{agentMachineCommands-VKLIGMZA.js → agentMachineCommands-24NFTIKY.js} +27 -26
  9. package/{agentPullCommand-O2MTUAFR.js → agentPullCommand-N6UWRTVL.js} +3 -3
  10. package/{agentRecordCommands-7TZICYDT.js → agentRecordCommands-7AWSR46F.js} +51 -49
  11. package/{agentRunCommand-L4OM23KV.js → agentRunCommand-P46WCJ6P.js} +55 -52
  12. package/{agentRunControl-K4VKNEHF.js → agentRunControl-S3G62M6C.js} +3 -3
  13. package/{agentRuntimeLocal-ZYEIPTY4.js → agentRuntimeLocal-V5UV7S4R.js} +14 -12
  14. package/{agentSlice-BX7GXSNO.js → agentSlice-3CVAZZOP.js} +9 -9
  15. package/{authCommand-EB5JSOX5.js → authCommand-B6P2XYLN.js} +11 -11
  16. package/{authCommands-XPEHTKSM.js → authCommands-4YKA4GTU.js} +7 -7
  17. package/{chunk-AS4PVWA4.js → chunk-2CVZSC5L.js} +1 -1
  18. package/{chunk-VUW5FBDB.js → chunk-4VA3UQRF.js} +9 -9
  19. package/{chunk-2JCXITPK.js → chunk-5NYGMN4O.js} +15 -15
  20. package/{chunk-AGFH73SK.js → chunk-6KRA6AWI.js} +1 -1
  21. package/{chunk-P3PKED2I.js → chunk-6OHYC4BY.js} +9 -12
  22. package/{chunk-5KLGBAAR.js → chunk-6UUD2WES.js} +1 -1
  23. package/{chunk-ENOG22KJ.js → chunk-A4MYG3TR.js} +18 -20
  24. package/{chunk-2FTTDCD4.js → chunk-AMJ7LA5D.js} +1 -1
  25. package/chunk-AOKWJZ5N.js +4884 -0
  26. package/{chunk-JRKKFRAV.js → chunk-AWY2AFHN.js} +9 -5
  27. package/{chunk-RL776AGR.js → chunk-BB2PII22.js} +1 -1
  28. package/{chunk-I6XMPTMR.js → chunk-BFDWXLFF.js} +2 -2
  29. package/{chunk-VVX233PH.js → chunk-BT37DVDA.js} +9 -9
  30. package/chunk-BYXBJQAS.js +0 -0
  31. package/{chunk-C3RUNRHT.js → chunk-D55DXHXL.js} +1 -1
  32. package/{chunk-7DAJ4AI4.js → chunk-DSNLHTP3.js} +2 -2
  33. package/{chunk-SDJDLO5W.js → chunk-EUN3SYY7.js} +5 -5
  34. package/{chunk-FSO5B7GH.js → chunk-HAC6GPRE.js} +2 -2
  35. package/{chunk-CKOJQDKR.js → chunk-JEMATI63.js} +1 -1
  36. package/{chunk-7U44LYTR.js → chunk-JTINRTBT.js} +1 -1
  37. package/{chunk-YPRZSPF3.js → chunk-KLOCUWKZ.js} +1 -1
  38. package/{chunk-4O3CARJ4.js → chunk-KTHLAJEY.js} +1 -1
  39. package/{chunk-URUUZLPA.js → chunk-L3KWEH3V.js} +8 -8
  40. package/{chunk-O2ZNTTET.js → chunk-LBUTKV7S.js} +21 -12
  41. package/{chunk-GU3PEVGZ.js → chunk-LFFATN2M.js} +2632 -1578
  42. package/{chunk-UB6SN4NJ.js → chunk-LJCH34R2.js} +6 -6
  43. package/{chunk-5EFXE3O7.js → chunk-LTH6AVG7.js} +3 -3
  44. package/{chunk-7GNGZRLZ.js → chunk-LW6FJFCT.js} +45 -67
  45. package/{chunk-7KCUSYT2.js → chunk-MIQOUMSN.js} +7 -7
  46. package/{chunk-FVYY6MCS.js → chunk-O7VS7JLJ.js} +17 -17
  47. package/{chunk-RCSJFQPB.js → chunk-P7GAHW32.js} +361 -90
  48. package/{chunk-AL2KDGR2.js → chunk-PTT6KSYQ.js} +134 -84
  49. package/{chunk-4IJYA27C.js → chunk-PXZAAB4L.js} +4 -4
  50. package/{chunk-4XENYTF5.js → chunk-Q2WC4KGQ.js} +3 -3
  51. package/{chunk-4QEWT7KD.js → chunk-RBB43B5W.js} +367 -85
  52. package/chunk-RBCENBG7.js +36 -0
  53. package/{chunk-IWX4UW2E.js → chunk-RBCNBU2A.js} +88 -8
  54. package/{chunk-25LCXTML.js → chunk-RQPZX6KP.js} +2 -2
  55. package/{chunk-6KHNO3SK.js → chunk-RYMUT5JO.js} +23 -23
  56. package/{chunk-VX3SXJ3N.js → chunk-UBSKX3LP.js} +6 -6
  57. package/{chunk-4ZDM73SD.js → chunk-V2J635L5.js} +1 -1
  58. package/{chunk-DSZUWUYB.js → chunk-VBKJTOAW.js} +1 -1
  59. package/{chunk-XBUBEFNX.js → chunk-WESWWEVA.js} +1 -1
  60. package/{chunk-2ECQG4YX.js → chunk-ZAUDEKML.js} +253 -159
  61. package/{chunk-N54XAP77.js → chunk-ZJS64PZJ.js} +1 -1
  62. package/{createAgentAutomationAction-RJF3N2QY.js → createAgentAutomationAction-DYQOGAVE.js} +25 -24
  63. package/{createDialogAction-DRSPS6CE.js → createDialogAction-ETB3KQQE.js} +25 -24
  64. package/{createPageAction-6B2WMNO3.js → createPageAction-UF2RHA63.js} +25 -24
  65. package/{dbSlice-Q3TM2FJV.js → dbSlice-R5EJKZBW.js} +7 -7
  66. package/{deleteFile-OW53A6BX.js → deleteFile-WPWVZE4B.js} +5 -5
  67. package/{dialogCommands-4IX4XIZE.js → dialogCommands-LYYC7XHF.js} +23 -22
  68. package/{dialogSlice-3M7KX2TX.js → dialogSlice-IFBZ4IT2.js} +24 -23
  69. package/{docCreateCommands-SIL3NPGT.js → docCreateCommands-I66OI374.js} +22 -21
  70. package/{docDeleteCommands-7IOMLUS4.js → docDeleteCommands-OVRBCHMF.js} +23 -22
  71. package/{docReadCommands-FNFXUA5L.js → docReadCommands-YLWUMEH7.js} +22 -21
  72. package/{docStore-SV7E34D4.js → docStore-65WO7U36.js} +24 -23
  73. package/{docUpdateCommands-X2HNDVUC.js → docUpdateCommands-NSICS4IN.js} +22 -21
  74. package/fetchMessages-KTNM7QAR.js +1 -1
  75. package/{getPricing-3E6UNPKL.js → getPricing-7PUT44ZS.js} +7 -3
  76. package/{handleSendMessageAction-JYETO5RZ.js → handleSendMessageAction-T76HEDOP.js} +29 -28
  77. package/index.js +74 -74
  78. package/{localDialogRead-2VRI24F4.js → localDialogRead-YSKFFRTT.js} +1 -1
  79. package/{machineCommands-RIO3RP5Q.js → machineCommands-4HQY6UVZ.js} +57 -55
  80. package/{machineWsRunDispatch-W7UYLGB5.js → machineWsRunDispatch-7YW2M4FS.js} +49 -47
  81. package/{memoryCommands-O4MIPIWQ.js → memoryCommands-HG4WKTU7.js} +2 -2
  82. package/{models-4OPOOLFS.js → models-MFXNI3TF.js} +2 -2
  83. package/package.json +1 -1
  84. package/{read-GW7ZEI23.js → read-5ZMY7FKP.js} +5 -5
  85. package/{readDocTool-HUFU6OCT.js → readDocTool-2NXDK32S.js} +1 -1
  86. package/{readlineWorkspace-27JR7WPW.js → readlineWorkspace-FLQWOAUR.js} +759 -604
  87. package/{removeDialogAgentAction-CXKR4NJI.js → removeDialogAgentAction-KOLQ2R5W.js} +13 -12
  88. package/{runAgentClientLoop-HZFAPJHS.js → runAgentClientLoop-IUV2TR3X.js} +43 -42
  89. package/{runtimeDoctorCommands-LRHLPDRC.js → runtimeDoctorCommands-UWR5UDSM.js} +5 -5
  90. package/{setDialogExtraReferencesAction-6RKUSXHX.js → setDialogExtraReferencesAction-OMTEO7X6.js} +10 -10
  91. package/{setPrimaryDialogAgentAction-T3UTBEFG.js → setPrimaryDialogAgentAction-DOCIS6V4.js} +13 -12
  92. package/{settingSlice-IVKXJXMG.js → settingSlice-UWZJYDOA.js} +8 -8
  93. package/{spaceCommands-E7VOF4LO.js → spaceCommands-BDDAT4VU.js} +29 -28
  94. package/{spaceSlice-TSVROA5U.js → spaceSlice-HH633ZA4.js} +23 -22
  95. package/{streamAgentChatTurn-3C5RQZJF.js → streamAgentChatTurn-UBZOVFKV.js} +95 -72
  96. package/{tableCommands-O7O2LBEG.js → tableCommands-M3DJUETS.js} +10 -10
  97. package/{toolApiClient-QI3YBNWB.js → toolApiClient-C7P7YSE4.js} +2 -2
  98. package/{tools-EQDEKR6N.js → tools-OQZ34KCU.js} +31 -30
  99. package/{tuiSummaryLlmCaller-RV3THLZF.js → tuiSummaryLlmCaller-42AEL3LL.js} +8 -6
  100. package/{updateCommands-VOSPKXFF.js → updateCommands-TC5SX42Y.js} +3 -3
  101. package/{updateDialogTitleAction-3XV7VWSZ.js → updateDialogTitleAction-A3OOMSDO.js} +27 -26
  102. package/chunk-BBYVOSU2.js +0 -792
  103. package/chunk-DCOA4QSN.js +0 -105
  104. package/{chunk-DZ3XJVET.js → chunk-3QAF2LTL.js} +3 -3
  105. package/{chunk-EHLHSX7R.js → chunk-5MMZUWSG.js} +3 -3
  106. package/{chunk-ISNCLGUZ.js → chunk-AVMJVOQY.js} +3 -3
  107. package/{chunk-UTLZINAP.js → chunk-DVRHHFEA.js} +10 -10
  108. package/{chunk-4CQLVGRV.js → chunk-ID4G2MAR.js} +3 -3
  109. package/{chunk-5MIDPSSK.js → chunk-JK7VW2FN.js} +3 -3
  110. package/{chunk-TILFE6LV.js → chunk-YOCHZD7D.js} +3 -3
  111. package/{db-HCJ5PRB5.js → db-6QED3ZVO.js} +3 -3
  112. package/{understanding-3CUQQ6SV.js → understanding-ZOESBLF3.js} +3 -3
@@ -3,113 +3,147 @@ import {
3
3
  normalizeDialogRecord,
4
4
  readDialogSnapshot,
5
5
  sortDialogs
6
- } from "./chunk-FVYY6MCS.js";
6
+ } from "./chunk-O7VS7JLJ.js";
7
7
  import {
8
+ ANSI_ESCAPE_REGEX,
8
9
  CLI_AUTO_TIER_AGENT_KEY_TABLE,
9
10
  CLI_IMAGE_AGENT_KEY,
11
+ COLLAPSED_PASTE_PLACEHOLDER_RE,
10
12
  THEME_PALETTES,
13
+ allocateCollapsedPaste,
14
+ applyTerminalOutputToText,
11
15
  buildSkillContextBlocks,
12
16
  classifyCliAutoRoute,
17
+ clearCollapsedPasteStore,
18
+ countPhysicalLines,
19
+ createCollapsedPasteStore,
13
20
  dimCliText,
21
+ displayWidth,
22
+ expandRangeToCollapsedPasteChips,
23
+ findCollapsedPasteSpanAt,
24
+ fitAnsiLine,
14
25
  formatAssistantDisplay,
15
26
  formatTokenCount,
16
27
  getActiveBrightness,
17
28
  getActiveDensity,
18
29
  getActiveThemeName,
19
- getCliLocale,
20
- highlightMarkdown,
21
30
  initCliLocale,
31
+ isBalanceExhaustedError,
22
32
  isQuotaExhaustedError,
23
33
  normalizeThinkingDisplayMode,
24
34
  normalizeToolDisplayMode,
35
+ padOrTruncateToWidth,
25
36
  parseCliLocale,
37
+ releaseCollapsedPaste,
38
+ releaseCollapsedPasteReferences,
26
39
  renderTokenStatus,
40
+ replaceCollapsedPastesWithReferences,
41
+ resolveAgentContextWindow,
27
42
  resolveCliColorEnabled,
28
43
  resolveSkillReference,
29
44
  resolveTuiBrightness,
30
45
  runAgentTurn,
31
46
  setActiveBrightness,
32
47
  setActiveDensity,
48
+ setActiveTerminalBaseHex,
33
49
  setActiveThemeName,
34
50
  setCliLocale,
51
+ shouldCollapsePaste,
52
+ stripAnsi,
35
53
  surfaceBackgroundSequence,
36
54
  t,
55
+ takeDisplayWidth,
37
56
  themeColorSequence,
38
- themeText
39
- } from "./chunk-GU3PEVGZ.js";
57
+ themeText,
58
+ truncateAnsi,
59
+ visibleWidth,
60
+ wrapTextToLines,
61
+ wrapTranscriptLine
62
+ } from "./chunk-LFFATN2M.js";
40
63
  import "./chunk-6HYVJV7B.js";
41
- import "./chunk-2FTTDCD4.js";
42
64
  import {
43
65
  listFavoriteAgentIdsAcrossServers,
44
66
  listLocalCachedAgents,
45
67
  listRemoteAgents,
46
68
  listRemoteAgentsAcrossServers
47
- } from "./chunk-7DAJ4AI4.js";
48
- import "./chunk-4CQLVGRV.js";
69
+ } from "./chunk-DSNLHTP3.js";
70
+ import "./chunk-ID4G2MAR.js";
49
71
  import {
50
72
  listUserRecordsFromServers
51
- } from "./chunk-RL776AGR.js";
52
- import "./chunk-DZ3XJVET.js";
53
- import "./chunk-RCSJFQPB.js";
54
- import "./chunk-EHLHSX7R.js";
73
+ } from "./chunk-BB2PII22.js";
74
+ import "./chunk-3QAF2LTL.js";
75
+ import {
76
+ createCliLocalRuntimeAdapter
77
+ } from "./chunk-P7GAHW32.js";
78
+ import "./chunk-5MMZUWSG.js";
79
+ import "./chunk-CMKUBIGW.js";
80
+ import "./chunk-JBTJAPUF.js";
55
81
  import {
56
82
  getReadableCliDb
57
83
  } from "./chunk-W4NVOSFF.js";
58
84
  import {
59
85
  queryUserRecords,
60
86
  readDbRecord
61
- } from "./chunk-SDJDLO5W.js";
62
- import "./chunk-N54XAP77.js";
87
+ } from "./chunk-EUN3SYY7.js";
88
+ import "./chunk-ZJS64PZJ.js";
63
89
  import {
64
90
  resolveCliAgentKeyInput
65
91
  } from "./chunk-VHBWHNVT.js";
66
92
  import "./chunk-LTRXGFMS.js";
67
- import "./chunk-4O3CARJ4.js";
68
- import "./chunk-CMKUBIGW.js";
69
- import "./chunk-JBTJAPUF.js";
93
+ import "./chunk-KTHLAJEY.js";
70
94
  import "./chunk-ATNTHIZI.js";
71
95
  import "./chunk-JEXVIMYZ.js";
72
- import "./chunk-FSO5B7GH.js";
73
- import "./chunk-C3RUNRHT.js";
74
- import "./chunk-AL2KDGR2.js";
96
+ import {
97
+ prepareTools
98
+ } from "./chunk-HAC6GPRE.js";
99
+ import "./chunk-D55DXHXL.js";
100
+ import {
101
+ expandEnabledPacks
102
+ } from "./chunk-PTT6KSYQ.js";
75
103
  import "./chunk-GAKEBQD6.js";
76
104
  import "./chunk-KQHGZWSV.js";
77
- import "./chunk-AS4PVWA4.js";
105
+ import "./chunk-2CVZSC5L.js";
78
106
  import "./chunk-3LY4F7SV.js";
79
107
  import "./chunk-VP4WJWKW.js";
80
108
  import "./chunk-63W5N6P3.js";
81
109
  import "./chunk-VF4K2QE6.js";
82
- import "./chunk-UB6SN4NJ.js";
83
- import "./chunk-ENOG22KJ.js";
110
+ import "./chunk-LJCH34R2.js";
111
+ import "./chunk-A4MYG3TR.js";
84
112
  import "./chunk-VC6OZXO5.js";
85
113
  import "./chunk-OWOHNGCN.js";
86
- import "./chunk-25LCXTML.js";
87
- import "./chunk-HNW7IJSK.js";
88
- import "./chunk-XENYHRUE.js";
89
114
  import {
90
115
  DEFAULT_CONTEXT_WINDOW,
116
+ estimateTokenCount,
91
117
  extractReferenceKeysFromMessage,
92
118
  getModelContextWindow,
93
119
  planCompression,
94
120
  serializeMessageContent
95
- } from "./chunk-2ECQG4YX.js";
121
+ } from "./chunk-ZAUDEKML.js";
96
122
  import {
97
123
  buildBuiltinSummaryContent
98
- } from "./chunk-4ZDM73SD.js";
124
+ } from "./chunk-V2J635L5.js";
99
125
  import "./chunk-MRC4Q34M.js";
100
126
  import "./chunk-MTU75CZ2.js";
101
127
  import "./chunk-CWMSB67P.js";
102
- import "./chunk-VUW5FBDB.js";
103
- import "./chunk-5EFXE3O7.js";
128
+ import "./chunk-4VA3UQRF.js";
129
+ import "./chunk-LTH6AVG7.js";
104
130
  import "./chunk-Z4NR32XR.js";
105
131
  import "./chunk-M76ECQRD.js";
132
+ import "./chunk-RQPZX6KP.js";
133
+ import "./chunk-UBSKX3LP.js";
134
+ import "./chunk-Y5GCAMGP.js";
106
135
  import "./chunk-SOTZ6RDN.js";
107
- import "./chunk-I6XMPTMR.js";
136
+ import "./chunk-BFDWXLFF.js";
108
137
  import "./chunk-UAD2WT54.js";
109
- import "./chunk-DCOA4QSN.js";
138
+ import "./chunk-L3KWEH3V.js";
139
+ import "./chunk-AZPCASRE.js";
140
+ import "./chunk-RBCENBG7.js";
141
+ import "./chunk-HNW7IJSK.js";
142
+ import "./chunk-XENYHRUE.js";
143
+ import "./chunk-JTINRTBT.js";
110
144
  import {
111
145
  runSelfUpdate
112
- } from "./chunk-CKOJQDKR.js";
146
+ } from "./chunk-JEMATI63.js";
113
147
  import {
114
148
  saveProfileAgentSelection,
115
149
  saveProfileLocale
@@ -118,15 +152,6 @@ import {
118
152
  readPipeText,
119
153
  spawnProcess
120
154
  } from "./chunk-IDZTNRP2.js";
121
- import {
122
- parseUserIdFromAuthToken,
123
- resolveAuthToken,
124
- resolveServerCandidates,
125
- resolveServerUrl
126
- } from "./chunk-ISNCLGUZ.js";
127
- import {
128
- DEFAULT_NOLO_SERVER_URL
129
- } from "./chunk-OLZBQWZU.js";
130
155
  import {
131
156
  buildSkillDiscoveryContextBlock
132
157
  } from "./chunk-AFON4QUU.js";
@@ -134,71 +159,158 @@ import "./chunk-C4FTUXVF.js";
134
159
  import "./chunk-KKY4B2Q2.js";
135
160
  import "./chunk-WZSRQNQG.js";
136
161
  import {
162
+ buildLocalWorkspaceOpenAiTools,
163
+ buildLocalWorkspaceToolset,
137
164
  getProcessRegistry
138
- } from "./chunk-O2ZNTTET.js";
139
- import "./chunk-5KLGBAAR.js";
165
+ } from "./chunk-LBUTKV7S.js";
166
+ import "./chunk-6UUD2WES.js";
140
167
  import "./chunk-ZNFJWEN4.js";
141
- import "./chunk-TILFE6LV.js";
168
+ import "./chunk-YOCHZD7D.js";
142
169
  import {
143
170
  readCommandActionGatePayload,
144
171
  resolveAgentImageInputSupport
145
- } from "./chunk-4QEWT7KD.js";
172
+ } from "./chunk-RBB43B5W.js";
146
173
  import "./chunk-OPZYGHUC.js";
147
- import "./chunk-AGFH73SK.js";
148
- import "./chunk-JRKKFRAV.js";
149
- import "./chunk-P3PKED2I.js";
174
+ import {
175
+ buildCurrentTimeBlock,
176
+ buildIdentityBlock,
177
+ buildRuntimeGuidanceBlocks
178
+ } from "./chunk-6KRA6AWI.js";
179
+ import "./chunk-AWY2AFHN.js";
180
+ import {
181
+ canonicalizeToolNames
182
+ } from "./chunk-6OHYC4BY.js";
150
183
  import {
151
184
  clipCompactText
152
185
  } from "./chunk-5MMAK75Q.js";
153
- import "./chunk-BBYVOSU2.js";
186
+ import "./chunk-AOKWJZ5N.js";
154
187
  import "./chunk-5CS33IBL.js";
155
188
  import "./chunk-JZPBVBIY.js";
156
- import "./chunk-IWX4UW2E.js";
157
- import "./chunk-5MIDPSSK.js";
189
+ import "./chunk-BYXBJQAS.js";
190
+ import "./chunk-KX6YBIHG.js";
191
+ import "./chunk-RBCNBU2A.js";
192
+ import "./chunk-O4BU24WZ.js";
193
+ import "./chunk-I42VC5KR.js";
194
+ import "./chunk-WWC7I6TA.js";
195
+ import "./chunk-JK7VW2FN.js";
158
196
  import {
159
197
  extractCustomId
160
198
  } from "./chunk-DFFIZ25G.js";
161
199
  import "./chunk-3ASDTTEI.js";
200
+ import {
201
+ asTrimmedLowercaseString
202
+ } from "./chunk-QSJ3HFEF.js";
162
203
  import {
163
204
  compactWhitespace
164
205
  } from "./chunk-DWLEOOGR.js";
206
+ import "./chunk-AMJ7LA5D.js";
207
+ import {
208
+ parseUserIdFromAuthToken,
209
+ resolveAuthToken,
210
+ resolveServerCandidates,
211
+ resolveServerUrl
212
+ } from "./chunk-AVMJVOQY.js";
213
+ import {
214
+ DEFAULT_NOLO_SERVER_URL
215
+ } from "./chunk-OLZBQWZU.js";
165
216
  import {
166
217
  toErrorMessage
167
218
  } from "./chunk-HNMXYYJR.js";
168
219
  import "./chunk-H33743XH.js";
169
220
  import "./chunk-LM6IYQ3F.js";
170
- import "./chunk-VX3SXJ3N.js";
171
- import "./chunk-Y5GCAMGP.js";
172
- import "./chunk-URUUZLPA.js";
173
- import "./chunk-AZPCASRE.js";
174
- import "./chunk-7U44LYTR.js";
175
- import "./chunk-KX6YBIHG.js";
176
- import "./chunk-O4BU24WZ.js";
177
- import "./chunk-I42VC5KR.js";
178
- import "./chunk-WWC7I6TA.js";
179
- import {
180
- asTrimmedLowercaseString
181
- } from "./chunk-QSJ3HFEF.js";
182
- import "./chunk-DSZUWUYB.js";
183
- import "./chunk-UTLZINAP.js";
221
+ import "./chunk-VBKJTOAW.js";
222
+ import "./chunk-DVRHHFEA.js";
184
223
  import "./chunk-OOSFSFMA.js";
185
224
  import "./chunk-GBRG75BQ.js";
186
- import "./chunk-4SN6J65J.js";
187
- import "./chunk-LCBAMY2M.js";
188
225
  import "./chunk-3EUW3WEO.js";
189
226
  import "./chunk-U6VC4MU4.js";
227
+ import "./chunk-KUG52IAP.js";
228
+ import "./chunk-LCBAMY2M.js";
229
+ import "./chunk-4SN6J65J.js";
190
230
  import "./chunk-CF7PE763.js";
191
231
  import {
192
232
  asOptionalTrimmedString
193
233
  } from "./chunk-G3SUCT4W.js";
194
- import "./chunk-KUG52IAP.js";
195
234
  import "./chunk-4VNS5WPM.js";
196
235
 
197
236
  // packages/cli/tui/readlineWorkspace.ts
198
237
  import { createInterface } from "node:readline";
199
238
  import { stdin as defaultInput, stdout as defaultOutput } from "node:process";
200
- import { existsSync as existsSync2, readFileSync } from "node:fs";
239
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
240
+ import { join as join2 } from "node:path";
241
+
242
+ // packages/cli/client/estimateCliContext.ts
243
+ import { existsSync, readFileSync } from "node:fs";
201
244
  import { join } from "node:path";
245
+ var DEFAULT_CLI_PACKS = ["code", "agent-orchestration"];
246
+ var DEFAULT_CLI_PLATFORM_TOOLS = [
247
+ "ui_ask_choice",
248
+ "exa_search",
249
+ "fetchWebpage"
250
+ ];
251
+ var DEFAULT_FLASH_PROMPT = "\u4F60\u662F\u5171\u4EAB\u7A7A\u95F4\u91CC\u7684\u9AD8\u6027\u4EF7\u6BD4\u901A\u7528 AI \u52A9\u624B\u3002\u4F18\u5148\u5FEB\u901F\u3001\u76F4\u63A5\u3001\u7A33\u5B9A\u5730\u5B8C\u6210\u4EFB\u52A1\uFF1B\u9700\u8981\u63A8\u7406\u65F6\u4FDD\u6301\u6B65\u9AA4\u6E05\u6670\u3002";
252
+ function readAgentsMd(cwd) {
253
+ for (const name of ["AGENTS.md", "agents.md"]) {
254
+ const path = join(cwd, name);
255
+ if (!existsSync(path)) continue;
256
+ try {
257
+ return readFileSync(path, "utf8");
258
+ } catch {
259
+ return "";
260
+ }
261
+ }
262
+ return "";
263
+ }
264
+ function estimateToolSchemas(toolNames) {
265
+ const toolset = buildLocalWorkspaceToolset({
266
+ declaredToolNames: toolNames,
267
+ exposeShellTools: true
268
+ });
269
+ const workspaceTools = buildLocalWorkspaceOpenAiTools({
270
+ toolNames: toolset.toolNames,
271
+ exposeShellTools: true
272
+ });
273
+ const platformNames = DEFAULT_CLI_PLATFORM_TOOLS.filter(
274
+ (name) => toolNames.includes(name)
275
+ );
276
+ const platformTools = platformNames.length > 0 ? prepareTools([...platformNames]) : [];
277
+ return estimateTokenCount(JSON.stringify([...workspaceTools, ...platformTools]));
278
+ }
279
+ function estimateDefaultCliContextTokens(opts = {}) {
280
+ const cwd = opts.cwd?.trim() || process.cwd();
281
+ const model = opts.model?.trim() || "deepseek-v4-flash";
282
+ const agentName = opts.agentName?.trim() || "DeepSeek V4 Flash";
283
+ const agentKey = opts.agentKey?.trim() || "agent-pub-deepseek-v4-flash";
284
+ const prompt = opts.agentPrompt?.trim() || DEFAULT_FLASH_PROMPT;
285
+ const packTools = canonicalizeToolNames(
286
+ expandEnabledPacks([...DEFAULT_CLI_PACKS], [])
287
+ );
288
+ const toolNames = canonicalizeToolNames([
289
+ ...packTools,
290
+ ...DEFAULT_CLI_PLATFORM_TOOLS
291
+ ]);
292
+ const guidance = buildRuntimeGuidanceBlocks(toolNames);
293
+ const systemParts = [
294
+ prompt,
295
+ buildIdentityBlock({
296
+ agentName,
297
+ agentId: agentKey,
298
+ model
299
+ }),
300
+ guidance.startupProtocol,
301
+ guidance.contextLayerContract,
302
+ guidance.emailRegistrationWorkflow,
303
+ guidance.webResearchToolPolicy,
304
+ buildCurrentTimeBlock(/* @__PURE__ */ new Date()),
305
+ readAgentsMd(cwd),
306
+ buildSkillDiscoveryContextBlock(cwd) ?? ""
307
+ ];
308
+ const systemTokens = estimateTokenCount(
309
+ systemParts.filter((part) => part?.trim()).join("\n\n")
310
+ );
311
+ const toolTokens = estimateToolSchemas(toolNames);
312
+ return Math.max(0, systemTokens + toolTokens);
313
+ }
202
314
 
203
315
  // packages/cli/client/compactDialog.ts
204
316
  import { ulid } from "ulid";
@@ -479,6 +591,12 @@ function renderDialogRow(args, colorEnabled = resolveCliColorEnabled()) {
479
591
  function renderDialogOverflow(text, colorEnabled = resolveCliColorEnabled()) {
480
592
  return themeText(` ${text}`, "chrome", colorEnabled);
481
593
  }
594
+ function renderOverflowAbove(count, colorEnabled = resolveCliColorEnabled()) {
595
+ return renderDialogOverflow(t("dialogMoreAbove", String(count)), colorEnabled);
596
+ }
597
+ function renderOverflowBelow(count, colorEnabled = resolveCliColorEnabled()) {
598
+ return renderDialogOverflow(t("dialogMoreBelow", String(count)), colorEnabled);
599
+ }
482
600
  function renderDialogCommand(text, colorEnabled = resolveCliColorEnabled()) {
483
601
  return themeText(` ${text}`, "danger", colorEnabled);
484
602
  }
@@ -577,7 +695,7 @@ function renderSelectDialog(args) {
577
695
  ];
578
696
  const lines = [...titleLines, ""];
579
697
  if (window.start > 0) {
580
- lines.push(renderDialogOverflow(`\u2191 ${window.start} more`));
698
+ lines.push(renderOverflowAbove(window.start));
581
699
  }
582
700
  for (let index = window.start; index < window.end; index += 1) {
583
701
  const item = args.items[index];
@@ -590,7 +708,7 @@ function renderSelectDialog(args) {
590
708
  );
591
709
  }
592
710
  if (window.end < total) {
593
- lines.push("", renderDialogOverflow(`\u2193 ${total - window.end} more`));
711
+ lines.push("", renderOverflowBelow(total - window.end));
594
712
  }
595
713
  return lines.join("\n");
596
714
  }
@@ -819,7 +937,7 @@ async function runSelectDialog(args) {
819
937
  // packages/cli/tui/confirmDialog.ts
820
938
  var FALLBACK_TERMINAL_WIDTH = 80;
821
939
  var WIDE_CHAR = /[ᄀ-ᅟ⺀-〾ぁ-㏿㐀-䶿一-鿿ꀀ-꓏가-힣豈-﫿︰-﹯＀-⦆¢-₩]/;
822
- function displayWidth(text) {
940
+ function displayWidth2(text) {
823
941
  let width = 0;
824
942
  for (const char of text) width += WIDE_CHAR.test(char) ? 2 : 1;
825
943
  return width;
@@ -827,9 +945,9 @@ function displayWidth(text) {
827
945
  function truncateCommand(command, maxWidth) {
828
946
  const indent = 2;
829
947
  const budget = Math.max(10, maxWidth - indent);
830
- if (displayWidth(command) <= budget) return command;
948
+ if (displayWidth2(command) <= budget) return command;
831
949
  const marker = ` ${t("dialogConfirmCommandTruncated")}`;
832
- const keep = Math.max(1, budget - displayWidth(marker));
950
+ const keep = Math.max(1, budget - displayWidth2(marker));
833
951
  let kept = "";
834
952
  let width = 0;
835
953
  for (const char of command) {
@@ -1111,19 +1229,23 @@ function renderTabBar(questions, activeIndex, colorEnabled) {
1111
1229
  }
1112
1230
  return colorEnabled ? themeText(` ${label} `, "muted", colorEnabled) : ` ${label} `;
1113
1231
  });
1114
- const submitLabel = "Submit";
1232
+ const submitLabel = t("askChoiceSubmit");
1115
1233
  return tabs.join(" ") + " " + (colorEnabled ? themeText(submitLabel, "chrome", colorEnabled) : submitLabel);
1116
1234
  }
1117
- function renderFooter(colorEnabled) {
1118
- const hints = "\u21B5 pick/submit \xB7 space toggle \xB7 tab switch \xB7 esc cancel";
1235
+ function renderFooter(multiSelect, colorEnabled) {
1236
+ const hints = multiSelect ? t("askChoiceFooterMulti") : t("askChoiceFooterSingle");
1119
1237
  return colorEnabled ? themeText(` ${hints}`, "chrome", colorEnabled) : ` ${hints}`;
1120
1238
  }
1239
+ function otherRowPrefix(index) {
1240
+ return ` [${index + 1}] ${t("askChoiceOtherLabel")}: `;
1241
+ }
1121
1242
  function renderAskChoiceFrame(state) {
1122
1243
  const colorEnabled = resolveCliColorEnabled();
1123
1244
  const q = state.questions[state.activeIndex];
1124
1245
  const qs = state.questionStates[state.activeIndex];
1125
1246
  const lines = [];
1126
- lines.push(renderDialogTitle("question"));
1247
+ let otherCursor = null;
1248
+ lines.push(renderDialogTitle(t("askChoiceTitle")));
1127
1249
  lines.push("");
1128
1250
  if (state.questions.length > 1) {
1129
1251
  lines.push(renderTabBar(state.questions, state.activeIndex, colorEnabled));
@@ -1134,11 +1256,11 @@ function renderAskChoiceFrame(state) {
1134
1256
  );
1135
1257
  if (q.multiSelect) {
1136
1258
  lines.push(
1137
- colorEnabled ? themeText(" Space to toggle, Enter to confirm selection.", "muted", colorEnabled) : " Space to toggle, Enter to confirm selection."
1259
+ colorEnabled ? themeText(` ${t("askChoiceHintMulti")}`, "muted", colorEnabled) : ` ${t("askChoiceHintMulti")}`
1138
1260
  );
1139
1261
  } else {
1140
1262
  lines.push(
1141
- colorEnabled ? themeText(" Type your answer, then press Enter to save.", "muted", colorEnabled) : " Type your answer, then press Enter to save."
1263
+ colorEnabled ? themeText(` ${t("askChoiceHintSingle")}`, "muted", colorEnabled) : ` ${t("askChoiceHintSingle")}`
1142
1264
  );
1143
1265
  }
1144
1266
  lines.push("");
@@ -1148,9 +1270,7 @@ function renderAskChoiceFrame(state) {
1148
1270
  total: totalRows
1149
1271
  });
1150
1272
  if (window.start > 0) {
1151
- lines.push(
1152
- colorEnabled ? themeText(` \u2191 ${window.start} more`, "chrome", colorEnabled) : ` \u2191 ${window.start} more`
1153
- );
1273
+ lines.push(renderOverflowAbove(window.start));
1154
1274
  }
1155
1275
  for (let i = window.start; i < window.end; i++) {
1156
1276
  if (i < q.choices.length) {
@@ -1168,25 +1288,29 @@ function renderAskChoiceFrame(state) {
1168
1288
  } else {
1169
1289
  const focused = qs.cursorIndex === i;
1170
1290
  const marker = focused ? DIALOG_CURSOR : " ";
1171
- const otherContent = qs.otherFocused ? `${qs.otherText}\u2588` : qs.otherText || "";
1172
- const row = `${marker} [${i + 1}] Other: ${otherContent}`;
1291
+ const plainPrefix = `${marker}${otherRowPrefix(i)}`;
1292
+ const plainRow = `${plainPrefix}${qs.otherText}`;
1173
1293
  if (focused && colorEnabled) {
1174
1294
  lines.push(
1175
- `\x1B[1m${themeColorSequence("accent")}${row}\x1B[0m`
1295
+ `\x1B[1m${themeColorSequence("accent")}${plainRow}\x1B[0m`
1176
1296
  );
1177
1297
  } else {
1178
- lines.push(row);
1298
+ lines.push(plainRow);
1299
+ }
1300
+ if (qs.otherFocused) {
1301
+ otherCursor = {
1302
+ lineIndex: lines.length - 1,
1303
+ col: displayWidth(plainPrefix + qs.otherText)
1304
+ };
1179
1305
  }
1180
1306
  }
1181
1307
  }
1182
1308
  if (window.end < totalRows) {
1183
- lines.push(
1184
- colorEnabled ? themeText(` \u2193 ${totalRows - window.end} more`, "chrome", colorEnabled) : ` \u2193 ${totalRows - window.end} more`
1185
- );
1309
+ lines.push(renderOverflowBelow(totalRows - window.end));
1186
1310
  }
1187
1311
  lines.push("");
1188
- lines.push(renderFooter(colorEnabled));
1189
- return lines.join("\n");
1312
+ lines.push(renderFooter(q.multiSelect, colorEnabled));
1313
+ return { text: lines.join("\n"), otherCursor };
1190
1314
  }
1191
1315
  async function runAskChoiceDialog(args) {
1192
1316
  const { request } = args;
@@ -1199,9 +1323,6 @@ async function runAskChoiceDialog(args) {
1199
1323
  if (normalized.questions.length === 0) {
1200
1324
  return { kind: "cancelled" };
1201
1325
  }
1202
- const q0 = normalized.questions[0];
1203
- if (normalized.questions.length === 1 && !q0.multiSelect && !q0.allowOther) {
1204
- }
1205
1326
  let state = createInitialAskChoiceState(normalized.questions);
1206
1327
  const output = args.output ?? process.stdout;
1207
1328
  const input = args.input ?? process.stdin;
@@ -1215,9 +1336,15 @@ async function runAskChoiceDialog(args) {
1215
1336
  typeof args.bottomRow === "function" ? args.bottomRow() : args.bottomRow ?? 0
1216
1337
  );
1217
1338
  let lastBottomRow = 0;
1339
+ let unanchoredCursorLift = 0;
1340
+ const restoreUnanchoredCursor = () => {
1341
+ if (unanchoredCursorLift <= 0) return;
1342
+ output.write(`\x1B[${unanchoredCursorLift}B`);
1343
+ unanchoredCursorLift = 0;
1344
+ };
1218
1345
  const paint = () => {
1219
1346
  const frame = renderAskChoiceFrame(state);
1220
- const lines = frame.split("\n");
1347
+ const lines = frame.text.split("\n");
1221
1348
  const lineCount = lines.length;
1222
1349
  const canPosition = outputIsTty(output) && typeof output.write === "function";
1223
1350
  if (bottomAnchored && canPosition) {
@@ -1234,22 +1361,37 @@ async function runAskChoiceDialog(args) {
1234
1361
  }
1235
1362
  lastBottomRow = anchorRow;
1236
1363
  renderedLineCount = lineCount;
1364
+ unanchoredCursorLift = 0;
1365
+ if (frame.otherCursor) {
1366
+ const cursorRow = anchorRow - (lineCount - 1 - frame.otherCursor.lineIndex);
1367
+ if (cursorRow >= 1) {
1368
+ output.write(`\x1B[${cursorRow};${frame.otherCursor.col + 1}H`);
1369
+ }
1370
+ }
1237
1371
  return;
1238
1372
  }
1239
1373
  if (canPosition) {
1374
+ restoreUnanchoredCursor();
1240
1375
  for (let i = 0; i < renderedLineCount; i++) {
1241
1376
  output.write("\x1B[1A\x1B[2K");
1242
1377
  }
1243
- output.write(`${frame}
1378
+ output.write(`${frame.text}
1244
1379
  `);
1245
1380
  renderedLineCount = lineCount;
1381
+ if (frame.otherCursor) {
1382
+ const linesFromBottom = lineCount - frame.otherCursor.lineIndex;
1383
+ output.write(`\x1B[${linesFromBottom}A`);
1384
+ output.write(`\x1B[${frame.otherCursor.col + 1}G`);
1385
+ unanchoredCursorLift = linesFromBottom;
1386
+ }
1246
1387
  return;
1247
1388
  }
1248
1389
  if (typeof output.write === "function") {
1249
- output.write(`${frame}
1390
+ output.write(`${frame.text}
1250
1391
  `);
1251
1392
  }
1252
1393
  renderedLineCount = lineCount;
1394
+ unanchoredCursorLift = 0;
1253
1395
  };
1254
1396
  const resizeTarget = output;
1255
1397
  const onOutputResize = () => paint();
@@ -1277,6 +1419,9 @@ async function runAskChoiceDialog(args) {
1277
1419
  continue;
1278
1420
  }
1279
1421
  let action = null;
1422
+ const qs = state.questionStates[state.activeIndex];
1423
+ const q = state.questions[state.activeIndex];
1424
+ const isOtherRow = qs.cursorIndex >= q.choices.length;
1280
1425
  if (isCancel(sequence)) {
1281
1426
  action = { type: "CANCEL" };
1282
1427
  } else if (sequence === CSI_TAB) {
@@ -1288,11 +1433,17 @@ async function runAskChoiceDialog(args) {
1288
1433
  } else if (isArrowDown(sequence)) {
1289
1434
  action = { type: "MOVE_CURSOR", delta: 1 };
1290
1435
  } else if (sequence === CSI_SPACE) {
1291
- action = { type: "TOGGLE_AT_CURSOR" };
1436
+ if (qs.otherFocused) {
1437
+ action = {
1438
+ type: "SET_OTHER_TEXT",
1439
+ text: qs.otherText + " "
1440
+ };
1441
+ } else if (q.multiSelect) {
1442
+ action = { type: "TOGGLE_AT_CURSOR" };
1443
+ } else if (isOtherRow) {
1444
+ action = { type: "FOCUS_OTHER" };
1445
+ }
1292
1446
  } else if (isSubmit(sequence)) {
1293
- const qs = state.questionStates[state.activeIndex];
1294
- const q = state.questions[state.activeIndex];
1295
- const isOtherRow = qs.cursorIndex >= q.choices.length;
1296
1447
  if (qs.otherFocused) {
1297
1448
  action = { type: "BLUR_OTHER" };
1298
1449
  } else if (isOtherRow && !qs.otherFocused) {
@@ -1303,27 +1454,29 @@ async function runAskChoiceDialog(args) {
1303
1454
  action = { type: "SELECT_AT_CURSOR" };
1304
1455
  }
1305
1456
  } else if (sequence === CSI_BACKSPACE || sequence === CSI_BACKSPACE_ALT) {
1306
- const qs = state.questionStates[state.activeIndex];
1307
1457
  if (qs.otherFocused && qs.otherText.length > 0) {
1458
+ const chars = Array.from(qs.otherText);
1308
1459
  action = {
1309
1460
  type: "SET_OTHER_TEXT",
1310
- text: qs.otherText.slice(0, -1)
1461
+ text: chars.slice(0, -1).join("")
1311
1462
  };
1312
1463
  }
1313
1464
  } else if (sequence.length >= 1 && sequence.charCodeAt(0) >= 32 && !sequence.startsWith("\x1B")) {
1314
- const qs = state.questionStates[state.activeIndex];
1315
- if (qs.otherFocused) {
1465
+ if (qs.otherFocused || isOtherRow && q.allowOther) {
1316
1466
  const cleaned = sequence.replace(/[\x00-\x1f\x7f]/g, "");
1317
1467
  if (cleaned) {
1468
+ if (!qs.otherFocused) {
1469
+ state = askChoiceReducer(state, { type: "FOCUS_OTHER" });
1470
+ }
1471
+ const currentText = state.questionStates[state.activeIndex].otherText;
1318
1472
  action = {
1319
1473
  type: "SET_OTHER_TEXT",
1320
- text: qs.otherText + cleaned
1474
+ text: currentText + cleaned
1321
1475
  };
1322
1476
  }
1323
1477
  }
1324
1478
  }
1325
1479
  if (action) {
1326
- const prev = state;
1327
1480
  state = askChoiceReducer(state, action);
1328
1481
  if (state.phase !== "active") break;
1329
1482
  if (action.type === "BLUR_OTHER" && state.activeIndex >= state.questions.length - 1 && canSubmit(state)) {
@@ -1347,6 +1500,7 @@ async function runAskChoiceDialog(args) {
1347
1500
  renderedLineCount
1348
1501
  );
1349
1502
  } else {
1503
+ restoreUnanchoredCursor();
1350
1504
  for (let i = 0; i < renderedLineCount; i++) {
1351
1505
  output.write("\x1B[1A\x1B[2K");
1352
1506
  }
@@ -1360,13 +1514,13 @@ async function runAskChoiceDialog(args) {
1360
1514
  }
1361
1515
  if (result.answers.length === 1) {
1362
1516
  const a = result.answers[0];
1517
+ const q = normalized.questions[0];
1518
+ const labels = a.selectedIds.map((id) => q.choices.find((c) => c.id === id)?.label ?? "").filter(Boolean);
1519
+ if (a.otherText) labels.push(a.otherText);
1363
1520
  return {
1364
1521
  kind: "selected",
1365
1522
  userMessage: a.userMessage,
1366
- label: a.selectedIds.map((id) => {
1367
- const q = normalized.questions[0];
1368
- return q.choices.find((c) => c.id === id)?.label ?? "";
1369
- }).join(", ") || a.otherText || ""
1523
+ label: labels.join(", ") || a.otherText || ""
1370
1524
  };
1371
1525
  }
1372
1526
  return {
@@ -1424,8 +1578,13 @@ function createActivityIndicator(deps) {
1424
1578
  let lastActivityAt = 0;
1425
1579
  let frameIndex = 0;
1426
1580
  let timer = null;
1581
+ let stopping = false;
1427
1582
  const elapsedSecFrom = (startedAt) => startedAt > 0 ? Math.max(0, Math.floor((now() - startedAt) / 1e3)) : 0;
1428
1583
  const tick = () => {
1584
+ if (stopping) {
1585
+ deps.onRepaint();
1586
+ return;
1587
+ }
1429
1588
  frameIndex += 1;
1430
1589
  if (explicitLabel === null && !fallbackActive && deps.isTurnActive() && lastActivityAt > 0 && now() - lastActivityAt >= fallbackDelayMs) {
1431
1590
  fallbackActive = true;
@@ -1454,9 +1613,21 @@ function createActivityIndicator(deps) {
1454
1613
  ensureTimer();
1455
1614
  deps.onRepaint();
1456
1615
  };
1616
+ const markStopping = () => {
1617
+ stopping = true;
1618
+ deps.onRepaint();
1619
+ };
1620
+ const isStopping = () => stopping;
1457
1621
  const getView = () => {
1458
1622
  if (!deps.isTurnActive()) return null;
1459
1623
  const frame = ACTIVITY_FRAMES[frameIndex % ACTIVITY_FRAMES.length];
1624
+ if (stopping) {
1625
+ return {
1626
+ frame,
1627
+ label: deps.stoppingLabel(),
1628
+ elapsedSec: 0
1629
+ };
1630
+ }
1460
1631
  if (explicitLabel !== null) {
1461
1632
  return {
1462
1633
  frame,
@@ -1483,8 +1654,9 @@ function createActivityIndicator(deps) {
1483
1654
  fallbackActive = false;
1484
1655
  fallbackStartedAt = 0;
1485
1656
  lastActivityAt = 0;
1657
+ stopping = false;
1486
1658
  };
1487
- return { report, getView, stop };
1659
+ return { report, getView, markStopping, isStopping, stop };
1488
1660
  }
1489
1661
 
1490
1662
  // packages/ai/agent/utils/sortUtils.ts
@@ -1724,13 +1896,15 @@ function findAgentCatalogEntry(entries, rawTarget) {
1724
1896
  if (!target) return null;
1725
1897
  if (/^\d+$/.test(target)) {
1726
1898
  const entry = entries[Number(target) - 1];
1727
- return entry ? { name: entry.name, key: entry.key } : null;
1899
+ return entry ? { name: entry.name, key: entry.key, model: entry.model } : null;
1728
1900
  }
1729
1901
  const lower = target.toLowerCase();
1730
1902
  const byName = entries.find(
1731
1903
  (entry) => entry.name.toLowerCase() === lower || entry.key.toLowerCase() === lower || entry.key.toLowerCase().endsWith(`-${lower}`)
1732
1904
  );
1733
- if (byName) return { name: byName.name, key: byName.key };
1905
+ if (byName) {
1906
+ return { name: byName.name, key: byName.key, model: byName.model };
1907
+ }
1734
1908
  if (target.startsWith("agent-") || target.startsWith("agent-pub-")) {
1735
1909
  return { name: target, key: target };
1736
1910
  }
@@ -1789,6 +1963,7 @@ async function runAgentPicker(args) {
1789
1963
  kind: "selected",
1790
1964
  name: selected.name,
1791
1965
  key: selected.key,
1966
+ model: selected.model,
1792
1967
  entries
1793
1968
  };
1794
1969
  }
@@ -1798,7 +1973,8 @@ function resolveAgentSwitchTarget(rawTarget, catalogEntries = []) {
1798
1973
  const aliasEntry = catalogEntries.find((entry) => entry.key === resolvedKey);
1799
1974
  return {
1800
1975
  name: aliasEntry?.name ?? asTrimmedLowercaseString(rawTarget),
1801
- key: resolvedKey
1976
+ key: resolvedKey,
1977
+ ...aliasEntry?.model ? { model: aliasEntry.model } : {}
1802
1978
  };
1803
1979
  }
1804
1980
  return findAgentCatalogEntry(catalogEntries, rawTarget);
@@ -1811,10 +1987,10 @@ function formatDialogTimestamp(value, now = Date.now()) {
1811
1987
  const time = typeof value === "number" ? value : Date.parse(value);
1812
1988
  if (!Number.isFinite(time) || time <= 0) return "";
1813
1989
  const deltaSeconds = Math.max(0, Math.floor((now - time) / 1e3));
1814
- if (deltaSeconds < 60) return "just now";
1815
- if (deltaSeconds < 3600) return `${Math.floor(deltaSeconds / 60)}m ago`;
1816
- if (deltaSeconds < 86400) return `${Math.floor(deltaSeconds / 3600)}h ago`;
1817
- if (deltaSeconds < 30 * 86400) return `${Math.floor(deltaSeconds / 86400)}d ago`;
1990
+ if (deltaSeconds < 60) return t("timeJustNow");
1991
+ if (deltaSeconds < 3600) return t("timeMinutesAgo", String(Math.floor(deltaSeconds / 60)));
1992
+ if (deltaSeconds < 86400) return t("timeHoursAgo", String(Math.floor(deltaSeconds / 3600)));
1993
+ if (deltaSeconds < 30 * 86400) return t("timeDaysAgo", String(Math.floor(deltaSeconds / 86400)));
1818
1994
  const date = new Date(time);
1819
1995
  const pad = (part) => String(part).padStart(2, "0");
1820
1996
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
@@ -1831,7 +2007,7 @@ function toDialogPickerItems(dialogs) {
1831
2007
  }
1832
2008
  function renderDialogList(dialogs) {
1833
2009
  if (dialogs.length === 0) return t("noDialogsYet");
1834
- const lines = ["Recent dialogs:"];
2010
+ const lines = [t("recentDialogs")];
1835
2011
  for (const [index, dialog] of dialogs.entries()) {
1836
2012
  const stamp = formatDialogTimestamp(dialog.updatedAt ?? dialog.createdAt);
1837
2013
  lines.push(
@@ -1839,7 +2015,7 @@ function renderDialogList(dialogs) {
1839
2015
  ` id=${dialog.id}`
1840
2016
  );
1841
2017
  }
1842
- lines.push("", "Tip: run /history to pick one interactively, or paste an id after /resume.");
2018
+ lines.push("", t("dialogListTip"));
1843
2019
  return lines.join("\n");
1844
2020
  }
1845
2021
  async function fetchRecentDialogs(args) {
@@ -1920,7 +2096,7 @@ async function runDialogPicker(args) {
1920
2096
  }
1921
2097
 
1922
2098
  // packages/cli/tui/pasteImage.ts
1923
- import { existsSync } from "node:fs";
2099
+ import { existsSync as existsSync2 } from "node:fs";
1924
2100
  import { readFile, stat } from "node:fs/promises";
1925
2101
  import { homedir } from "node:os";
1926
2102
  import { isAbsolute, resolve } from "node:path";
@@ -1975,7 +2151,7 @@ function detectImagePaths(line, cwd) {
1975
2151
  if (!token.raw) continue;
1976
2152
  const resolved = resolveImageSource(token.decoded, cwd);
1977
2153
  if (!isImagePath(resolved)) continue;
1978
- if (!existsSync(resolved)) continue;
2154
+ if (!existsSync2(resolved)) continue;
1979
2155
  out.push({ raw: token.raw, resolvedPath: resolved });
1980
2156
  }
1981
2157
  return out;
@@ -2191,271 +2367,6 @@ function detectGitStatus(cwd) {
2191
2367
  }
2192
2368
  }
2193
2369
 
2194
- // packages/cli/tui/tuiAnsi.ts
2195
- var ANSI_ESCAPE_REGEX = /\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/g;
2196
- var OSC_HYPERLINK_REGEX = /\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)\x1b\]8;;(?:\x07|\x1b\\)|\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/g;
2197
- function stripAnsi(text) {
2198
- return text.replace(OSC_HYPERLINK_REGEX, "").replace(ANSI_ESCAPE_REGEX, "");
2199
- }
2200
- var SGR_SEQUENCE_REGEX = /^\x1b\[[0-9;]*m/;
2201
- var TRAILING_SGR_REGEX = /(?:\x1b\[[0-9;]*m)+$/;
2202
- function applyTerminalOutputToText(existing, chunk) {
2203
- if (!chunk) return existing;
2204
- let text = existing;
2205
- let index = 0;
2206
- while (index < chunk.length) {
2207
- if (chunk[index] === "\x1B") {
2208
- const sgr = SGR_SEQUENCE_REGEX.exec(chunk.slice(index));
2209
- if (sgr) {
2210
- text += sgr[0];
2211
- index += sgr[0].length;
2212
- continue;
2213
- }
2214
- const osc = chunk.slice(index).match(/^\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/);
2215
- if (osc) {
2216
- index += osc[0].length;
2217
- continue;
2218
- }
2219
- const csi = chunk.slice(index).match(/^\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/);
2220
- if (csi) {
2221
- index += csi[0].length;
2222
- continue;
2223
- }
2224
- index += 1;
2225
- continue;
2226
- }
2227
- const ch = chunk[index];
2228
- if (ch === "\r") {
2229
- const lastNl = text.lastIndexOf("\n");
2230
- text = lastNl === -1 ? "" : text.slice(0, lastNl + 1);
2231
- index += 1;
2232
- continue;
2233
- }
2234
- if (ch === "\n") {
2235
- text += "\n";
2236
- index += 1;
2237
- continue;
2238
- }
2239
- if (ch === "\b") {
2240
- const trailing = TRAILING_SGR_REGEX.exec(text);
2241
- const sgrTail = trailing ? trailing[0] : "";
2242
- const head = sgrTail ? text.slice(0, -sgrTail.length) : text;
2243
- if (head.length > 0 && head[head.length - 1] !== "\n") {
2244
- text = head.slice(0, -1) + sgrTail;
2245
- }
2246
- index += 1;
2247
- continue;
2248
- }
2249
- const code = ch.charCodeAt(0);
2250
- if (code < 32 && ch !== " " || code === 127) {
2251
- index += 1;
2252
- continue;
2253
- }
2254
- text += ch;
2255
- index += 1;
2256
- }
2257
- return text;
2258
- }
2259
- function displayWidth2(str) {
2260
- let width = 0;
2261
- for (const char of str) {
2262
- const code = char.codePointAt(0) ?? 0;
2263
- if (code < 32 || code === 127) continue;
2264
- if (code >= 4352 && code <= 4447 || // 0x2768-0x2775 (ornamental brackets, incl. the ❯ prompt at U+276F)
2265
- // render narrow in terminals; counting them wide drifts the cursor.
2266
- code >= 9728 && code <= 10175 && !(code >= 10088 && code <= 10101) || // 0x2B00-0x2BFF (Misc Symbols and Arrows, incl. ⬢ U+2B22 used as the
2267
- // status-line agent icon) render double-wide in common monospace fonts;
2268
- // counting ⬢ as width 1 drifts the whole status line right of the icon.
2269
- code >= 11008 && code <= 11263 || code >= 11904 && code <= 12350 || code >= 12352 && code <= 13247 || code >= 13312 && code <= 19903 || code >= 19968 && code <= 42191 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65072 && code <= 65135 || code >= 65281 && code <= 65376 || code >= 65504 && code <= 65510 || code >= 127744 && code <= 129791 || code >= 131072 && code <= 196605 || code >= 196608 && code <= 262141 || // East Asian Ambiguous CJK quotation marks (U+201C/D “ ”, U+2018/9 ‘ ’).
2270
- // In CJK locale + CJK fonts these render double-wide like 全角 punctuation;
2271
- // in English fonts they stay width 1. Follow the active locale so Chinese
2272
- // replies align correctly without breaking English terminal output.
2273
- getCliLocale() === "zh" && (code === 8220 || code === 8221 || code === 8216 || code === 8217)) {
2274
- width += 2;
2275
- } else {
2276
- width += 1;
2277
- }
2278
- }
2279
- return width;
2280
- }
2281
- function visibleWidth(str) {
2282
- return displayWidth2(stripAnsi(str));
2283
- }
2284
- function truncateAnsi(text, maxWidth) {
2285
- if (maxWidth <= 0) return "";
2286
- if (visibleWidth(text) <= maxWidth) return text;
2287
- let width = 0;
2288
- let out = "";
2289
- let i = 0;
2290
- let sawAnsi = false;
2291
- while (i < text.length) {
2292
- if (text[i] === "\x1B" && text[i + 1] === "[") {
2293
- sawAnsi = true;
2294
- let j = i + 2;
2295
- while (j < text.length) {
2296
- const code = text.charCodeAt(j);
2297
- j += 1;
2298
- if (code >= 64 && code <= 126) break;
2299
- }
2300
- out += text.slice(i, j);
2301
- i = j;
2302
- continue;
2303
- }
2304
- const codePoint = text.codePointAt(i) ?? 0;
2305
- const char = String.fromCodePoint(codePoint);
2306
- const charWidth = displayWidth2(char);
2307
- if (width + charWidth > maxWidth) break;
2308
- out += char;
2309
- width += charWidth;
2310
- i += char.length;
2311
- }
2312
- return sawAnsi ? `${out}\x1B[0m` : out;
2313
- }
2314
- function fitAnsiLine(text, width, ellipsis = "\u2026") {
2315
- if (width <= 0) return "";
2316
- if (visibleWidth(text) <= width) return text;
2317
- const ellipsisWidth = displayWidth2(ellipsis);
2318
- if (width < ellipsisWidth) return truncateAnsi(text, width);
2319
- if (width === ellipsisWidth) return truncateAnsi(ellipsis, width) || truncateAnsi(text, width);
2320
- return `${truncateAnsi(text, width - ellipsisWidth)}${ellipsis}`;
2321
- }
2322
- function countPhysicalLines(text, columns) {
2323
- const lines = text.split("\n");
2324
- let total = 0;
2325
- for (const line of lines) {
2326
- const width = displayWidth2(line);
2327
- total += Math.max(1, Math.ceil(width / columns));
2328
- }
2329
- return Math.max(total, 1);
2330
- }
2331
- function takeDisplayWidth(text, width) {
2332
- let used = 0;
2333
- let index = 0;
2334
- for (const char of text) {
2335
- const charWidth = displayWidth2(char);
2336
- if (used + charWidth > width && used > 0) break;
2337
- used += charWidth;
2338
- index += char.length;
2339
- }
2340
- return { prefix: text.slice(0, index), rest: text.slice(index) };
2341
- }
2342
- function padOrTruncateToWidth(text, width) {
2343
- const textWidth = visibleWidth(text);
2344
- if (textWidth > width) {
2345
- return truncateAnsi(text, width);
2346
- }
2347
- return `${text}${" ".repeat(width - textWidth)}`;
2348
- }
2349
- var SGR_RESET_REGEX = /^\x1b\[0?m$/;
2350
- function tokenizeAnsiLine(line) {
2351
- const tokens = [];
2352
- let index = 0;
2353
- while (index < line.length) {
2354
- if (line[index] === "\x1B") {
2355
- const osc = line.slice(index).match(/^\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/);
2356
- if (osc) {
2357
- tokens.push({ kind: "sgr", value: osc[0], width: 0 });
2358
- index += osc[0].length;
2359
- continue;
2360
- }
2361
- const sgr = SGR_SEQUENCE_REGEX.exec(line.slice(index));
2362
- if (sgr) {
2363
- tokens.push({ kind: "sgr", value: sgr[0], width: 0 });
2364
- index += sgr[0].length;
2365
- continue;
2366
- }
2367
- }
2368
- const codePoint = line.codePointAt(index) ?? 0;
2369
- const value = String.fromCodePoint(codePoint);
2370
- tokens.push({ kind: "char", value, width: displayWidth2(value) });
2371
- index += value.length;
2372
- }
2373
- return tokens;
2374
- }
2375
- function wrapTranscriptLine(line, columns) {
2376
- if (line === "") return [""];
2377
- const tokens = tokenizeAnsiLine(line);
2378
- const result = [];
2379
- let activeStyles = [];
2380
- const applyStyleToken = (value) => {
2381
- if (SGR_RESET_REGEX.test(value)) {
2382
- activeStyles = [];
2383
- } else {
2384
- activeStyles.push(value);
2385
- }
2386
- };
2387
- let start = 0;
2388
- while (start < tokens.length) {
2389
- if (tokens.slice(start).every((token) => token.kind === "sgr")) {
2390
- if (result.length > 0) break;
2391
- }
2392
- const openingStyles = [...activeStyles];
2393
- let width = 0;
2394
- let end = start;
2395
- let lastBreak = -1;
2396
- while (end < tokens.length) {
2397
- const token = tokens[end];
2398
- if (token.kind === "sgr") {
2399
- end += 1;
2400
- continue;
2401
- }
2402
- if (width + token.width > columns && width > 0) break;
2403
- width += token.width;
2404
- end += 1;
2405
- if (token.value === " " || token.value === " ") {
2406
- lastBreak = end;
2407
- }
2408
- }
2409
- let segmentEnd = end;
2410
- if (end < tokens.length && lastBreak > start) {
2411
- const overflowToken = tokens[end];
2412
- if (overflowToken.kind === "char" && overflowToken.value !== " " && overflowToken.width === 1) {
2413
- segmentEnd = lastBreak;
2414
- }
2415
- }
2416
- if (segmentEnd === start) segmentEnd = start + 1;
2417
- let segment = "";
2418
- let sawStyle = openingStyles.length > 0;
2419
- for (let i = start; i < segmentEnd; i += 1) {
2420
- const token = tokens[i];
2421
- segment += token.value;
2422
- if (token.kind === "sgr") {
2423
- sawStyle = true;
2424
- applyStyleToken(token.value);
2425
- }
2426
- }
2427
- const prefix = openingStyles.join("");
2428
- const needsReset = (sawStyle || activeStyles.length > 0) && !segment.endsWith("\x1B[0m");
2429
- result.push(`${prefix}${segment}${needsReset ? "\x1B[0m" : ""}`);
2430
- start = segmentEnd;
2431
- while (start < tokens.length) {
2432
- const token = tokens[start];
2433
- if (token.kind === "char" && token.value === " ") {
2434
- start += 1;
2435
- continue;
2436
- }
2437
- break;
2438
- }
2439
- }
2440
- return result.length > 0 ? result : [""];
2441
- }
2442
- function wrapTextToLines(text, columns) {
2443
- const result = [];
2444
- for (const logicalLine of text.split("\n")) {
2445
- if (logicalLine === "") {
2446
- result.push("");
2447
- continue;
2448
- }
2449
- let remaining = logicalLine;
2450
- while (remaining.length > 0) {
2451
- const { prefix, rest } = takeDisplayWidth(remaining, columns);
2452
- result.push(prefix);
2453
- remaining = rest;
2454
- }
2455
- }
2456
- return result;
2457
- }
2458
-
2459
2370
  // packages/cli/tui/sessionRender.ts
2460
2371
  function formatCwd(cwd) {
2461
2372
  const parts = cwd.split(/[/\\]/);
@@ -2470,12 +2381,12 @@ function formatElapsedSeconds(totalSeconds) {
2470
2381
  const mins = minutes % 60;
2471
2382
  return `${hours}h ${mins}m`;
2472
2383
  }
2473
- function renderComposerTokenChip(tokens, fallbackContextWindow) {
2384
+ function renderComposerTokenChip(tokens, fallbackContextWindow, estimatedContextTokens) {
2474
2385
  const cw = tokens?.contextWindow ?? fallbackContextWindow;
2475
2386
  if (!cw) {
2476
2387
  return "context: \u2014";
2477
2388
  }
2478
- const used = tokens ? tokens.input + tokens.output : 0;
2389
+ const used = tokens ? tokens.input + tokens.output : Math.max(0, estimatedContextTokens ?? 0);
2479
2390
  const pct = Math.min(100, used / cw * 100);
2480
2391
  const pctText = pct > 0 && pct < 10 ? pct.toFixed(1) : Math.round(pct).toString();
2481
2392
  return `context: ${pctText}% (${formatTokenCount(used)}/${formatTokenCount(cw)})`;
@@ -2497,7 +2408,15 @@ function renderStatusLine(state) {
2497
2408
  const untrackedText = untracked > 0 ? ` ${themeText(`?${untracked}`, "muted", colorEnabled)}` : "";
2498
2409
  parts.push(`${branchText}${modifiedText}${untrackedText}`);
2499
2410
  }
2500
- const tokenSegment = themeText(renderComposerTokenChip(state.turnTokens, state.contextWindow), "muted", colorEnabled);
2411
+ const tokenSegment = themeText(
2412
+ renderComposerTokenChip(
2413
+ state.turnTokens,
2414
+ state.contextWindow,
2415
+ state.estimatedContextTokens
2416
+ ),
2417
+ "muted",
2418
+ colorEnabled
2419
+ );
2501
2420
  parts.push(tokenSegment);
2502
2421
  const runningCount = getProcessRegistry().list().filter((p) => p.status === "running").length;
2503
2422
  if (runningCount > 0) {
@@ -2579,7 +2498,7 @@ function renderWelcome(state, frame = 0, maxFrames = 0, columns) {
2579
2498
  const isDark = brightness === "dark";
2580
2499
  let sceneArt = colorEnabled ? buildColoredScene(isDark, frame, maxFrames) : buildPlainScene(isDark, frame, maxFrames);
2581
2500
  if (typeof columns === "number" && columns > 0) {
2582
- const widestSceneCol = sceneArt.split("\n").reduce((max, line) => Math.max(max, displayWidth2(stripAnsi(line))), 0);
2501
+ const widestSceneCol = sceneArt.split("\n").reduce((max, line) => Math.max(max, displayWidth(stripAnsi(line))), 0);
2583
2502
  if (columns < widestSceneCol) sceneArt = "";
2584
2503
  }
2585
2504
  const versionLine = colorEnabled ? `\x1B[1m${themeColorSequence("accent")}nolo\x1B[0m ${state.cliVersion ?? ""} | server ${state.serverUrl}`.replace(" |", " |") : `nolo ${state.cliVersion ?? ""} | server ${state.serverUrl}`.replace(" |", " |");
@@ -2629,19 +2548,19 @@ function renderContextPanel(state, colorEnabled = resolveCliColorEnabled()) {
2629
2548
  ];
2630
2549
  let maxW = 0;
2631
2550
  for (const l of labels) {
2632
- const w = displayWidth2(l);
2551
+ const w = displayWidth(l);
2633
2552
  if (w > maxW) maxW = w;
2634
2553
  }
2635
2554
  const targetWidth = maxW >= 9 ? maxW + 1 : 9;
2636
2555
  const padLabel = (raw) => {
2637
- const w = displayWidth2(raw);
2556
+ const w = displayWidth(raw);
2638
2557
  const padding = " ".repeat(Math.max(0, targetWidth - w));
2639
2558
  return raw + padding;
2640
2559
  };
2641
2560
  const field = (rawLabel, value) => `${themeText(padLabel(rawLabel), "muted", colorEnabled)}${value}`;
2642
2561
  const next = (command, description) => ` ${themeText(command, "accent", colorEnabled)}${themeText(description, "muted", colorEnabled)}`;
2643
2562
  const titleText = t("contextTitle");
2644
- const heading = colorEnabled ? [renderDialogTitle(titleText, true)] : [titleText, "\u2500".repeat(displayWidth2(titleText))];
2563
+ const heading = colorEnabled ? [renderDialogTitle(titleText, true)] : [titleText, "\u2500".repeat(displayWidth(titleText))];
2645
2564
  return [
2646
2565
  ...heading,
2647
2566
  field(labels[0], `${state.agentName} (${state.agentKey})`),
@@ -2684,86 +2603,6 @@ function renderKnownAgents(colorEnabled = resolveCliColorEnabled()) {
2684
2603
  ].join("\n");
2685
2604
  }
2686
2605
 
2687
- // packages/core/collapsedPaste.ts
2688
- var COLLAPSE_PASTE_MIN_LINES = 8;
2689
- var COLLAPSE_PASTE_MIN_CHARS = 400;
2690
- var COLLAPSED_PASTE_PLACEHOLDER_RE = /\[paste #(\d+) · (\d+) lines\]/g;
2691
- function countTextLines(text) {
2692
- if (text.length === 0) return 0;
2693
- let lines = 1;
2694
- for (let i = 0; i < text.length; i += 1) {
2695
- if (text.charCodeAt(i) === 10) lines += 1;
2696
- }
2697
- return lines;
2698
- }
2699
- function shouldCollapsePaste(text, threshold = {}) {
2700
- const minLines = threshold.minLines ?? COLLAPSE_PASTE_MIN_LINES;
2701
- const minChars = threshold.minChars ?? COLLAPSE_PASTE_MIN_CHARS;
2702
- if (text.length === 0) return false;
2703
- if (text.length >= minChars) return true;
2704
- return countTextLines(text) >= minLines;
2705
- }
2706
- function formatCollapsedPastePlaceholder(id, text) {
2707
- const lines = countTextLines(text);
2708
- return `[paste #${id} \xB7 ${lines} lines]`;
2709
- }
2710
- function createCollapsedPasteStore() {
2711
- return { nextId: 1, items: /* @__PURE__ */ new Map() };
2712
- }
2713
- function allocateCollapsedPaste(store, text) {
2714
- const id = store.nextId;
2715
- store.nextId += 1;
2716
- store.items.set(id, text);
2717
- return { id, placeholder: formatCollapsedPastePlaceholder(id, text) };
2718
- }
2719
- function releaseCollapsedPaste(store, id) {
2720
- store.items.delete(id);
2721
- }
2722
- function clearCollapsedPasteStore(store) {
2723
- store.items.clear();
2724
- store.nextId = 1;
2725
- }
2726
- function expandCollapsedPastes(buffer, store) {
2727
- if (store.items.size === 0) return buffer;
2728
- COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
2729
- return buffer.replace(COLLAPSED_PASTE_PLACEHOLDER_RE, (match, idRaw) => {
2730
- const id = Number(idRaw);
2731
- const full = store.items.get(id);
2732
- return full === void 0 ? match : full;
2733
- });
2734
- }
2735
- function expandRangeToCollapsedPasteChips(buffer, start, end) {
2736
- let s = Math.max(0, Math.min(start, end));
2737
- let e = Math.max(s, Math.max(start, end));
2738
- if (s === e) return { start: s, end: e };
2739
- COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
2740
- let match;
2741
- while ((match = COLLAPSED_PASTE_PLACEHOLDER_RE.exec(buffer)) !== null) {
2742
- const chipStart = match.index;
2743
- const chipEnd = chipStart + match[0].length;
2744
- if (chipStart < e && chipEnd > s) {
2745
- if (chipStart < s) s = chipStart;
2746
- if (chipEnd > e) e = chipEnd;
2747
- }
2748
- }
2749
- return { start: s, end: e };
2750
- }
2751
- function findCollapsedPasteSpanAt(buffer, pos, opts = {}) {
2752
- COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
2753
- let match;
2754
- while ((match = COLLAPSED_PASTE_PLACEHOLDER_RE.exec(buffer)) !== null) {
2755
- const start = match.index;
2756
- const end = start + match[0].length;
2757
- const inside = pos > start && pos < end;
2758
- const atEnd = opts.preferLeft && pos === end;
2759
- const atStart = !opts.preferLeft && pos === start;
2760
- if (inside || atEnd || atStart) {
2761
- return { id: Number(match[1]), start, end };
2762
- }
2763
- }
2764
- return null;
2765
- }
2766
-
2767
2606
  // packages/cli/tui/sessionInput.ts
2768
2607
  var PASTE_TOKEN_PREFIX = "\0PASTE\0";
2769
2608
  function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
@@ -3051,6 +2890,7 @@ function createInitialTuiState(env = process.env) {
3051
2890
  ) || void 0;
3052
2891
  const dialogEnvValue = asOptionalTrimmedString(env.NOLO_DIALOG);
3053
2892
  const explicitDialogKey = asOptionalTrimmedString(env.NOLO_DIALOG_KEY) ?? (dialogEnvValue?.startsWith("dialog-") ? dialogEnvValue : void 0);
2893
+ const autoRouteDefault = env.NOLO_AUTO_ROUTE !== "0";
3054
2894
  return {
3055
2895
  agentKey,
3056
2896
  agentName,
@@ -3076,16 +2916,39 @@ function createInitialTuiState(env = process.env) {
3076
2916
  "hide"
3077
2917
  ),
3078
2918
  toolDisplay: normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "compact"),
3079
- contextWindow: getModelContextWindow(agentName)
2919
+ contextWindow: resolveAgentContextWindow({
2920
+ agentKey,
2921
+ agentName,
2922
+ autoRouteDefault
2923
+ }),
2924
+ estimatedContextTokens: estimateDefaultCliContextTokens({
2925
+ cwd,
2926
+ agentKey,
2927
+ agentName: autoRouteDefault ? "DeepSeek V4 Flash" : agentName,
2928
+ model: autoRouteDefault ? "deepseek-v4-flash" : void 0
2929
+ })
3080
2930
  };
3081
2931
  }
3082
- function applyAgentSwitch(state, target) {
2932
+ function applyAgentSwitch(state, target, opts) {
2933
+ const autoRouteDefault = opts?.autoRouteDefault ?? process.env.NOLO_AUTO_ROUTE !== "0";
2934
+ const contextWindow = resolveAgentContextWindow({
2935
+ agentKey: target.key,
2936
+ agentName: target.name,
2937
+ model: target.model,
2938
+ autoRouteDefault
2939
+ });
3083
2940
  return {
3084
2941
  nextState: {
3085
2942
  ...state,
3086
2943
  agentName: target.name,
3087
2944
  agentKey: target.key,
3088
- contextWindow: getModelContextWindow(target.name)
2945
+ contextWindow,
2946
+ estimatedContextTokens: estimateDefaultCliContextTokens({
2947
+ cwd: state.cwd,
2948
+ agentKey: target.key,
2949
+ agentName: target.name,
2950
+ model: target.model
2951
+ })
3089
2952
  },
3090
2953
  output: `Switched to ${target.name}. ${state.dialogId ? `Dialog kept: ${state.dialogId}` : "Dialog kept: new"}`
3091
2954
  };
@@ -3147,32 +3010,32 @@ function handleTuiInput(input, state) {
3147
3010
  return {
3148
3011
  nextState: state,
3149
3012
  output: [
3150
- `Current theme: ${getActiveThemeName()} \xB7 ${brightness}`,
3151
- `Usage: /theme <name> | /theme light | /theme dark`,
3152
- `Available themes: ${available}`
3013
+ t("themeCurrent", getActiveThemeName(), brightness),
3014
+ t("themeUsage"),
3015
+ t("themeAvailable", available)
3153
3016
  ].join("\n")
3154
3017
  };
3155
3018
  }
3156
3019
  if (sub === "light" || sub === "dark") {
3157
3020
  setActiveBrightness(sub);
3158
- return { nextState: state, output: `Switched to ${sub} background colors.` };
3021
+ return { nextState: state, output: t("themeBrightnessSwitched", sub) };
3159
3022
  }
3160
3023
  if (sub === "auto") {
3161
3024
  setActiveBrightness(null);
3162
3025
  return {
3163
3026
  nextState: state,
3164
- output: `Background colors follow terminal detection (now: ${resolveTuiBrightness()}).`
3027
+ output: t("themeBrightnessAuto", resolveTuiBrightness())
3165
3028
  };
3166
3029
  }
3167
3030
  if (setActiveThemeName(sub)) {
3168
3031
  return {
3169
3032
  nextState: state,
3170
- output: `Switched to theme: ${sub}`
3033
+ output: t("themeSwitched", sub)
3171
3034
  };
3172
3035
  } else {
3173
3036
  return {
3174
3037
  nextState: state,
3175
- output: `Unknown theme: ${sub}. Available themes: ${available}`
3038
+ output: t("themeUnknown", sub, available)
3176
3039
  };
3177
3040
  }
3178
3041
  }
@@ -3182,20 +3045,19 @@ function handleTuiInput(input, state) {
3182
3045
  if (!sub) {
3183
3046
  return {
3184
3047
  nextState: state,
3185
- output: `Current density: ${getActiveDensity()}
3186
- Usage: /density <cozy|spacious>`
3048
+ output: t("densityCurrent", getActiveDensity())
3187
3049
  };
3188
3050
  }
3189
3051
  if (sub === "cozy" || sub === "spacious") {
3190
3052
  setActiveDensity(sub);
3191
3053
  return {
3192
3054
  nextState: state,
3193
- output: `Switched to layout density: ${sub}`
3055
+ output: t("densitySwitched", sub)
3194
3056
  };
3195
3057
  } else {
3196
3058
  return {
3197
3059
  nextState: state,
3198
- output: `Unknown density: ${sub}. Use 'cozy' or 'spacious'.`
3060
+ output: t("densityUnknown", sub)
3199
3061
  };
3200
3062
  }
3201
3063
  }
@@ -3206,52 +3068,52 @@ Usage: /density <cozy|spacious>`
3206
3068
  if (argText !== "auto" && argText !== "local" && argText !== "server") {
3207
3069
  return {
3208
3070
  nextState: state,
3209
- output: "Usage: /runtime <auto|local|server>"
3071
+ output: t("runtimeUsage")
3210
3072
  };
3211
3073
  }
3212
3074
  return {
3213
3075
  nextState: { ...state, runtimeMode: argText },
3214
- output: `Runtime: ${argText}`
3076
+ output: t("runtimeSet", argText)
3215
3077
  };
3216
3078
  }
3217
3079
  case "/tools": {
3218
3080
  if (!argText) {
3219
3081
  return {
3220
3082
  nextState: state,
3221
- output: `Tool display: ${state.toolDisplay} (hide | compact | verbose)`
3083
+ output: t("toolsCurrent", state.toolDisplay)
3222
3084
  };
3223
3085
  }
3224
3086
  const normalizedArg = asTrimmedLowercaseString(argText);
3225
3087
  if (!["hide", "compact", "verbose", "on", "off"].includes(normalizedArg)) {
3226
3088
  return {
3227
3089
  nextState: state,
3228
- output: "Usage: /tools <hide|compact|verbose>"
3090
+ output: t("toolsUsage")
3229
3091
  };
3230
3092
  }
3231
3093
  const nextMode = normalizeToolDisplayMode(normalizedArg, state.toolDisplay);
3232
3094
  return {
3233
3095
  nextState: { ...state, toolDisplay: nextMode },
3234
- output: `Tool display: ${nextMode}`
3096
+ output: t("toolsSet", nextMode)
3235
3097
  };
3236
3098
  }
3237
3099
  case "/thinking": {
3238
3100
  if (!argText) {
3239
3101
  return {
3240
3102
  nextState: state,
3241
- output: `Thinking display: ${state.thinkingDisplay} (hide | marker | show)`
3103
+ output: t("thinkingCurrent", state.thinkingDisplay)
3242
3104
  };
3243
3105
  }
3244
3106
  const normalizedArg = asTrimmedLowercaseString(argText);
3245
3107
  if (!["hide", "marker", "show", "on", "off"].includes(normalizedArg)) {
3246
3108
  return {
3247
3109
  nextState: state,
3248
- output: "Usage: /thinking <hide|marker|show>"
3110
+ output: t("thinkingUsage")
3249
3111
  };
3250
3112
  }
3251
3113
  const nextMode = normalizeThinkingDisplayMode(normalizedArg, state.thinkingDisplay);
3252
3114
  return {
3253
3115
  nextState: { ...state, thinkingDisplay: nextMode },
3254
- output: `Thinking display: ${nextMode}`
3116
+ output: t("thinkingSet", nextMode)
3255
3117
  };
3256
3118
  }
3257
3119
  case "/tasks":
@@ -3263,14 +3125,14 @@ Usage: /density <cozy|spacious>`
3263
3125
  const stopped = all.filter((p) => p.status !== "running");
3264
3126
  const lines = [];
3265
3127
  if (running.length > 0) {
3266
- lines.push(`Running processes (${running.length}):`);
3128
+ lines.push(t("tasksRunning", String(running.length)));
3267
3129
  for (const p of running) {
3268
3130
  const elapsed = formatElapsedSeconds(Math.floor((Date.now() - p.startedAt) / 1e3));
3269
3131
  lines.push(` pid ${p.pid} ${p.label} running ${elapsed}`);
3270
3132
  }
3271
3133
  }
3272
3134
  if (stopped.length > 0) {
3273
- lines.push(`Stopped/exited (${stopped.length}):`);
3135
+ lines.push(t("tasksStopped", String(stopped.length)));
3274
3136
  for (const p of stopped) {
3275
3137
  const elapsed = formatElapsedSeconds(Math.floor((Date.now() - p.startedAt) / 1e3));
3276
3138
  const exitInfo = p.exitCode !== void 0 ? ` exit ${p.exitCode}` : "";
@@ -3278,38 +3140,38 @@ Usage: /density <cozy|spacious>`
3278
3140
  }
3279
3141
  }
3280
3142
  if (all.length === 0) {
3281
- lines.push("No processes.");
3143
+ lines.push(t("tasksNone"));
3282
3144
  }
3283
3145
  return { nextState: state, output: lines.join("\n") };
3284
3146
  }
3285
3147
  case "/stop": {
3286
3148
  const registry = getProcessRegistry();
3287
3149
  if (!argText) {
3288
- return { nextState: state, output: "Usage: /stop <pid|label|all>" };
3150
+ return { nextState: state, output: t("stopUsage") };
3289
3151
  }
3290
3152
  if (argText === "all") {
3291
3153
  const before = registry.list().filter((p) => p.status === "running").length;
3292
3154
  registry.stopAll();
3293
- return { nextState: state, output: `Stopped ${before} processes` };
3155
+ return { nextState: state, output: t("stopAllDone", String(before)) };
3294
3156
  }
3295
3157
  if (/^\d+$/.test(argText)) {
3296
3158
  const pid = parseInt(argText, 10);
3297
3159
  const proc = registry.get(pid);
3298
3160
  if (!proc || proc.status !== "running") {
3299
- return { nextState: state, output: `No running process with pid ${pid}` };
3161
+ return { nextState: state, output: t("stopNoPid", String(pid)) };
3300
3162
  }
3301
3163
  registry.kill(pid);
3302
- return { nextState: state, output: `Stopped pid ${pid} (${proc.label})` };
3164
+ return { nextState: state, output: t("stopPidDone", String(pid), proc.label) };
3303
3165
  }
3304
3166
  const matches = registry.list().filter((p) => p.status === "running" && p.label === argText);
3305
3167
  if (matches.length === 0) {
3306
- return { nextState: state, output: `No running process labeled '${argText}'` };
3168
+ return { nextState: state, output: t("stopNoLabel", argText) };
3307
3169
  }
3308
3170
  for (const p of matches) {
3309
3171
  registry.kill(p.pid);
3310
3172
  }
3311
3173
  const stoppedNames = matches.map((p) => `pid ${p.pid} (${p.label})`).join(", ");
3312
- return { nextState: state, output: `Stopped ${stoppedNames}` };
3174
+ return { nextState: state, output: t("stopLabelsDone", stoppedNames) };
3313
3175
  }
3314
3176
  case "/exit":
3315
3177
  case "/quit":
@@ -3333,15 +3195,13 @@ Usage: /density <cozy|spacious>`
3333
3195
  if (argText) {
3334
3196
  return {
3335
3197
  nextState: state,
3336
- output: `Unknown command: ${trimmed}
3337
-
3338
- ${renderTuiHelp()}`
3198
+ output: t("unknownCommand", trimmed) + renderTuiHelp()
3339
3199
  };
3340
3200
  }
3341
3201
  if (!state.dialogId) {
3342
3202
  return {
3343
3203
  nextState: state,
3344
- output: "Current dialog: new (nothing to compact yet)"
3204
+ output: t("compactNothing")
3345
3205
  };
3346
3206
  }
3347
3207
  return {
@@ -3368,15 +3228,14 @@ ${renderTuiHelp()}`
3368
3228
  if (argText === "current" || argText === "show") {
3369
3229
  return {
3370
3230
  nextState: state,
3371
- output: `Current agent: ${state.agentName} (${state.agentKey})`
3231
+ output: t("agentCurrent", state.agentName, state.agentKey)
3372
3232
  };
3373
3233
  }
3374
3234
  const resolvedTarget = resolveAgentSwitchTarget(argText, resolveCatalogPlatformAgents());
3375
3235
  if (!resolvedTarget) {
3376
3236
  return {
3377
3237
  nextState: state,
3378
- output: `I don't know agent "${argText}" yet.
3379
- Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
3238
+ output: t("agentUnknown", argText)
3380
3239
  };
3381
3240
  }
3382
3241
  return applyAgentSwitch(state, resolvedTarget);
@@ -3430,6 +3289,16 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
3430
3289
  action: { type: "set-mouse", enabled: argText === "on" }
3431
3290
  };
3432
3291
  }
3292
+ case "/altscreen": {
3293
+ if (argText !== "on" && argText !== "off") {
3294
+ return { nextState: state, output: t("altscreenUsage") };
3295
+ }
3296
+ return {
3297
+ nextState: state,
3298
+ output: argText === "on" ? t("altscreenOn") : t("altscreenOff"),
3299
+ action: { type: "set-altscreen", enabled: argText === "on" }
3300
+ };
3301
+ }
3433
3302
  case "/resume": {
3434
3303
  if (!argText) {
3435
3304
  return {
@@ -3459,7 +3328,7 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
3459
3328
  if (rest[0] === "attach") {
3460
3329
  const docName = rest.slice(1).join(" ").trim();
3461
3330
  if (!docName) {
3462
- return { nextState: state, output: "Usage: /doc attach <doc>" };
3331
+ return { nextState: state, output: t("docAttachUsage") };
3463
3332
  }
3464
3333
  const attachedDocs = state.attachedDocs.includes(docName) ? state.attachedDocs : [...state.attachedDocs, docName];
3465
3334
  return {
@@ -3469,7 +3338,7 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
3469
3338
  }
3470
3339
  return {
3471
3340
  nextState: state,
3472
- output: state.attachedDocs.length > 0 ? `Attached docs: ${state.attachedDocs.join(", ")}` : "No docs attached. Use /doc attach <doc>."
3341
+ output: state.attachedDocs.length > 0 ? t("docList", state.attachedDocs.join(", ")) : t("docNone")
3473
3342
  };
3474
3343
  }
3475
3344
  case "/skill": {
@@ -3477,7 +3346,7 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
3477
3346
  if (sub === "attach") {
3478
3347
  const skillRef = rest.slice(1).join(" ").trim();
3479
3348
  if (!skillRef) {
3480
- return { nextState: state, output: "Usage: /skill attach <skill-ref>" };
3349
+ return { nextState: state, output: t("skillAttachUsage") };
3481
3350
  }
3482
3351
  const attachedSkills = state.attachedSkills.includes(skillRef) ? state.attachedSkills : [...state.attachedSkills, skillRef];
3483
3352
  return {
@@ -3488,38 +3357,37 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
3488
3357
  if (sub === "detach") {
3489
3358
  const skillRef = rest.slice(1).join(" ").trim();
3490
3359
  if (!skillRef) {
3491
- return { nextState: state, output: "Usage: /skill detach <skill-ref>" };
3360
+ return { nextState: state, output: t("skillDetachUsage") };
3492
3361
  }
3493
3362
  const attachedSkills = state.attachedSkills.filter((s) => s !== skillRef);
3494
3363
  return {
3495
3364
  nextState: { ...state, attachedSkills },
3496
- output: state.attachedSkills.includes(skillRef) ? `Detached skill: ${skillRef}` : `Skill not attached: ${skillRef}`
3365
+ output: state.attachedSkills.includes(skillRef) ? t("skillDetached", skillRef) : t("skillNotAttached", skillRef)
3497
3366
  };
3498
3367
  }
3499
3368
  if (sub === "clear") {
3500
3369
  if (state.attachedSkills.length === 0) {
3501
- return { nextState: state, output: "No skills attached." };
3370
+ return { nextState: state, output: t("skillNone") };
3502
3371
  }
3503
3372
  return {
3504
3373
  nextState: { ...state, attachedSkills: [] },
3505
- output: `Cleared ${state.attachedSkills.length} skill(s).`
3374
+ output: t("skillCleared", String(state.attachedSkills.length))
3506
3375
  };
3507
3376
  }
3508
3377
  return {
3509
3378
  nextState: state,
3510
- output: state.attachedSkills.length > 0 ? `Attached skills: ${state.attachedSkills.join(", ")}
3511
- Usage: /skill attach <ref> | /skill detach <ref> | /skill clear` : "No skills attached. Use /skill attach <skill-ref> to attach a skill.\nSkill refs can be a dbKey (page-xxx), a skill name (searched in .agents/skills/ then docs/skills/), or a direct path."
3379
+ output: state.attachedSkills.length > 0 ? t("skillList", state.attachedSkills.join(", ")) : t("skillNoneHint")
3512
3380
  };
3513
3381
  }
3514
3382
  case "/customize":
3515
3383
  return {
3516
3384
  nextState: state,
3517
- output: "Tell nolo what to change, for example: /customize make my default agent more concise."
3385
+ output: t("customizeHint")
3518
3386
  };
3519
3387
  case "/login":
3520
3388
  return {
3521
3389
  nextState: state,
3522
- output: "MVP login uses profile/env auth. Set AUTH_TOKEN, NOLO_SERVER, or NOLO_PROFILE before starting nolo."
3390
+ output: t("loginHint")
3523
3391
  };
3524
3392
  case "/profile":
3525
3393
  return {
@@ -3535,16 +3403,12 @@ Usage: /skill attach <ref> | /skill detach <ref> | /skill clear` : "No skills at
3535
3403
  case "/version":
3536
3404
  return {
3537
3405
  nextState: state,
3538
- output: `nolo ${state.cliVersion || "unknown version"}
3539
- Update this install with: nolo update
3540
- If repo-local output differs, publish/install the latest npm package first.`
3406
+ output: t("versionInfo", state.cliVersion || t("versionUnknown"))
3541
3407
  };
3542
3408
  default:
3543
3409
  return {
3544
3410
  nextState: state,
3545
- output: `Unknown command: ${command}
3546
-
3547
- ${renderTuiHelp()}`
3411
+ output: t("unknownCommand", command) + renderTuiHelp()
3548
3412
  };
3549
3413
  }
3550
3414
  }
@@ -3562,19 +3426,23 @@ function brightnessFromRgb(r, g, b) {
3562
3426
  const luma = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
3563
3427
  return luma >= 0.5 ? "light" : "dark";
3564
3428
  }
3565
- function parseOsc11Reply(reply) {
3429
+ function parseOsc11Background(reply) {
3566
3430
  const match = reply.match(OSC11_REPLY_RE);
3567
3431
  if (!match) return null;
3568
- return brightnessFromRgb(
3432
+ const channels = [
3569
3433
  componentToByte(match[1]),
3570
3434
  componentToByte(match[2]),
3571
3435
  componentToByte(match[3])
3572
- );
3436
+ ];
3437
+ return {
3438
+ brightness: brightnessFromRgb(channels[0], channels[1], channels[2]),
3439
+ hex: channels.map((v) => v.toString(16).padStart(2, "0").toUpperCase()).join("")
3440
+ };
3573
3441
  }
3574
3442
  function isTerminalDevice(stream) {
3575
3443
  return stream instanceof ReadStream;
3576
3444
  }
3577
- async function detectTerminalBrightness(args = {}) {
3445
+ async function detectTerminalBackground(args = {}) {
3578
3446
  const stdin = args.stdin ?? process.stdin;
3579
3447
  const stdout = args.stdout ?? process.stdout;
3580
3448
  const timeoutMs = args.timeoutMs ?? 100;
@@ -3601,7 +3469,7 @@ async function detectTerminalBrightness(args = {}) {
3601
3469
  };
3602
3470
  const onData = (chunk) => {
3603
3471
  buffer += chunk.toString("latin1");
3604
- const parsed = parseOsc11Reply(buffer);
3472
+ const parsed = parseOsc11Background(buffer);
3605
3473
  if (parsed) finish(parsed);
3606
3474
  else if (buffer.length > 256) finish(null);
3607
3475
  };
@@ -3945,7 +3813,7 @@ function buildHistoryLines(history, contentWidth) {
3945
3813
  const reset = "\x1B[39m";
3946
3814
  return `${accent}\u276F${reset} ${content}`;
3947
3815
  }
3948
- const highlighted = highlightMarkdown(content, colorEnabled);
3816
+ const highlighted = colorEnabled ? formatAssistantDisplay(content) : stripAnsi(formatAssistantDisplay(content));
3949
3817
  const rawLines = highlighted.split("\n");
3950
3818
  const styledLines = rawLines.map((line, idx) => {
3951
3819
  if (idx === 0 && !line.startsWith("[nolo]")) {
@@ -4072,6 +3940,30 @@ function applyScrollAction(history, action, output, inputLines) {
4072
3940
  }
4073
3941
 
4074
3942
  // packages/cli/tui/tuiRawInput.ts
3943
+ function normalizePasteNewlines(text) {
3944
+ return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
3945
+ }
3946
+ var altScreenOn = /* @__PURE__ */ new WeakMap();
3947
+ function outputIsTty2(output) {
3948
+ return Boolean(output.isTTY);
3949
+ }
3950
+ function enterAltScreen(output) {
3951
+ if (!outputIsTty2(output)) return false;
3952
+ if (altScreenOn.get(output)) return false;
3953
+ altScreenOn.set(output, true);
3954
+ output.write("\x1B[?1049h");
3955
+ return true;
3956
+ }
3957
+ function leaveAltScreen(output) {
3958
+ if (!outputIsTty2(output)) return false;
3959
+ if (!altScreenOn.get(output)) return false;
3960
+ altScreenOn.set(output, false);
3961
+ output.write("\x1B[?1049l");
3962
+ return true;
3963
+ }
3964
+ function isAltScreenOn(output) {
3965
+ return Boolean(altScreenOn.get(output));
3966
+ }
4075
3967
  function styleCollapsedPastePlaceholders(text, colorEnabled) {
4076
3968
  if (!colorEnabled || !text.includes("[paste #")) return text;
4077
3969
  COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
@@ -4102,6 +3994,8 @@ function createNoopFixedInput() {
4102
3994
  getInputLines: () => 1,
4103
3995
  isPaused: () => false,
4104
3996
  setMouseEnabled() {
3997
+ },
3998
+ setAltScreenEnabled() {
4105
3999
  }
4106
4000
  };
4107
4001
  }
@@ -4145,7 +4039,7 @@ function createFixedInput(output, config) {
4145
4039
  sections.push(fitAnsiLine(line.replace(/\r?\n/g, " "), cols));
4146
4040
  }
4147
4041
  const promptRaw = t("promptLabel");
4148
- const promptWidth = displayWidth2(promptRaw);
4042
+ const promptWidth = displayWidth(promptRaw);
4149
4043
  const prompt = colorEnabled ? `${themeColorSequence("accent")}${promptRaw}\x1B[39m` : promptRaw;
4150
4044
  const contentWidth = Math.max(1, cols - promptWidth);
4151
4045
  const logicalLines = buffer.length === 0 ? [""] : buffer.split("\n");
@@ -4181,7 +4075,7 @@ function createFixedInput(output, config) {
4181
4075
  if (targetPos <= charOffset + rowLen || j === rows.length - 1 && i === logicalLines.length - 1) {
4182
4076
  const subOffset = Math.max(0, Math.min(rowLen, targetPos - charOffset));
4183
4077
  const subStr = rowText.slice(0, subOffset);
4184
- cursorCol = promptWidth + displayWidth2(subStr);
4078
+ cursorCol = promptWidth + displayWidth(subStr);
4185
4079
  cursorRow = inputRows;
4186
4080
  cursorFound = true;
4187
4081
  }
@@ -4198,10 +4092,15 @@ function createFixedInput(output, config) {
4198
4092
  };
4199
4093
  const repaintAt = (buffer, cursorPos) => {
4200
4094
  const { text, lines, cursorCol, cursorRow } = renderInputArea(buffer, cursorPos);
4095
+ let linesChanged = false;
4201
4096
  if (lines !== inputLines) {
4202
4097
  inputLines = lines;
4098
+ linesChanged = true;
4203
4099
  }
4204
4100
  setScrollRegion(inputLines);
4101
+ if (linesChanged) {
4102
+ config.onInputLinesChange?.(inputLines);
4103
+ }
4205
4104
  const startRow = getRows() - inputLines + 1;
4206
4105
  write(`\x1B[${startRow};1H`);
4207
4106
  write("\x1B[J");
@@ -4249,8 +4148,7 @@ function createFixedInput(output, config) {
4249
4148
  disable() {
4250
4149
  disableMouse();
4251
4150
  resetScrollRegion();
4252
- const rows = getRows();
4253
- write(`\x1B[${rows};1H\x1B[2K\x1B[${Math.max(1, rows - 1)};1H`);
4151
+ leaveAltScreen(output);
4254
4152
  },
4255
4153
  getInputLines: () => inputLines,
4256
4154
  isPaused: () => paused,
@@ -4261,6 +4159,13 @@ function createFixedInput(output, config) {
4261
4159
  } else {
4262
4160
  write("\x1B[?1000l\x1B[?1006l");
4263
4161
  }
4162
+ },
4163
+ setAltScreenEnabled(enabled) {
4164
+ if (enabled) {
4165
+ enterAltScreen(output);
4166
+ } else {
4167
+ leaveAltScreen(output);
4168
+ }
4264
4169
  }
4265
4170
  };
4266
4171
  }
@@ -4310,9 +4215,27 @@ function isIncompleteTail(input, start) {
4310
4215
  }
4311
4216
  return false;
4312
4217
  }
4313
- var PASTE_START = "\x1B[?2004h";
4314
- var PASTE_END = "\x1B[?2004l";
4315
- function splitRawInputWithTail(input) {
4218
+ var PASTE_START = "\x1B[200~";
4219
+ var PASTE_END = "\x1B[201~";
4220
+ function findBracketedPasteEnd(input, contentStart) {
4221
+ return input.indexOf(PASTE_END, contentStart);
4222
+ }
4223
+ function emitPlainRunAsTokens(run) {
4224
+ if (run.length === 0) return [];
4225
+ if (shouldCollapsePaste(normalizePasteNewlines(run))) {
4226
+ return [`${PASTE_TOKEN_PREFIX}${run}`];
4227
+ }
4228
+ const tokens = [];
4229
+ for (let index = 0; index < run.length; ) {
4230
+ const codePoint = run.codePointAt(index);
4231
+ if (codePoint === void 0) break;
4232
+ const value = String.fromCodePoint(codePoint);
4233
+ tokens.push(value);
4234
+ index += value.length;
4235
+ }
4236
+ return tokens;
4237
+ }
4238
+ function splitRawInputWithTail(input, options) {
4316
4239
  const tokens = [];
4317
4240
  for (let index = 0; index < input.length; ) {
4318
4241
  if (isIncompleteTail(input, index)) {
@@ -4320,15 +4243,17 @@ function splitRawInputWithTail(input) {
4320
4243
  }
4321
4244
  if (input.startsWith(PASTE_START, index)) {
4322
4245
  const contentStart = index + PASTE_START.length;
4323
- const endPos = input.indexOf(PASTE_END, contentStart);
4246
+ const endPos = findBracketedPasteEnd(input, contentStart);
4324
4247
  if (endPos !== -1) {
4325
4248
  const payload = input.slice(contentStart, endPos);
4326
4249
  tokens.push(`${PASTE_TOKEN_PREFIX}${payload}`);
4327
4250
  index = endPos + PASTE_END.length;
4328
- } else {
4251
+ } else if (options?.forceCompleteOpenPaste) {
4329
4252
  const payload = input.slice(contentStart);
4330
4253
  tokens.push(`${PASTE_TOKEN_PREFIX}${payload}`);
4331
4254
  index = input.length;
4255
+ } else {
4256
+ return { tokens, tail: input.slice(index) };
4332
4257
  }
4333
4258
  continue;
4334
4259
  }
@@ -4353,63 +4278,121 @@ function splitRawInputWithTail(input) {
4353
4278
  index += csi.length;
4354
4279
  continue;
4355
4280
  }
4356
- const codePoint = input.codePointAt(index);
4357
- if (codePoint === void 0) break;
4358
- const value = String.fromCodePoint(codePoint);
4359
- tokens.push(value);
4360
- index += value.length;
4281
+ const nextEsc = input.indexOf("\x1B", index);
4282
+ const runEnd = nextEsc === -1 ? input.length : nextEsc;
4283
+ const run = input.slice(index, runEnd);
4284
+ if (run.length === 0) {
4285
+ const codePoint = input.codePointAt(index);
4286
+ if (codePoint === void 0) break;
4287
+ const value = String.fromCodePoint(codePoint);
4288
+ tokens.push(value);
4289
+ index += value.length;
4290
+ continue;
4291
+ }
4292
+ tokens.push(...emitPlainRunAsTokens(run));
4293
+ index = runEnd;
4361
4294
  }
4362
4295
  return { tokens, tail: "" };
4363
4296
  }
4364
4297
  function splitRawInput(input) {
4365
- const { tokens, tail } = splitRawInputWithTail(input);
4298
+ const { tokens, tail } = splitRawInputWithTail(input, {
4299
+ forceCompleteOpenPaste: true
4300
+ });
4366
4301
  if (!tail) return tokens;
4367
- const tailTokens = [];
4368
- for (let index = 0; index < tail.length; ) {
4369
- const codePoint = tail.codePointAt(index);
4370
- if (codePoint === void 0) break;
4371
- const value = String.fromCodePoint(codePoint);
4372
- tailTokens.push(value);
4373
- index += value.length;
4374
- }
4375
- return [...tokens, ...tailTokens];
4302
+ return [...tokens, ...emitPlainRunAsTokens(tail)];
4376
4303
  }
4377
4304
  function createRawInputDecoder(onToken, options) {
4378
4305
  const decoder = new TextDecoder("utf-8", { fatal: false, ignoreBOM: true });
4379
4306
  let pendingBuffer = "";
4380
4307
  let timer = null;
4381
4308
  const timeoutMs = options?.escTimeoutMs ?? 15;
4309
+ const unmarkedPasteDebounceMs = options?.unmarkedPasteDebounceMs ?? 40;
4382
4310
  const clearTimer = () => {
4383
4311
  if (timer !== null) {
4384
4312
  clearTimeout(timer);
4385
4313
  timer = null;
4386
4314
  }
4387
4315
  };
4388
- const flush = () => {
4316
+ const emitCodePoints = (text) => {
4317
+ for (let index = 0; index < text.length; ) {
4318
+ const codePoint = text.codePointAt(index);
4319
+ if (codePoint === void 0) break;
4320
+ const value = String.fromCodePoint(codePoint);
4321
+ onToken(value);
4322
+ index += value.length;
4323
+ }
4324
+ };
4325
+ const flushPlainPending = () => {
4389
4326
  clearTimer();
4390
- if (pendingBuffer.length > 0) {
4391
- const textToFlush = pendingBuffer;
4392
- pendingBuffer = "";
4393
- for (const token of splitRawInput(textToFlush)) {
4394
- onToken(token);
4395
- }
4327
+ if (pendingBuffer.length === 0) return;
4328
+ const text = pendingBuffer;
4329
+ pendingBuffer = "";
4330
+ for (const token of emitPlainRunAsTokens(text)) {
4331
+ onToken(token);
4332
+ }
4333
+ };
4334
+ const flushEscPending = (forceCompleteOpenPaste) => {
4335
+ clearTimer();
4336
+ if (pendingBuffer.length === 0) return;
4337
+ const textToFlush = pendingBuffer;
4338
+ pendingBuffer = "";
4339
+ const { tokens, tail } = splitRawInputWithTail(textToFlush, {
4340
+ forceCompleteOpenPaste
4341
+ });
4342
+ for (const token of tokens) {
4343
+ onToken(token);
4344
+ }
4345
+ if (!tail) return;
4346
+ if (forceCompleteOpenPaste) {
4347
+ emitCodePoints(tail);
4348
+ return;
4396
4349
  }
4350
+ pendingBuffer = tail;
4397
4351
  };
4398
4352
  const decodeFn = (chunk) => {
4399
4353
  clearTimer();
4400
4354
  const bytes = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
4401
4355
  const text = decoder.decode(bytes, { stream: true });
4402
4356
  pendingBuffer += text;
4403
- const { tokens, tail } = splitRawInputWithTail(pendingBuffer);
4404
- pendingBuffer = tail;
4405
- for (const token of tokens) {
4406
- onToken(token);
4357
+ if (pendingBuffer.startsWith(PASTE_START)) {
4358
+ const endPos = findBracketedPasteEnd(
4359
+ pendingBuffer,
4360
+ PASTE_START.length
4361
+ );
4362
+ if (endPos === -1) return;
4363
+ const { tokens, tail } = splitRawInputWithTail(pendingBuffer);
4364
+ pendingBuffer = tail;
4365
+ for (const token of tokens) onToken(token);
4366
+ if (pendingBuffer.startsWith(PASTE_START)) return;
4367
+ }
4368
+ if (pendingBuffer.includes("\x1B")) {
4369
+ const { tokens, tail } = splitRawInputWithTail(pendingBuffer);
4370
+ pendingBuffer = tail;
4371
+ for (const token of tokens) onToken(token);
4372
+ if (pendingBuffer.startsWith(PASTE_START)) return;
4373
+ if (pendingBuffer.length > 0) {
4374
+ timer = setTimeout(() => flushEscPending(true), timeoutMs);
4375
+ }
4376
+ return;
4377
+ }
4378
+ if (shouldCollapsePaste(normalizePasteNewlines(pendingBuffer))) {
4379
+ timer = setTimeout(flushPlainPending, unmarkedPasteDebounceMs);
4380
+ return;
4407
4381
  }
4408
- if (pendingBuffer.length > 0) {
4409
- timer = setTimeout(flush, timeoutMs);
4382
+ if (!pendingBuffer.includes("\n") && !pendingBuffer.includes("\r")) {
4383
+ emitCodePoints(pendingBuffer);
4384
+ pendingBuffer = "";
4385
+ return;
4410
4386
  }
4387
+ timer = setTimeout(flushPlainPending, unmarkedPasteDebounceMs);
4388
+ };
4389
+ decodeFn.flush = () => {
4390
+ if (pendingBuffer.startsWith(PASTE_START) || pendingBuffer.includes("\x1B")) {
4391
+ flushEscPending(true);
4392
+ return;
4393
+ }
4394
+ flushPlainPending();
4411
4395
  };
4412
- decodeFn.flush = flush;
4413
4396
  decodeFn.destroy = () => {
4414
4397
  clearTimer();
4415
4398
  pendingBuffer = "";
@@ -4419,12 +4402,66 @@ function createRawInputDecoder(onToken, options) {
4419
4402
 
4420
4403
  // packages/cli/tui/readlineWorkspace.ts
4421
4404
  var AGENTS_MD_MAX_BYTES = 8192;
4405
+ var altScreenRestoreOutput = null;
4406
+ var altScreenHandlersInstalled = false;
4407
+ var preExistingSignalListeners = {};
4408
+ var SIGNAL_EXIT_CODE = {
4409
+ SIGINT: 130,
4410
+ SIGTERM: 143,
4411
+ SIGHUP: 129
4412
+ };
4413
+ var restoreAltScreen = () => {
4414
+ try {
4415
+ if (altScreenRestoreOutput) leaveAltScreen(altScreenRestoreOutput);
4416
+ } catch {
4417
+ }
4418
+ };
4419
+ function installAltScreenRestoreHandlers(output) {
4420
+ altScreenRestoreOutput = output;
4421
+ if (altScreenHandlersInstalled) return;
4422
+ altScreenHandlersInstalled = true;
4423
+ process.on("exit", restoreAltScreen);
4424
+ for (const sig of ["SIGINT", "SIGTERM", "SIGHUP"]) {
4425
+ const existing = process.listeners(sig);
4426
+ preExistingSignalListeners[sig] = [...existing];
4427
+ const handler = () => {
4428
+ restoreAltScreen();
4429
+ const others = process.listeners(sig).filter((fn) => fn !== handler);
4430
+ if (others.length === 0) {
4431
+ process.exit(SIGNAL_EXIT_CODE[sig] ?? 128 + 1);
4432
+ return;
4433
+ }
4434
+ };
4435
+ process.prependListener(sig, handler);
4436
+ }
4437
+ process.on("uncaughtException", (err) => {
4438
+ restoreAltScreen();
4439
+ try {
4440
+ process.stderr.write(
4441
+ `uncaughtException: ${err?.stack ?? String(err)}
4442
+ `
4443
+ );
4444
+ } catch {
4445
+ }
4446
+ process.exit(1);
4447
+ });
4448
+ process.on("unhandledRejection", (reason) => {
4449
+ restoreAltScreen();
4450
+ try {
4451
+ const text = reason instanceof Error ? reason.stack ?? String(reason) : String(reason);
4452
+ process.stderr.write(`unhandledRejection: ${text}
4453
+ `);
4454
+ } catch {
4455
+ }
4456
+ process.exit(1);
4457
+ });
4458
+ }
4422
4459
  function readAgentsMdBlock(cwd) {
4423
4460
  for (const name of ["AGENTS.md", "CLAUDE.md"]) {
4424
- const filePath = join(cwd, name);
4425
- if (existsSync2(filePath)) {
4461
+ const filePath = join2(cwd, name);
4462
+ if (existsSync3(filePath)) {
4426
4463
  try {
4427
- let content = readFileSync(filePath, "utf8").trim();
4464
+ let content = readFileSync2(filePath, "utf8").trim();
4428
4465
  if (!content) continue;
4429
4466
  if (Buffer.byteLength(content, "utf8") > AGENTS_MD_MAX_BYTES) {
4430
4467
  content = Buffer.from(content, "utf8").subarray(0, AGENTS_MD_MAX_BYTES).toString("utf8") + "\n\n<!-- AGENTS.md truncated -->";
@@ -4539,6 +4576,18 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
4539
4576
  if (skillDiscoveryBlock) {
4540
4577
  extraContextBlocks.push(skillDiscoveryBlock);
4541
4578
  }
4579
+ const agentsMdMarker = "--- \u9879\u76EE\u6307\u4EE4\uFF08";
4580
+ const contextBlockScopes = [];
4581
+ for (const block of extraContextBlocks) {
4582
+ if (block.startsWith(agentsMdMarker)) {
4583
+ contextBlockScopes.push({ content: block, cacheScope: "session" });
4584
+ }
4585
+ }
4586
+ for (const block of extraContextBlocks) {
4587
+ if (!block.startsWith(agentsMdMarker)) {
4588
+ contextBlockScopes.push({ content: block, cacheScope: "turn" });
4589
+ }
4590
+ }
4542
4591
  const result = await agentRunner({
4543
4592
  agentName: effectiveAgentName,
4544
4593
  agentKey: effectiveAgentKey,
@@ -4559,9 +4608,17 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
4559
4608
  ...options.confirmDestructiveAction ? { confirmDestructiveAction: options.confirmDestructiveAction } : {},
4560
4609
  ...options.requestUserChoice ? { requestUserChoice: options.requestUserChoice } : {},
4561
4610
  ...options.abortSignal ? { abortSignal: options.abortSignal } : {},
4611
+ ...options.pastedTextStore?.items.size ? {
4612
+ pastedTextStore: options.pastedTextStore,
4613
+ localRuntimeAdapterFactory: (factoryEnv, factoryOptions) => createCliLocalRuntimeAdapter({
4614
+ env: factoryEnv,
4615
+ cwd: factoryOptions?.cwd ?? state.cwd,
4616
+ pastedTextStore: options.pastedTextStore
4617
+ })
4618
+ } : {},
4562
4619
  ...options.activityReporter ? { activityReporter: options.activityReporter } : {},
4563
4620
  ...skillAllowedTools !== void 0 ? { allowedToolNames: skillAllowedTools } : {},
4564
- ...extraContextBlocks.length > 0 ? { extraContextBlocks } : {}
4621
+ ...contextBlockScopes.length > 0 ? { contextBlockScopes } : {}
4565
4622
  });
4566
4623
  if (!continueId && result.dialogId && effectiveAgentKey !== state.agentKey) {
4567
4624
  autoRouteByDialog.set(result.dialogId, {
@@ -4569,7 +4626,14 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
4569
4626
  agentName: effectiveAgentName
4570
4627
  });
4571
4628
  }
4572
- return result;
4629
+ return {
4630
+ ...result,
4631
+ contextWindow: resolveAgentContextWindow({
4632
+ agentKey: effectiveAgentKey,
4633
+ agentName: effectiveAgentName,
4634
+ autoRouteDefault: env.NOLO_AUTO_ROUTE !== "0"
4635
+ })
4636
+ };
4573
4637
  }
4574
4638
  function waitForActionGate(rl, input, output, gate, spawnRunner) {
4575
4639
  const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
@@ -4755,13 +4819,18 @@ async function startTuiWorkspace(options) {
4755
4819
  const spawnRunner = options.spawnRunner ?? spawnProcess;
4756
4820
  const selfUpdater = options.selfUpdater ?? ((target) => runSelfUpdate({ output: target }));
4757
4821
  if (output.isTTY) {
4758
- output.write("\x1B[2J\x1B[3J\x1B[H");
4822
+ enterAltScreen(output);
4823
+ installAltScreenRestoreHandlers(output);
4824
+ output.write("\x1B[2J\x1B[H");
4759
4825
  }
4760
- const detected = await detectTerminalBrightness({
4826
+ const detected = await detectTerminalBackground({
4761
4827
  stdin: input,
4762
4828
  stdout: output
4763
4829
  });
4764
- if (detected) setActiveBrightness(detected);
4830
+ if (detected) {
4831
+ setActiveBrightness(detected.brightness);
4832
+ setActiveTerminalBaseHex(detected.hex);
4833
+ }
4765
4834
  const bannerColumns = output.columns;
4766
4835
  output.write(renderWelcome(state, 0, 0, bannerColumns));
4767
4836
  let fixedInput = createNoopFixedInput();
@@ -4769,9 +4838,14 @@ async function startTuiWorkspace(options) {
4769
4838
  let cursorPos = 0;
4770
4839
  const pasteStore = createCollapsedPasteStore();
4771
4840
  let activeTurnAbort = null;
4841
+ let forcedStop = false;
4842
+ let forcedStopEpoch = 0;
4843
+ let turnEpoch = 0;
4844
+ let activeTurnEpoch = 0;
4772
4845
  const activityIndicator = createActivityIndicator({
4773
4846
  isTurnActive: () => activeTurnAbort !== null,
4774
4847
  fallbackLabel: () => `${state.agentName} -> working`,
4848
+ stoppingLabel: () => t("turnStopping"),
4775
4849
  onRepaint: () => {
4776
4850
  if (fixedInput.active && !fixedInput.isPaused()) {
4777
4851
  output.write("\x1B[?2026h\x1B[?25l");
@@ -4831,9 +4905,16 @@ async function startTuiWorkspace(options) {
4831
4905
  paintSyncedFrame();
4832
4906
  }, 0);
4833
4907
  };
4908
+ let syncingLayout = false;
4834
4909
  const renderHistoryToOutput = () => {
4835
4910
  if (fixedInput.isPaused()) return;
4836
- renderHistory(output, history, fixedInput.getInputLines());
4911
+ if (syncingLayout) return;
4912
+ syncingLayout = true;
4913
+ try {
4914
+ renderHistory(output, history, fixedInput.getInputLines());
4915
+ } finally {
4916
+ syncingLayout = false;
4917
+ }
4837
4918
  };
4838
4919
  const readLatestAssistantReply = () => {
4839
4920
  const lastReply = [...history.turns].reverse().find((turn) => turn.role === "assistant")?.content;
@@ -4872,6 +4953,9 @@ ${t("copyViewHint")}
4872
4953
  };
4873
4954
  let modalOwnsKeyboard = false;
4874
4955
  const runOneAgentTurn = async (message, imageUrls, actionGateHandler, confirmDestructiveAction) => {
4956
+ forcedStop = false;
4957
+ turnEpoch += 1;
4958
+ const myEpoch = turnEpoch;
4875
4959
  history.followBottom = true;
4876
4960
  startTurn(history, "user");
4877
4961
  appendToCurrentTurn(history, message);
@@ -4901,6 +4985,7 @@ ${t("copyViewHint")}
4901
4985
  } : void 0;
4902
4986
  try {
4903
4987
  activeTurnAbort = new AbortController();
4988
+ activeTurnEpoch = myEpoch;
4904
4989
  const runResult = await runAgentChat(
4905
4990
  options.scriptDir,
4906
4991
  state,
@@ -4914,10 +4999,27 @@ ${t("copyViewHint")}
4914
4999
  ...confirmDestructiveAction ? { confirmDestructiveAction } : {},
4915
5000
  ...requestUserChoice ? { requestUserChoice } : {},
4916
5001
  abortSignal: activeTurnAbort.signal,
5002
+ pastedTextStore: pasteStore,
4917
5003
  explicitAgentSwitch,
4918
5004
  activityReporter
4919
5005
  }
4920
5006
  );
5007
+ const wasForceStopped = forcedStopEpoch === myEpoch;
5008
+ if (wasForceStopped) {
5009
+ if (runResult.dialogId || runResult.turnTokens) {
5010
+ const nextDialogKey = runResult.dialogId ? runResult.dialogId === state.dialogId && state.dialogKey ? state.dialogKey : state.dialogOwnerId ? `dialog-${state.dialogOwnerId}-${runResult.dialogId}` : void 0 : state.dialogKey;
5011
+ state = {
5012
+ ...state,
5013
+ ...runResult.dialogId ? {
5014
+ dialogId: runResult.dialogId,
5015
+ dialogKey: nextDialogKey,
5016
+ dialogLabel: runResult.dialogId
5017
+ } : {},
5018
+ ...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {}
5019
+ };
5020
+ }
5021
+ return { ok: false, aborted: true };
5022
+ }
4921
5023
  const wasAborted = activeTurnAbort.signal.aborted;
4922
5024
  activeTurnAbort = null;
4923
5025
  explicitAgentSwitch = false;
@@ -4928,9 +5030,13 @@ ${t("copyViewHint")}
4928
5030
  if (fixedInput.active) fixedInput.repaint(buffer);
4929
5031
  }
4930
5032
  if (wasAborted) {
4931
- emitCommandOutput(t("turnStopped"));
5033
+ if (runResult.pendingToolName) {
5034
+ emitCommandOutput(t("turnStoppedToolPending", runResult.pendingToolName));
5035
+ } else {
5036
+ emitCommandOutput(t("turnStopped"));
5037
+ }
4932
5038
  }
4933
- if (runResult.dialogId || runResult.turnTokens) {
5039
+ if (runResult.dialogId || runResult.turnTokens || runResult.contextWindow) {
4934
5040
  const nextDialogKey = runResult.dialogId ? runResult.dialogId === state.dialogId && state.dialogKey ? state.dialogKey : state.dialogOwnerId ? `dialog-${state.dialogOwnerId}-${runResult.dialogId}` : void 0 : state.dialogKey;
4935
5041
  state = {
4936
5042
  ...state,
@@ -4939,11 +5045,20 @@ ${t("copyViewHint")}
4939
5045
  dialogKey: nextDialogKey,
4940
5046
  dialogLabel: runResult.dialogId
4941
5047
  } : {},
4942
- ...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {}
5048
+ ...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {},
5049
+ ...runResult.contextWindow ? { contextWindow: runResult.contextWindow } : {}
4943
5050
  };
4944
5051
  }
4945
- if (!wasAborted && runResult.exitCode !== 0 && isQuotaExhaustedError(runResult.localError)) {
4946
- emitCommandOutput(t("quotaExhaustedHint"));
5052
+ if (!wasAborted && runResult.exitCode !== 0) {
5053
+ if (isBalanceExhaustedError(runResult.localError) && runResult.dialogId) {
5054
+ emitCommandOutput(t("balanceExhaustedHint"));
5055
+ } else if (isQuotaExhaustedError(runResult.localError)) {
5056
+ emitCommandOutput(t("quotaExhaustedHint"));
5057
+ } else if (runResult.dialogId) {
5058
+ emitCommandOutput(t("dialogPreservedHint"));
5059
+ } else {
5060
+ emitCommandOutput(t("dialogNotSavedHint"));
5061
+ }
4947
5062
  }
4948
5063
  return { ok: !wasAborted, aborted: wasAborted };
4949
5064
  } finally {
@@ -4998,6 +5113,7 @@ ${t("copyViewHint")}
4998
5113
  }
4999
5114
  if (result.action?.type === "exit") return true;
5000
5115
  if (result.action?.type === "clear") {
5116
+ clearCollapsedPasteStore(pasteStore);
5001
5117
  history.turns.length = 0;
5002
5118
  history.currentRole = null;
5003
5119
  history.currentContent = "";
@@ -5068,7 +5184,18 @@ ${t("copyViewHint")}
5068
5184
  ...state,
5069
5185
  agentName: pickResult.name,
5070
5186
  agentKey: pickResult.key,
5071
- contextWindow: getModelContextWindow(pickResult.name)
5187
+ contextWindow: resolveAgentContextWindow({
5188
+ agentKey: pickResult.key,
5189
+ agentName: pickResult.name,
5190
+ model: pickResult.model,
5191
+ autoRouteDefault: (options.env ?? process.env).NOLO_AUTO_ROUTE !== "0"
5192
+ }),
5193
+ estimatedContextTokens: estimateDefaultCliContextTokens({
5194
+ cwd: state.cwd,
5195
+ agentKey: pickResult.key,
5196
+ agentName: pickResult.name,
5197
+ model: pickResult.model
5198
+ })
5072
5199
  };
5073
5200
  if (state.dialogId) autoRouteByDialog.delete(state.dialogId);
5074
5201
  explicitAgentSwitch = true;
@@ -5100,6 +5227,16 @@ ${t("copyViewHint")}
5100
5227
  if (result.action?.type === "set-mouse") {
5101
5228
  fixedInput.setMouseEnabled(result.action.enabled);
5102
5229
  }
5230
+ if (result.action?.type === "set-altscreen") {
5231
+ if (result.action.enabled) {
5232
+ enterAltScreen(output);
5233
+ installAltScreenRestoreHandlers(output);
5234
+ } else {
5235
+ leaveAltScreen(output);
5236
+ }
5237
+ renderHistoryToOutput();
5238
+ fixedInput.repaint(buffer);
5239
+ }
5103
5240
  if (result.action?.type === "copy-view") {
5104
5241
  const opened = await openCopyView();
5105
5242
  if (!opened) emitCommandOutput(t("copyNothing"));
@@ -5143,14 +5280,7 @@ ${t("copyViewHint")}
5143
5280
  dialog: pickResult.dialog,
5144
5281
  env: options.env ?? process.env
5145
5282
  });
5146
- const restored = loadedTurns.slice(-MAX_TUI_HISTORY_TURNS).map(
5147
- (turn) => turn.role === "assistant" ? {
5148
- ...turn,
5149
- content: formatAssistantDisplay(
5150
- turn.content
5151
- )
5152
- } : turn
5153
- );
5283
+ const restored = loadedTurns.slice(-MAX_TUI_HISTORY_TURNS);
5154
5284
  history.turns.length = 0;
5155
5285
  history.turns.push(...restored);
5156
5286
  history.currentRole = null;
@@ -5164,6 +5294,7 @@ ${t("copyViewHint")}
5164
5294
  dialogLabel: pickResult.dialog.id,
5165
5295
  turnTokens: void 0
5166
5296
  };
5297
+ clearCollapsedPasteStore(pasteStore);
5167
5298
  emitCommandOutput(
5168
5299
  `${t("resumedDialogPrefix")}: ${pickResult.dialog.title} (${pickResult.dialog.id})`
5169
5300
  );
@@ -5323,6 +5454,9 @@ ${err.message}` : ""}`
5323
5454
  const oneLine = text.replace(/\r?\n/g, " \u23CE ");
5324
5455
  return dimCliText(` \u2937 ${i + 1}. ${oneLine}`, colorEnabled);
5325
5456
  });
5457
+ },
5458
+ onInputLinesChange: () => {
5459
+ renderHistoryToOutput();
5326
5460
  }
5327
5461
  });
5328
5462
  fixedInput.init();
@@ -5345,6 +5479,7 @@ ${err.message}` : ""}`
5345
5479
  const finish = () => {
5346
5480
  if (done) return;
5347
5481
  done = true;
5482
+ clearCollapsedPasteStore(pasteStore);
5348
5483
  resizeTarget.off?.("resize", onResize);
5349
5484
  input.off("data", onData);
5350
5485
  onData.destroy();
@@ -5372,10 +5507,25 @@ ${err.message}` : ""}`
5372
5507
  return;
5373
5508
  }
5374
5509
  if (busyLock && sequence === "\x1B" && activeTurnAbort) {
5510
+ if (activityIndicator.isStopping()) {
5511
+ forcedStop = true;
5512
+ forcedStopEpoch = activeTurnEpoch;
5513
+ activityIndicator.stop();
5514
+ activeTurnAbort.abort();
5515
+ activeTurnAbort = null;
5516
+ activeTurnEpoch = 0;
5517
+ busy = false;
5518
+ emitCommandOutput(t("forceStopped"));
5519
+ flushPendingRender();
5520
+ renderHistoryToOutput();
5521
+ if (fixedInput.active) fixedInput.repaint(buffer);
5522
+ return;
5523
+ }
5375
5524
  const stopBinding = chatQueueBinding;
5376
5525
  if (stopBinding && stopBinding.queueLength() > 0) {
5377
5526
  stopBinding.preemptForStop();
5378
5527
  }
5528
+ activityIndicator.markStopping();
5379
5529
  activeTurnAbort.abort();
5380
5530
  return;
5381
5531
  }
@@ -5402,7 +5552,10 @@ ${err.message}` : ""}`
5402
5552
  return;
5403
5553
  }
5404
5554
  if (result.submit !== void 0) {
5405
- const submittedText = expandCollapsedPastes(result.submit, pasteStore);
5555
+ const submittedText = replaceCollapsedPastesWithReferences(
5556
+ result.submit,
5557
+ pasteStore
5558
+ );
5406
5559
  if (busyLock) {
5407
5560
  const trimmedText = submittedText.trim();
5408
5561
  const busySlashCommand = trimmedText.split(/\s+/)[0]?.toLowerCase();
@@ -5427,7 +5580,7 @@ ${hint}` : hint;
5427
5580
  `);
5428
5581
  }
5429
5582
  }
5430
- clearCollapsedPasteStore(pasteStore);
5583
+ releaseCollapsedPasteReferences(submittedText, pasteStore);
5431
5584
  buffer = "";
5432
5585
  cursorPos2 = 0;
5433
5586
  if (fixedInput.active) fixedInput.repaint(buffer, cursorPos2);
@@ -5466,7 +5619,6 @@ ${hint}` : hint;
5466
5619
  isRunning: true
5467
5620
  });
5468
5621
  if (decision.kind === "queue-text") {
5469
- clearCollapsedPasteStore(pasteStore);
5470
5622
  binding.enqueue(decision.text);
5471
5623
  buffer = "";
5472
5624
  cursorPos2 = 0;
@@ -5541,7 +5693,6 @@ ${err.message}` : ""}`
5541
5693
  return;
5542
5694
  }
5543
5695
  }
5544
- clearCollapsedPasteStore(pasteStore);
5545
5696
  busy = true;
5546
5697
  buffer = "";
5547
5698
  cursorPos2 = 0;
@@ -5664,9 +5815,13 @@ export {
5664
5815
  createNoopFixedInput,
5665
5816
  createRawInputDecoder,
5666
5817
  createTurnHistory,
5667
- displayWidth2 as displayWidth,
5818
+ displayWidth,
5819
+ enterAltScreen,
5668
5820
  finalizeCurrentTurn,
5669
5821
  fitAnsiLine,
5822
+ installAltScreenRestoreHandlers,
5823
+ isAltScreenOn,
5824
+ leaveAltScreen,
5670
5825
  padOrTruncateToWidth,
5671
5826
  parseScrollAction,
5672
5827
  renderHistory,