nolo-cli 0.53.0-alpha.1 → 0.54.0-alpha.2
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.
- package/{_executeModel-36GKPAEZ.js → _executeModel-ANY4SIAS.js} +34 -35
- package/{action-IU6ON7ZB.js → action-Q4W5JPI5.js} +7 -7
- package/{addContentAction-5V5CCI3I.js → addContentAction-O25HFR37.js} +6 -6
- package/{addDialogAgentAction-KF3KZZNZ.js → addDialogAgentAction-GH7AUPPB.js} +5 -5
- package/{agentDeleteCommand-SBODEUPE.js → agentDeleteCommand-JWIKNWWI.js} +17 -17
- package/{agentEmailCommands-ME7BCY5S.js → agentEmailCommands-PL22BEU5.js} +39 -40
- package/{agentListCommands-QBWPKN5D.js → agentListCommands-6NR7AQEK.js} +19 -19
- package/{agentMachineCommands-KFFUPELZ.js → agentMachineCommands-TASPU6OA.js} +18 -18
- package/{agentRecordCommands-4BF6JIHS.js → agentRecordCommands-Z64TA63M.js} +38 -39
- package/{agentRunCommand-4MA7D6SV.js → agentRunCommand-4QJQLPRW.js} +39 -40
- package/{agentRuntimeLocal-RD52NPCG.js → agentRuntimeLocal-PCJJ56J2.js} +17 -17
- package/{agentSlice-AJABGQHU.js → agentSlice-KYLDUSNN.js} +6 -6
- package/{appDeleteCommands-I42NL3LP.js → appDeleteCommands-WLHMJAVT.js} +19 -19
- package/{appDeployCommands-CZWHXVPU.js → appDeployCommands-CKON7N2E.js} +19 -19
- package/{appDeployStatusCommands-PIQYXACM.js → appDeployStatusCommands-PXRLDASH.js} +19 -19
- package/{appGetCommands-CI2OWLT7.js → appGetCommands-RAB5RM4M.js} +19 -19
- package/{appListCommands-LWLSHPCP.js → appListCommands-GU57FB62.js} +19 -19
- package/{authCommand-WLWOEVYI.js → authCommand-QOPOEYEK.js} +7 -7
- package/{chatQueueReduxAdapter-V37RK3A6.js → chatQueueReduxAdapter-5O2WLITN.js} +16 -16
- package/chunk-2BWU4ORW.js +2574 -0
- package/{chunk-SG65C33A.js → chunk-32I5RVMY.js} +4 -4
- package/{chunk-X7S7OFUX.js → chunk-3QJTD6DO.js} +4 -4
- package/{chunk-CY5KIIPU.js → chunk-3Z3DXZBD.js} +12 -12
- package/{chunk-RO2IUWZE.js → chunk-4NN3EK7H.js} +1 -1
- package/{chunk-Y7TGWSUN.js → chunk-56W233KG.js} +1 -1
- package/{chunk-C2WF2OY7.js → chunk-5WADL4O7.js} +1 -1
- package/{chunk-QTH72J3N.js → chunk-6BGAQ3KR.js} +116 -23
- package/{chunk-67Q6IHM5.js → chunk-6FQ2552G.js} +142 -62
- package/{chunk-6XIE5ZGI.js → chunk-6HIGYUBQ.js} +1 -1
- package/{chunk-XPW6JLOB.js → chunk-6SZ52ORL.js} +8 -8
- package/{chunk-4ZL2KBI7.js → chunk-757BGY6Y.js} +1 -1
- package/{chunk-SQTVMYMU.js → chunk-7APQB6R6.js} +3 -3
- package/{chunk-QF27IZB3.js → chunk-7K5VMB4Q.js} +3 -3
- package/{chunk-V2IPBG5U.js → chunk-AA564GBL.js} +2 -2
- package/{chunk-76UA7376.js → chunk-AV6KQCM5.js} +6 -6
- package/{chunk-PGKZ2KGE.js → chunk-BJLYCOZK.js} +24 -24
- package/{chunk-VKSBVRGP.js → chunk-CVT7L2WZ.js} +1 -1
- package/{chunk-JVKFKKYN.js → chunk-D3JQPONH.js} +1 -1
- package/{chunk-KHCLMKZZ.js → chunk-EY7V7REW.js} +280 -6
- package/{chunk-4RXXP6WD.js → chunk-FGEYVPPR.js} +2 -2
- package/{chunk-AZ6DT2UD.js → chunk-GBADO3SM.js} +1 -1
- package/chunk-GLGD2JGY.js +1766 -0
- package/{chunk-POLE2QLO.js → chunk-GV35EHNA.js} +126 -59
- package/{chunk-HR5XDXYM.js → chunk-H4RYESI6.js} +3 -3
- package/{chunk-W3RZLXMA.js → chunk-IKTHA3JH.js} +2 -2
- package/{chunk-XB7ACJFH.js → chunk-INXBNYCG.js} +3 -3
- package/{chunk-F22JQTSX.js → chunk-KUUTWU4I.js} +3 -3
- package/{chunk-DFY6O64O.js → chunk-LA4IDAK7.js} +12 -12
- package/{chunk-IVKEJD7I.js → chunk-LN3OQJGG.js} +1 -1
- package/{chunk-YZ2WE6CW.js → chunk-MFI4FGHX.js} +2 -2
- package/{chunk-LGUQHYAL.js → chunk-O5FLGN2L.js} +3 -2
- package/{chunk-HCBQVVFZ.js → chunk-PAHILFNT.js} +1 -1
- package/{chunk-HHBXCRJS.js → chunk-PYKV6FSC.js} +1 -1
- package/{chunk-BO3YFOZR.js → chunk-QDHZCAH3.js} +1 -1
- package/{chunk-L3JWI7WX.js → chunk-QOKAKDPE.js} +15 -11
- package/{chunk-B54WOZ77.js → chunk-RTLJUGQH.js} +1 -1
- package/{chunk-Z7A54NFZ.js → chunk-RU5D3B22.js} +1 -1
- package/{chunk-JBL24PK6.js → chunk-SP3DPVBH.js} +2 -2
- package/{chunk-TZRB2I2M.js → chunk-TI5BCZCH.js} +18 -18
- package/{chunk-KOZ2G3ZG.js → chunk-U2A47SVI.js} +5 -5
- package/{chunk-3YVCM5PE.js → chunk-U5Z7LFZF.js} +1 -1
- package/{chunk-DIQCV4FR.js → chunk-UITMHBVK.js} +1 -1
- package/{chunk-H5QLIP6S.js → chunk-UW4INMD2.js} +2 -2
- package/{chunk-5SLTA66C.js → chunk-V4KZGLOI.js} +30 -30
- package/{chunk-AV4Z57LV.js → chunk-VRJUIUIY.js} +2 -2
- package/{chunk-5XCW6RQG.js → chunk-VRZIH5JO.js} +1 -1
- package/{chunk-2JYSSXLY.js → chunk-VULELK4T.js} +2 -2
- package/{chunk-VFN256RI.js → chunk-WL3UOGYO.js} +25 -0
- package/{chunk-PJASTA2U.js → chunk-Y7LNKP32.js} +3 -3
- package/{chunk-OZKJBDG4.js → chunk-YBV6QJKM.js} +14 -8
- package/{codingSkills-BYQI6EPT.js → codingSkills-BCQXRZOI.js} +3 -4
- package/{createAgentAutomationAction-5OZIWOK4.js → createAgentAutomationAction-UJLNFFFC.js} +17 -17
- package/{createDialogAction-334CHPJF.js → createDialogAction-TJCX6GUE.js} +20 -21
- package/{createPageAction-LXY22WTA.js → createPageAction-N3IYABHV.js} +18 -19
- package/{dbSlice-FWF5F4L7.js → dbSlice-D5CNGWPD.js} +5 -5
- package/{deleteFile-NPZ64DFN.js → deleteFile-44TUM34Y.js} +3 -3
- package/{dialogCommands-4MGUHAJI.js → dialogCommands-35M6RBAC.js} +18 -18
- package/{dialogSlice-76W7S3C4.js → dialogSlice-KO7ADD7H.js} +16 -16
- package/{docCreateCommands-346W5443.js → docCreateCommands-VXHZWQ3P.js} +20 -21
- package/{docDeleteCommands-FKEEPUUS.js → docDeleteCommands-4WFAJR6A.js} +20 -21
- package/{docReadCommands-AACI4DVO.js → docReadCommands-OYREEFAR.js} +20 -21
- package/{docStore-N7QTPHAX.js → docStore-5BU76DFK.js} +18 -18
- package/{docUpdateCommands-WHWVZ2XE.js → docUpdateCommands-A7QERSME.js} +20 -21
- package/{getPricing-JNOCWYDH.js → getPricing-HAU62AFM.js} +3 -3
- package/{handleSendMessageAction-EAXEX5AX.js → handleSendMessageAction-OSGQJQ45.js} +16 -16
- package/index.js +58 -58
- package/{machineCommands-XNWLQVTN.js → machineCommands-J43U3TX5.js} +38 -39
- package/{machineWsRunDispatch-56HWQ67L.js → machineWsRunDispatch-Z2Z6STXZ.js} +38 -39
- package/{models-N4NXQ44D.js → models-4QF4BJVY.js} +2 -2
- package/package.json +2 -3
- package/{read-J7RVVCHH.js → read-RGNPI5H2.js} +3 -3
- package/{readDocTool-G2WBM4IH.js → readDocTool-6ESWKTXD.js} +1 -1
- package/{readlineWorkspace-AXTB7DJC.js → readlineWorkspace-YRPV6JPN.js} +485 -222
- package/{removeDialogAgentAction-RMPISD42.js → removeDialogAgentAction-JYT73FU2.js} +7 -7
- package/{runAgentClientLoop-PU3R3UXA.js → runAgentClientLoop-5YM5WMAY.js} +32 -33
- package/{setDialogExtraReferencesAction-7BUTHDAL.js → setDialogExtraReferencesAction-D564LMYQ.js} +6 -6
- package/{setPrimaryDialogAgentAction-WCYIBGZ4.js → setPrimaryDialogAgentAction-ACY3BLYA.js} +7 -7
- package/{settingSlice-7NN2MI6Y.js → settingSlice-MKI3MNZJ.js} +6 -6
- package/{skillDiscovery-COX56OBO.js → skillDiscovery-GPUDHDTZ.js} +1 -2
- package/{spaceCommands-JYI3X4N2.js → spaceCommands-MY26V52L.js} +17 -17
- package/{spaceSlice-ERZ3RGWC.js → spaceSlice-JUIXC365.js} +17 -17
- package/{streamAgentChatTurn-2IH4MTQC.js → streamAgentChatTurn-XV5X5TNQ.js} +36 -37
- package/{switchDialogAgentAction-WGMMQHDI.js → switchDialogAgentAction-CJ5H6SAR.js} +5 -5
- package/{tableCommands-P2TXJ3CF.js → tableCommands-R6WFRDYF.js} +1 -1
- package/{tools-DJUTQEMP.js → tools-MIMELA2Y.js} +27 -28
- package/{tuiSummaryLlmCaller-U4EGD2SX.js → tuiSummaryLlmCaller-XJ5BKNNS.js} +12 -12
- package/{updateDialogTitleAction-OVOPGTC3.js → updateDialogTitleAction-EIZUSWHR.js} +17 -17
- package/chunk-AETZ7AD6.js +0 -274
- package/chunk-EUG45QJR.js +0 -6104
- package/chunk-OFZPJ3NT.js +0 -114
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
normalizeDialogRecord,
|
|
4
4
|
readDialogSnapshot,
|
|
5
5
|
sortDialogs
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-GLGD2JGY.js";
|
|
7
7
|
import {
|
|
8
8
|
ANSI_ESCAPE_REGEX,
|
|
9
9
|
COLLAPSED_PASTE_PLACEHOLDER_RE,
|
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
fitAnsiLine,
|
|
26
26
|
formatAssistantDisplay,
|
|
27
27
|
formatTokenCount,
|
|
28
|
-
getActiveDensity,
|
|
29
28
|
getActiveThemeMode,
|
|
30
29
|
getActiveThemeName,
|
|
31
30
|
isBalanceExhaustedError,
|
|
@@ -46,7 +45,6 @@ import {
|
|
|
46
45
|
resolveTuiThemeMode,
|
|
47
46
|
runAgentTurn,
|
|
48
47
|
setActiveBrightness,
|
|
49
|
-
setActiveDensity,
|
|
50
48
|
setActiveThemeMode,
|
|
51
49
|
setActiveThemeName,
|
|
52
50
|
setMathRenderingEnabled,
|
|
@@ -64,14 +62,14 @@ import {
|
|
|
64
62
|
wrapTextToLines,
|
|
65
63
|
wrapTranscriptLine,
|
|
66
64
|
wrapTranscriptLineWithLayout
|
|
67
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-6FQ2552G.js";
|
|
68
66
|
import {
|
|
69
67
|
listFavoriteAgentIdsAcrossServers,
|
|
70
68
|
listLocalCachedAgents,
|
|
71
69
|
listRemoteAgents,
|
|
72
70
|
listRemoteAgentsAcrossServers,
|
|
73
71
|
normalizeListedAgent
|
|
74
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-5WADL4O7.js";
|
|
75
73
|
import "./chunk-ID4G2MAR.js";
|
|
76
74
|
import {
|
|
77
75
|
listUserRecordsFromServers,
|
|
@@ -86,8 +84,8 @@ import {
|
|
|
86
84
|
readTimestamp,
|
|
87
85
|
setCliLocale,
|
|
88
86
|
t
|
|
89
|
-
} from "./chunk-
|
|
90
|
-
import "./chunk-
|
|
87
|
+
} from "./chunk-GV35EHNA.js";
|
|
88
|
+
import "./chunk-U5Z7LFZF.js";
|
|
91
89
|
import "./chunk-EADNWBAZ.js";
|
|
92
90
|
import "./chunk-NI2BS6UD.js";
|
|
93
91
|
import {
|
|
@@ -113,21 +111,21 @@ import {
|
|
|
113
111
|
import "./chunk-ESHYE7WU.js";
|
|
114
112
|
import "./chunk-JBTJAPUF.js";
|
|
115
113
|
import "./chunk-LTRXGFMS.js";
|
|
116
|
-
import "./chunk-
|
|
114
|
+
import "./chunk-4NN3EK7H.js";
|
|
117
115
|
import "./chunk-ATNTHIZI.js";
|
|
118
116
|
import "./chunk-JEXVIMYZ.js";
|
|
119
117
|
import {
|
|
120
118
|
prepareTools
|
|
121
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-UW4INMD2.js";
|
|
122
120
|
import "./chunk-HS7MLR74.js";
|
|
123
|
-
import "./chunk-
|
|
124
|
-
import "./chunk-
|
|
121
|
+
import "./chunk-757BGY6Y.js";
|
|
122
|
+
import "./chunk-V4KZGLOI.js";
|
|
125
123
|
import "./chunk-5XTOKQLW.js";
|
|
126
124
|
import "./chunk-NF64D32W.js";
|
|
127
125
|
import "./chunk-3L2WKC3W.js";
|
|
128
|
-
import "./chunk-
|
|
126
|
+
import "./chunk-RU5D3B22.js";
|
|
129
127
|
import "./chunk-KQHGZWSV.js";
|
|
130
|
-
import "./chunk-
|
|
128
|
+
import "./chunk-VRZIH5JO.js";
|
|
131
129
|
import {
|
|
132
130
|
clipText,
|
|
133
131
|
formatDuration,
|
|
@@ -140,9 +138,9 @@ import {
|
|
|
140
138
|
shortRunId
|
|
141
139
|
} from "./chunk-KXKQO4Q6.js";
|
|
142
140
|
import "./chunk-INZZJSQF.js";
|
|
143
|
-
import "./chunk-
|
|
141
|
+
import "./chunk-Y7LNKP32.js";
|
|
144
142
|
import "./chunk-BANYWEYY.js";
|
|
145
|
-
import "./chunk-
|
|
143
|
+
import "./chunk-PAHILFNT.js";
|
|
146
144
|
import "./chunk-MEYIRKDN.js";
|
|
147
145
|
import "./chunk-63W5N6P3.js";
|
|
148
146
|
import "./chunk-VF4K2QE6.js";
|
|
@@ -151,17 +149,17 @@ import {
|
|
|
151
149
|
createTurnRequest,
|
|
152
150
|
normalizeRunCompletionShape
|
|
153
151
|
} from "./chunk-YPREESF4.js";
|
|
154
|
-
import "./chunk-
|
|
155
|
-
import "./chunk-
|
|
152
|
+
import "./chunk-6SZ52ORL.js";
|
|
153
|
+
import "./chunk-LA4IDAK7.js";
|
|
156
154
|
import {
|
|
157
155
|
extractReferenceKeysFromMessage
|
|
158
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-BJLYCOZK.js";
|
|
159
157
|
import "./chunk-EVBFYPDC.js";
|
|
160
158
|
import "./chunk-H2G6JXTR.js";
|
|
161
159
|
import "./chunk-YYLHWIW6.js";
|
|
162
|
-
import "./chunk-
|
|
160
|
+
import "./chunk-U2A47SVI.js";
|
|
163
161
|
import "./chunk-AGGIDPCZ.js";
|
|
164
|
-
import "./chunk-
|
|
162
|
+
import "./chunk-32I5RVMY.js";
|
|
165
163
|
import "./chunk-5RGU3J7P.js";
|
|
166
164
|
import "./chunk-M76ECQRD.js";
|
|
167
165
|
import "./chunk-MRWGHF56.js";
|
|
@@ -171,22 +169,21 @@ import "./chunk-GLKOYSRU.js";
|
|
|
171
169
|
import {
|
|
172
170
|
buildSkillDiscoveryContextBlock,
|
|
173
171
|
buildSkillDiscoveryContextLayer
|
|
174
|
-
} from "./chunk-
|
|
175
|
-
import "./chunk-
|
|
172
|
+
} from "./chunk-2BWU4ORW.js";
|
|
173
|
+
import "./chunk-AA564GBL.js";
|
|
176
174
|
import {
|
|
177
175
|
expandEnabledPacks
|
|
178
|
-
} from "./chunk-
|
|
179
|
-
import "./chunk-
|
|
180
|
-
import "./chunk-KHCLMKZZ.js";
|
|
176
|
+
} from "./chunk-O5FLGN2L.js";
|
|
177
|
+
import "./chunk-EY7V7REW.js";
|
|
181
178
|
import {
|
|
182
179
|
buildLocalWorkspaceOpenAiTools,
|
|
183
180
|
buildLocalWorkspaceToolset,
|
|
184
181
|
getProcessRegistry,
|
|
185
182
|
readCommandActionGatePayload
|
|
186
|
-
} from "./chunk-
|
|
187
|
-
import "./chunk-
|
|
183
|
+
} from "./chunk-6BGAQ3KR.js";
|
|
184
|
+
import "./chunk-INXBNYCG.js";
|
|
188
185
|
import "./chunk-ZNFJWEN4.js";
|
|
189
|
-
import "./chunk-
|
|
186
|
+
import "./chunk-CVT7L2WZ.js";
|
|
190
187
|
import "./chunk-T27IEBNQ.js";
|
|
191
188
|
import "./chunk-N7J63Q6C.js";
|
|
192
189
|
import {
|
|
@@ -194,11 +191,11 @@ import {
|
|
|
194
191
|
buildIdentityBlock,
|
|
195
192
|
buildRuntimeGuidanceBlocks,
|
|
196
193
|
resolveToolGuidedSections
|
|
197
|
-
} from "./chunk-
|
|
194
|
+
} from "./chunk-YBV6QJKM.js";
|
|
198
195
|
import "./chunk-6BYAXNH5.js";
|
|
199
196
|
import {
|
|
200
197
|
resolvePlatformAuthToken
|
|
201
|
-
} from "./chunk-
|
|
198
|
+
} from "./chunk-SP3DPVBH.js";
|
|
202
199
|
import "./chunk-TNPCQNGQ.js";
|
|
203
200
|
import {
|
|
204
201
|
isQuotaExhaustedError
|
|
@@ -207,7 +204,7 @@ import "./chunk-2MBTWINN.js";
|
|
|
207
204
|
import {
|
|
208
205
|
DEFAULT_CONTEXT_WINDOW,
|
|
209
206
|
getModelContextWindow
|
|
210
|
-
} from "./chunk-
|
|
207
|
+
} from "./chunk-KUUTWU4I.js";
|
|
211
208
|
import {
|
|
212
209
|
buildCompactionMetricsFromPlan,
|
|
213
210
|
buildCompactionUserContent,
|
|
@@ -218,11 +215,11 @@ import {
|
|
|
218
215
|
formatMessagesForSummaryWithTruncation,
|
|
219
216
|
planCompression,
|
|
220
217
|
serializeMessageContent
|
|
221
|
-
} from "./chunk-
|
|
222
|
-
import "./chunk-
|
|
218
|
+
} from "./chunk-H4RYESI6.js";
|
|
219
|
+
import "./chunk-VRJUIUIY.js";
|
|
223
220
|
import "./chunk-NQ4N4IGO.js";
|
|
224
221
|
import "./chunk-FD36SCCD.js";
|
|
225
|
-
import "./chunk-
|
|
222
|
+
import "./chunk-QDHZCAH3.js";
|
|
226
223
|
import {
|
|
227
224
|
compactWhitespace
|
|
228
225
|
} from "./chunk-DWLEOOGR.js";
|
|
@@ -268,19 +265,19 @@ import {
|
|
|
268
265
|
import {
|
|
269
266
|
DEFAULT_NOLO_SERVER_URL
|
|
270
267
|
} from "./chunk-OLZBQWZU.js";
|
|
271
|
-
import "./chunk-
|
|
272
|
-
import "./chunk-
|
|
273
|
-
import "./chunk-
|
|
274
|
-
import "./chunk-
|
|
268
|
+
import "./chunk-56W233KG.js";
|
|
269
|
+
import "./chunk-WL3UOGYO.js";
|
|
270
|
+
import "./chunk-7APQB6R6.js";
|
|
271
|
+
import "./chunk-3QJTD6DO.js";
|
|
275
272
|
import "./chunk-Y5GCAMGP.js";
|
|
276
273
|
import "./chunk-UZ6XXCVR.js";
|
|
277
274
|
import "./chunk-KX6YBIHG.js";
|
|
278
|
-
import "./chunk-
|
|
279
|
-
import "./chunk-
|
|
275
|
+
import "./chunk-FGEYVPPR.js";
|
|
276
|
+
import "./chunk-AV6KQCM5.js";
|
|
280
277
|
import "./chunk-SVEUG45B.js";
|
|
281
278
|
import "./chunk-WWC7I6TA.js";
|
|
282
279
|
import "./chunk-I42VC5KR.js";
|
|
283
|
-
import "./chunk-
|
|
280
|
+
import "./chunk-MFI4FGHX.js";
|
|
284
281
|
import {
|
|
285
282
|
asTrimmedLowercaseString
|
|
286
283
|
} from "./chunk-QSJ3HFEF.js";
|
|
@@ -289,13 +286,13 @@ import {
|
|
|
289
286
|
BUILTIN_NOLO_AGENT_MODEL,
|
|
290
287
|
BUILTIN_NOLO_AGENT_NAME,
|
|
291
288
|
builtinAgentCatalogEntryById
|
|
292
|
-
} from "./chunk-
|
|
289
|
+
} from "./chunk-VULELK4T.js";
|
|
293
290
|
import {
|
|
294
291
|
extractCustomId,
|
|
295
292
|
parsePublicAgentId
|
|
296
293
|
} from "./chunk-BJIRLHJR.js";
|
|
297
|
-
import "./chunk-
|
|
298
|
-
import "./chunk-
|
|
294
|
+
import "./chunk-PYKV6FSC.js";
|
|
295
|
+
import "./chunk-QOKAKDPE.js";
|
|
299
296
|
import "./chunk-OW765XBU.js";
|
|
300
297
|
import "./chunk-GBRG75BQ.js";
|
|
301
298
|
import "./chunk-KUG52IAP.js";
|
|
@@ -624,9 +621,9 @@ function createRawKeyReader(input) {
|
|
|
624
621
|
};
|
|
625
622
|
const resolveWaiter = (value) => {
|
|
626
623
|
if (!waiter) return;
|
|
627
|
-
const
|
|
624
|
+
const resolve4 = waiter;
|
|
628
625
|
waiter = null;
|
|
629
|
-
|
|
626
|
+
resolve4(value);
|
|
630
627
|
};
|
|
631
628
|
const tryDeliver = () => {
|
|
632
629
|
if (!waiter) return;
|
|
@@ -683,12 +680,12 @@ function createRawKeyReader(input) {
|
|
|
683
680
|
input.on("close", onClose);
|
|
684
681
|
input.on("end", onClose);
|
|
685
682
|
input.resume?.();
|
|
686
|
-
const reader = () => new Promise((
|
|
683
|
+
const reader = () => new Promise((resolve4) => {
|
|
687
684
|
if (closed) {
|
|
688
|
-
|
|
685
|
+
resolve4(drainClosed());
|
|
689
686
|
return;
|
|
690
687
|
}
|
|
691
|
-
waiter =
|
|
688
|
+
waiter = resolve4;
|
|
692
689
|
tryDeliver();
|
|
693
690
|
});
|
|
694
691
|
reader.dispose = () => {
|
|
@@ -1385,9 +1382,9 @@ function layoutTurnRows(role, content, contentWidth, colorEnabled, command) {
|
|
|
1385
1382
|
}
|
|
1386
1383
|
return rows.length > 0 ? rows : [{ rendered: "", sourceStart: 0, sourceEnd: 0, prefixWidth: 0 }];
|
|
1387
1384
|
}
|
|
1388
|
-
function getTurnLayoutRows(turn, contentWidth, colorEnabled,
|
|
1385
|
+
function getTurnLayoutRows(turn, contentWidth, colorEnabled, themeFingerprint) {
|
|
1389
1386
|
const cached = getCachedTurnLine(turn);
|
|
1390
|
-
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.
|
|
1387
|
+
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.themeFingerprint === themeFingerprint) {
|
|
1391
1388
|
return cached.layoutRows;
|
|
1392
1389
|
}
|
|
1393
1390
|
const layoutRows = layoutTurnRows(turn.role, turn.content, contentWidth, colorEnabled, turn.command);
|
|
@@ -1395,7 +1392,6 @@ function getTurnLayoutRows(turn, contentWidth, colorEnabled, density, themeFinge
|
|
|
1395
1392
|
setCachedTurnLine(turn, {
|
|
1396
1393
|
width: contentWidth,
|
|
1397
1394
|
color: colorEnabled,
|
|
1398
|
-
density,
|
|
1399
1395
|
themeFingerprint,
|
|
1400
1396
|
lines,
|
|
1401
1397
|
layoutRows
|
|
@@ -1450,8 +1446,8 @@ function renderTailTurnBlock(role, content, contentWidth, colorEnabled) {
|
|
|
1450
1446
|
return lines;
|
|
1451
1447
|
}
|
|
1452
1448
|
}
|
|
1453
|
-
function getStreamingTurnLines(role, content, contentWidth, colorEnabled,
|
|
1454
|
-
if (streamingTurnCache && (streamingTurnCache.role !== role || streamingTurnCache.contentWidth !== contentWidth || streamingTurnCache.colorEnabled !== colorEnabled || streamingTurnCache.
|
|
1449
|
+
function getStreamingTurnLines(role, content, contentWidth, colorEnabled, themeFingerprint) {
|
|
1450
|
+
if (streamingTurnCache && (streamingTurnCache.role !== role || streamingTurnCache.contentWidth !== contentWidth || streamingTurnCache.colorEnabled !== colorEnabled || streamingTurnCache.themeFingerprint !== themeFingerprint || !content.startsWith(streamingTurnCache.fullContent.slice(0, streamingTurnCache.prefixLength)))) {
|
|
1455
1451
|
streamingTurnCache = null;
|
|
1456
1452
|
}
|
|
1457
1453
|
if (!streamingTurnCache) {
|
|
@@ -1459,7 +1455,6 @@ function getStreamingTurnLines(role, content, contentWidth, colorEnabled, densit
|
|
|
1459
1455
|
role,
|
|
1460
1456
|
contentWidth,
|
|
1461
1457
|
colorEnabled,
|
|
1462
|
-
density,
|
|
1463
1458
|
themeFingerprint,
|
|
1464
1459
|
fullContent: content,
|
|
1465
1460
|
prefixLength: 0,
|
|
@@ -1513,12 +1508,11 @@ function countTurnLines(role, content, contentWidth, command) {
|
|
|
1513
1508
|
return layoutTurnRows(role, content, contentWidth, false, command).length;
|
|
1514
1509
|
}
|
|
1515
1510
|
function buildTurnOffsets(history, contentWidth) {
|
|
1516
|
-
const density = getActiveDensity();
|
|
1517
1511
|
const entries = [];
|
|
1518
1512
|
let offset = 0;
|
|
1519
1513
|
for (let i = 0; i < history.turns.length; i++) {
|
|
1520
1514
|
const turn = history.turns[i];
|
|
1521
|
-
const separatorAbove =
|
|
1515
|
+
const separatorAbove = i > 0 && turn.role === "user" ? 1 : 0;
|
|
1522
1516
|
offset += separatorAbove;
|
|
1523
1517
|
const cacheMap = turnLineCountCache.get(turn);
|
|
1524
1518
|
let lineCount;
|
|
@@ -1547,7 +1541,6 @@ function getAllTurnEntries(history, contentWidth) {
|
|
|
1547
1541
|
const { entries, totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
1548
1542
|
const turns = [...history.turns];
|
|
1549
1543
|
if (history.currentRole !== null && history.currentContent) {
|
|
1550
|
-
const density = getActiveDensity();
|
|
1551
1544
|
const colorEnabled = resolveCliColorEnabled();
|
|
1552
1545
|
const themeFingerprint = tuiRenderThemeFingerprint(colorEnabled);
|
|
1553
1546
|
const streamingLines = getStreamingTurnLines(
|
|
@@ -1555,10 +1548,9 @@ function getAllTurnEntries(history, contentWidth) {
|
|
|
1555
1548
|
history.currentContent,
|
|
1556
1549
|
contentWidth,
|
|
1557
1550
|
colorEnabled,
|
|
1558
|
-
density,
|
|
1559
1551
|
themeFingerprint
|
|
1560
1552
|
);
|
|
1561
|
-
const sep = currentTurnSeparator(history
|
|
1553
|
+
const sep = currentTurnSeparator(history);
|
|
1562
1554
|
const startRow = finalizedLines + sep;
|
|
1563
1555
|
entries.push({
|
|
1564
1556
|
startRow,
|
|
@@ -1573,12 +1565,11 @@ function getAllTurnEntries(history, contentWidth) {
|
|
|
1573
1565
|
}
|
|
1574
1566
|
return { entries, totalLines: finalizedLines, turns };
|
|
1575
1567
|
}
|
|
1576
|
-
function currentTurnSeparator(history
|
|
1577
|
-
return
|
|
1568
|
+
function currentTurnSeparator(history) {
|
|
1569
|
+
return history.turns.length > 0 && history.currentRole === "user" ? 1 : 0;
|
|
1578
1570
|
}
|
|
1579
1571
|
function buildHistoryLayoutRows(history, contentWidth) {
|
|
1580
1572
|
const colorEnabled = resolveCliColorEnabled();
|
|
1581
|
-
const density = getActiveDensity();
|
|
1582
1573
|
const themeFingerprint = tuiRenderThemeFingerprint(colorEnabled);
|
|
1583
1574
|
const rows = [];
|
|
1584
1575
|
const separatorRow = () => ({
|
|
@@ -1589,20 +1580,19 @@ function buildHistoryLayoutRows(history, contentWidth) {
|
|
|
1589
1580
|
});
|
|
1590
1581
|
for (let i = 0; i < history.turns.length; i++) {
|
|
1591
1582
|
const turn = history.turns[i];
|
|
1592
|
-
if (
|
|
1583
|
+
if (i > 0 && turn.role === "user") {
|
|
1593
1584
|
rows.push(separatorRow());
|
|
1594
1585
|
}
|
|
1595
1586
|
rows.push(...getTurnLayoutRows(
|
|
1596
1587
|
turn,
|
|
1597
1588
|
contentWidth,
|
|
1598
1589
|
colorEnabled,
|
|
1599
|
-
density,
|
|
1600
1590
|
themeFingerprint
|
|
1601
1591
|
));
|
|
1602
1592
|
}
|
|
1603
1593
|
if (history.currentRole !== null && history.currentContent) {
|
|
1604
1594
|
const i = history.turns.length;
|
|
1605
|
-
if (
|
|
1595
|
+
if (i > 0 && history.currentRole === "user") {
|
|
1606
1596
|
rows.push(separatorRow());
|
|
1607
1597
|
}
|
|
1608
1598
|
rows.push(
|
|
@@ -1625,7 +1615,6 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
1625
1615
|
const visibleHeight = Math.max(1, rows - inputLines);
|
|
1626
1616
|
const contentWidth = Math.max(1, columns - 1);
|
|
1627
1617
|
const colorEnabled = resolveCliColorEnabled();
|
|
1628
|
-
const density = getActiveDensity();
|
|
1629
1618
|
const themeFingerprint = tuiRenderThemeFingerprint(colorEnabled);
|
|
1630
1619
|
const { entries, totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
1631
1620
|
let currentLines = [];
|
|
@@ -1636,10 +1625,9 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
1636
1625
|
history.currentContent,
|
|
1637
1626
|
contentWidth,
|
|
1638
1627
|
colorEnabled,
|
|
1639
|
-
density,
|
|
1640
1628
|
themeFingerprint
|
|
1641
1629
|
);
|
|
1642
|
-
const sep = currentTurnSeparator(history
|
|
1630
|
+
const sep = currentTurnSeparator(history);
|
|
1643
1631
|
currentStart = finalizedLines + sep;
|
|
1644
1632
|
}
|
|
1645
1633
|
const totalLines = currentStart >= 0 ? currentStart + currentLines.length : finalizedLines;
|
|
@@ -1670,7 +1658,7 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
1670
1658
|
const turn = history.turns[i];
|
|
1671
1659
|
const cached = getCachedTurnLine(turn);
|
|
1672
1660
|
let layoutRows;
|
|
1673
|
-
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.
|
|
1661
|
+
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.themeFingerprint === themeFingerprint) {
|
|
1674
1662
|
layoutRows = cached.layoutRows;
|
|
1675
1663
|
} else {
|
|
1676
1664
|
renderCacheMissCount += 1;
|
|
@@ -1678,7 +1666,6 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
1678
1666
|
turn,
|
|
1679
1667
|
contentWidth,
|
|
1680
1668
|
colorEnabled,
|
|
1681
|
-
density,
|
|
1682
1669
|
themeFingerprint
|
|
1683
1670
|
);
|
|
1684
1671
|
}
|
|
@@ -1690,7 +1677,7 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
1690
1677
|
}
|
|
1691
1678
|
}
|
|
1692
1679
|
if (currentStart >= 0) {
|
|
1693
|
-
const separatorAbove = currentTurnSeparator(history
|
|
1680
|
+
const separatorAbove = currentTurnSeparator(history);
|
|
1694
1681
|
if (separatorAbove > 0) {
|
|
1695
1682
|
const sepRow = currentStart - 1;
|
|
1696
1683
|
if (sepRow >= winStart && sepRow < winEnd) {
|
|
@@ -1774,7 +1761,7 @@ function applyScrollAction(history, action, output, inputLines) {
|
|
|
1774
1761
|
const { totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
1775
1762
|
let totalLines = finalizedLines;
|
|
1776
1763
|
if (history.currentRole !== null && history.currentContent) {
|
|
1777
|
-
totalLines += currentTurnSeparator(history
|
|
1764
|
+
totalLines += currentTurnSeparator(history) + countTurnLines(history.currentRole, history.currentContent, contentWidth);
|
|
1778
1765
|
}
|
|
1779
1766
|
const maxScrollTop = Math.max(0, totalLines - visibleHeight);
|
|
1780
1767
|
history.followBottom = false;
|
|
@@ -1863,6 +1850,18 @@ function formatTerminalRunAge(snapshot, now) {
|
|
|
1863
1850
|
function formatUnassignedFact(snapshot) {
|
|
1864
1851
|
return snapshot.unassigned ? "parent: ?" : null;
|
|
1865
1852
|
}
|
|
1853
|
+
function sanitizeRunSnapshotForNormal(snapshot) {
|
|
1854
|
+
const clean = (value) => stripAnsi(value).replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
|
|
1855
|
+
return {
|
|
1856
|
+
...snapshot,
|
|
1857
|
+
agentName: snapshot.agentName ? clean(snapshot.agentName) : snapshot.agentName,
|
|
1858
|
+
taskPreview: snapshot.taskPreview ? clean(snapshot.taskPreview) : snapshot.taskPreview,
|
|
1859
|
+
lastAssistantText: snapshot.lastAssistantText ? clean(snapshot.lastAssistantText) : snapshot.lastAssistantText,
|
|
1860
|
+
lastToolNames: snapshot.lastToolNames?.map(clean).filter(Boolean),
|
|
1861
|
+
errorMessage: void 0,
|
|
1862
|
+
logLines: void 0
|
|
1863
|
+
};
|
|
1864
|
+
}
|
|
1866
1865
|
|
|
1867
1866
|
// packages/cli/tui/agentRunPanelLines.ts
|
|
1868
1867
|
function formatPanelProgress(snapshot, now) {
|
|
@@ -2037,11 +2036,13 @@ function createRunDock(deps) {
|
|
|
2037
2036
|
const ordered = orderedEntries();
|
|
2038
2037
|
if (ordered.length === 0) return [];
|
|
2039
2038
|
const at = now();
|
|
2040
|
-
|
|
2041
|
-
|
|
2039
|
+
const mode = typeof deps.displayMode === "function" ? deps.displayMode() : deps.displayMode;
|
|
2040
|
+
const displaySnapshots = mode === "normal" || mode === "hide" ? ordered.map((entry) => sanitizeRunSnapshotForNormal(entry.snapshot)) : ordered.map((entry) => entry.snapshot);
|
|
2041
|
+
if (displaySnapshots.length === 1) {
|
|
2042
|
+
return formatAgentRunPanelLines(displaySnapshots[0], colorEnabled, at);
|
|
2042
2043
|
}
|
|
2043
2044
|
return formatRunDockLines(
|
|
2044
|
-
|
|
2045
|
+
displaySnapshots,
|
|
2045
2046
|
colorEnabled,
|
|
2046
2047
|
at,
|
|
2047
2048
|
maxRows
|
|
@@ -2210,7 +2211,8 @@ function createActivityIndicator(deps) {
|
|
|
2210
2211
|
onRepaint: deps.onRepaint,
|
|
2211
2212
|
now,
|
|
2212
2213
|
setIntervalFn,
|
|
2213
|
-
clearIntervalFn
|
|
2214
|
+
clearIntervalFn,
|
|
2215
|
+
displayMode: deps.displayMode
|
|
2214
2216
|
});
|
|
2215
2217
|
const updateAgentRun = (snapshot) => {
|
|
2216
2218
|
runDock.update(snapshot);
|
|
@@ -3312,6 +3314,20 @@ function summarizeAttachment(img) {
|
|
|
3312
3314
|
].join("\n");
|
|
3313
3315
|
return themeText(text, "chrome", colorEnabled);
|
|
3314
3316
|
}
|
|
3317
|
+
function formatComposerAttachmentLine(images) {
|
|
3318
|
+
if (images.length === 0) return null;
|
|
3319
|
+
const head = images.slice(0, 2).map((img) => `\u{1F4CE} ${img.filename} (${formatBytes(img.sizeBytes)})`);
|
|
3320
|
+
const extra = images.length - head.length;
|
|
3321
|
+
return extra > 0 ? `${head.join(", ")} +${extra}` : head.join(", ");
|
|
3322
|
+
}
|
|
3323
|
+
function popLastAttachedImage(images) {
|
|
3324
|
+
if (images.length === 0) return { handled: false, images };
|
|
3325
|
+
return {
|
|
3326
|
+
handled: true,
|
|
3327
|
+
images: images.slice(0, -1),
|
|
3328
|
+
removed: images[images.length - 1]
|
|
3329
|
+
};
|
|
3330
|
+
}
|
|
3315
3331
|
function mergeAttachedImages(existing, incoming) {
|
|
3316
3332
|
if (incoming.length === 0) return existing;
|
|
3317
3333
|
if (existing.length === 0) return [...incoming];
|
|
@@ -3333,12 +3349,12 @@ function mergeAttachedImages(existing, incoming) {
|
|
|
3333
3349
|
return out;
|
|
3334
3350
|
}
|
|
3335
3351
|
async function readImagePaths(paths, options = {}) {
|
|
3336
|
-
const
|
|
3352
|
+
const resolve4 = options.resolve ?? ((p) => p);
|
|
3337
3353
|
const reportedFailures = /* @__PURE__ */ new Set();
|
|
3338
3354
|
const images = [];
|
|
3339
3355
|
const failures = [];
|
|
3340
3356
|
for (const raw of paths) {
|
|
3341
|
-
const absolute =
|
|
3357
|
+
const absolute = resolve4(raw);
|
|
3342
3358
|
try {
|
|
3343
3359
|
const img = await readImageAsDataUrl(absolute, {
|
|
3344
3360
|
...options.maxBytes !== void 0 ? { maxBytes: options.maxBytes } : {}
|
|
@@ -3378,7 +3394,7 @@ async function resolveAttachmentImageUrls({
|
|
|
3378
3394
|
// packages/cli/tui/clipboardImage.ts
|
|
3379
3395
|
import { createHash } from "node:crypto";
|
|
3380
3396
|
import { mkdirSync } from "node:fs";
|
|
3381
|
-
import { writeFile } from "node:fs/promises";
|
|
3397
|
+
import { readdir, stat as stat2, unlink, writeFile } from "node:fs/promises";
|
|
3382
3398
|
import { tmpdir } from "node:os";
|
|
3383
3399
|
import { join } from "node:path";
|
|
3384
3400
|
var ClipboardImageError = class extends Error {
|
|
@@ -3390,6 +3406,34 @@ var ClipboardImageError = class extends Error {
|
|
|
3390
3406
|
}
|
|
3391
3407
|
};
|
|
3392
3408
|
var DEFAULT_CLIPBOARD_TIMEOUT_MS = 3e4;
|
|
3409
|
+
var CLIPBOARD_TEMP_DIR_NAME = "nolo-clipboard";
|
|
3410
|
+
function getDefaultClipboardTempDir() {
|
|
3411
|
+
return join(tmpdir(), CLIPBOARD_TEMP_DIR_NAME);
|
|
3412
|
+
}
|
|
3413
|
+
var CLIPBOARD_SWEEP_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
3414
|
+
var CLIPBOARD_SWEEP_FILE_RE = /^clip-[0-9a-f]{8,}\.(png|jpg|jpeg|gif|webp)$/;
|
|
3415
|
+
async function sweepStaleClipboardFiles(tempDir, opts = {}) {
|
|
3416
|
+
try {
|
|
3417
|
+
const maxAgeMs = opts.maxAgeMs ?? CLIPBOARD_SWEEP_MAX_AGE_MS;
|
|
3418
|
+
const now = opts.now ?? Date.now();
|
|
3419
|
+
const entries = await readdir(tempDir);
|
|
3420
|
+
let removed = 0;
|
|
3421
|
+
for (const name of entries) {
|
|
3422
|
+
if (!CLIPBOARD_SWEEP_FILE_RE.test(name)) continue;
|
|
3423
|
+
try {
|
|
3424
|
+
const fullPath = join(tempDir, name);
|
|
3425
|
+
const stats = await stat2(fullPath);
|
|
3426
|
+
if (stats.mtimeMs >= now - maxAgeMs) continue;
|
|
3427
|
+
await unlink(fullPath);
|
|
3428
|
+
removed += 1;
|
|
3429
|
+
} catch {
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
return removed;
|
|
3433
|
+
} catch {
|
|
3434
|
+
return 0;
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3393
3437
|
function isRemoteSession(env = process.env) {
|
|
3394
3438
|
return Boolean(env.SSH_CONNECTION || env.SSH_TTY || env.SSH_CLIENT);
|
|
3395
3439
|
}
|
|
@@ -3405,13 +3449,20 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3405
3449
|
}
|
|
3406
3450
|
if (platform === "darwin") {
|
|
3407
3451
|
const pngpaste = which("pngpaste");
|
|
3408
|
-
if (
|
|
3452
|
+
if (pngpaste) {
|
|
3453
|
+
return { command: [pngpaste, "-"], outputFormat: "raw" };
|
|
3454
|
+
}
|
|
3455
|
+
const osascript = which("osascript");
|
|
3456
|
+
if (!osascript) {
|
|
3409
3457
|
throw new ClipboardImageError(
|
|
3410
3458
|
"binary-missing",
|
|
3411
|
-
"\u672A\u627E\u5230 pngpaste\uFF0C\u8BF7\u8FD0\u884C brew install pngpaste \u5B89\u88C5\uFF0C\u6216\u76F4\u63A5\u62D6\u5165\u56FE\u7247\u6587\u4EF6/\u8F93\u5165\u56FE\u7247\u8DEF\u5F84"
|
|
3459
|
+
"\u672A\u627E\u5230 pngpaste\uFF0C\u4E5F\u672A\u627E\u5230\u7CFB\u7EDF\u81EA\u5E26\u7684 osascript\uFF0C\u65E0\u6CD5\u8BFB\u53D6\u526A\u8D34\u677F\u56FE\u50CF\u3002\u8BF7\u8FD0\u884C brew install pngpaste \u5B89\u88C5\uFF0C\u6216\u76F4\u63A5\u62D6\u5165\u56FE\u7247\u6587\u4EF6/\u8F93\u5165\u56FE\u7247\u8DEF\u5F84"
|
|
3412
3460
|
);
|
|
3413
3461
|
}
|
|
3414
|
-
return {
|
|
3462
|
+
return {
|
|
3463
|
+
command: [osascript, "-e", "the clipboard as \xABclass PNGf\xBB"],
|
|
3464
|
+
outputFormat: "osascript-hex"
|
|
3465
|
+
};
|
|
3415
3466
|
}
|
|
3416
3467
|
if (platform === "win32") {
|
|
3417
3468
|
const ps = which("powershell.exe") || which("powershell") || which("pwsh.exe") || which("pwsh");
|
|
@@ -3428,7 +3479,8 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3428
3479
|
"-NonInteractive",
|
|
3429
3480
|
"-Command",
|
|
3430
3481
|
"$img = Get-Clipboard -Format Image; if ($img) { $ms = New-Object System.IO.MemoryStream; $img.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); [Console]::OpenStandardOutput().Write($ms.ToArray(), 0, $ms.Length) }"
|
|
3431
|
-
]
|
|
3482
|
+
],
|
|
3483
|
+
outputFormat: "raw"
|
|
3432
3484
|
};
|
|
3433
3485
|
}
|
|
3434
3486
|
if (platform === "linux") {
|
|
@@ -3441,17 +3493,18 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3441
3493
|
"\u672A\u627E\u5230 wl-paste\uFF0C\u8BF7\u5B89\u88C5 wl-clipboard (\u4F8B\u5982 sudo apt install wl-clipboard)\uFF0C\u6216\u76F4\u63A5\u62D6\u5165\u56FE\u7247\u6587\u4EF6/\u8F93\u5165\u56FE\u7247\u8DEF\u5F84"
|
|
3442
3494
|
);
|
|
3443
3495
|
}
|
|
3444
|
-
return { command: [wlPaste2, "--type", "image/png"] };
|
|
3496
|
+
return { command: [wlPaste2, "--type", "image/png"], outputFormat: "raw" };
|
|
3445
3497
|
}
|
|
3446
3498
|
const xclip = which("xclip");
|
|
3447
3499
|
if (xclip) {
|
|
3448
3500
|
return {
|
|
3449
|
-
command: [xclip, "-selection", "clipboard", "-t", "image/png", "-o"]
|
|
3501
|
+
command: [xclip, "-selection", "clipboard", "-t", "image/png", "-o"],
|
|
3502
|
+
outputFormat: "raw"
|
|
3450
3503
|
};
|
|
3451
3504
|
}
|
|
3452
3505
|
const wlPaste = which("wl-paste");
|
|
3453
3506
|
if (wlPaste) {
|
|
3454
|
-
return { command: [wlPaste, "--type", "image/png"] };
|
|
3507
|
+
return { command: [wlPaste, "--type", "image/png"], outputFormat: "raw" };
|
|
3455
3508
|
}
|
|
3456
3509
|
throw new ClipboardImageError(
|
|
3457
3510
|
"binary-missing",
|
|
@@ -3463,6 +3516,21 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3463
3516
|
`\u5F53\u524D\u64CD\u4F5C\u7CFB\u7EDF\u6682\u4E0D\u652F\u6301\u526A\u8D34\u677F\u56FE\u50CF\u8BFB\u53D6: ${platform}`
|
|
3464
3517
|
);
|
|
3465
3518
|
}
|
|
3519
|
+
var OSASCRIPT_EMPTY_CLIPBOARD_MESSAGE = "\u526A\u8D34\u677F\u4E2D\u6CA1\u6709\u56FE\u50CF\u6570\u636E\u3002\u53EF\u76F4\u63A5\u62D6\u5165\u56FE\u7247\u6587\u4EF6\u3001\u8F93\u5165\u56FE\u7247\u8DEF\u5F84\uFF0C\u6216\u8FD0\u884C brew install pngpaste \u4EE5\u652F\u6301\u66F4\u591A\u56FE\u7247\u683C\u5F0F";
|
|
3520
|
+
function decodeOsascriptPngHex(text) {
|
|
3521
|
+
const match = /PNGf\s*([0-9A-Fa-f]*)/.exec(text);
|
|
3522
|
+
if (!match) return { kind: "empty" };
|
|
3523
|
+
const hex = match[1] ?? "";
|
|
3524
|
+
const tail = text.slice(match.index + match[0].length).replace(/[\s»]*$/, "");
|
|
3525
|
+
if (tail.length > 0) return { kind: "invalid" };
|
|
3526
|
+
if (hex.length === 0) return { kind: "empty" };
|
|
3527
|
+
if (hex.length % 2 !== 0) return { kind: "invalid" };
|
|
3528
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
3529
|
+
for (let i = 0; i < bytes.length; i += 1) {
|
|
3530
|
+
bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
3531
|
+
}
|
|
3532
|
+
return { kind: "bytes", bytes };
|
|
3533
|
+
}
|
|
3466
3534
|
async function readClipboardImage(deps = {}) {
|
|
3467
3535
|
const env = deps.env ?? process.env;
|
|
3468
3536
|
const platform = deps.platform ?? process.platform;
|
|
@@ -3470,8 +3538,8 @@ async function readClipboardImage(deps = {}) {
|
|
|
3470
3538
|
const spawn = deps.spawn ?? Bun.spawn;
|
|
3471
3539
|
const maxBytes = deps.maxBytes ?? DEFAULT_MAX_IMAGE_BYTES;
|
|
3472
3540
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_CLIPBOARD_TIMEOUT_MS;
|
|
3473
|
-
const tempDir = deps.tempDir ??
|
|
3474
|
-
const { command } = getClipboardImageCommand({
|
|
3541
|
+
const tempDir = deps.tempDir ?? getDefaultClipboardTempDir();
|
|
3542
|
+
const { command, outputFormat } = getClipboardImageCommand({
|
|
3475
3543
|
env,
|
|
3476
3544
|
platform,
|
|
3477
3545
|
which
|
|
@@ -3505,6 +3573,12 @@ async function readClipboardImage(deps = {}) {
|
|
|
3505
3573
|
timeoutPromise
|
|
3506
3574
|
]);
|
|
3507
3575
|
if (exitCode !== 0 || stdoutArrayBuffer.byteLength === 0) {
|
|
3576
|
+
if (outputFormat === "osascript-hex") {
|
|
3577
|
+
throw new ClipboardImageError(
|
|
3578
|
+
"empty-clipboard",
|
|
3579
|
+
OSASCRIPT_EMPTY_CLIPBOARD_MESSAGE + (stderrText.trim() ? `: ${stderrText.trim()}` : "")
|
|
3580
|
+
);
|
|
3581
|
+
}
|
|
3508
3582
|
throw new ClipboardImageError(
|
|
3509
3583
|
"empty-clipboard",
|
|
3510
3584
|
"\u526A\u8D34\u677F\u4E2D\u6CA1\u6709\u56FE\u50CF\u6570\u636E\uFF0C\u8BF7\u76F4\u63A5\u62D6\u5165\u56FE\u7247\u6587\u4EF6\u6216\u8F93\u5165\u56FE\u7247\u8DEF\u5F84" + (stderrText.trim() ? `: ${stderrText.trim()}` : "")
|
|
@@ -3523,6 +3597,23 @@ async function readClipboardImage(deps = {}) {
|
|
|
3523
3597
|
`\u8BFB\u53D6\u526A\u8D34\u677F\u56FE\u50CF\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`
|
|
3524
3598
|
);
|
|
3525
3599
|
}
|
|
3600
|
+
if (outputFormat === "osascript-hex") {
|
|
3601
|
+
const text = Buffer.from(stdoutBuf).toString("utf8");
|
|
3602
|
+
const decoded = decodeOsascriptPngHex(text);
|
|
3603
|
+
if (decoded.kind === "empty") {
|
|
3604
|
+
throw new ClipboardImageError(
|
|
3605
|
+
"empty-clipboard",
|
|
3606
|
+
OSASCRIPT_EMPTY_CLIPBOARD_MESSAGE
|
|
3607
|
+
);
|
|
3608
|
+
}
|
|
3609
|
+
if (decoded.kind === "invalid") {
|
|
3610
|
+
throw new ClipboardImageError(
|
|
3611
|
+
"read-failed",
|
|
3612
|
+
"\u526A\u8D34\u677F\u56FE\u50CF\u6570\u636E\u65E0\u6CD5\u89E3\u6790\uFF08hex \u7F16\u7801\u635F\u574F\uFF09\uFF0C\u8BF7\u91CD\u65B0\u590D\u5236\u56FE\u7247\u540E\u91CD\u8BD5\uFF0C\u6216\u76F4\u63A5\u62D6\u5165\u56FE\u7247\u6587\u4EF6/\u8F93\u5165\u56FE\u7247\u8DEF\u5F84"
|
|
3613
|
+
);
|
|
3614
|
+
}
|
|
3615
|
+
stdoutBuf = decoded.bytes;
|
|
3616
|
+
}
|
|
3526
3617
|
const compressResult = await compressImage(stdoutBuf, "image/png");
|
|
3527
3618
|
const finalBuf = compressResult.buffer;
|
|
3528
3619
|
const finalMime = compressResult.mime;
|
|
@@ -3583,7 +3674,7 @@ function parseStatusOutput(branch, status) {
|
|
|
3583
3674
|
return { branch, modified, untracked };
|
|
3584
3675
|
}
|
|
3585
3676
|
function execFileUtf8(file, args, cwd) {
|
|
3586
|
-
return new Promise((
|
|
3677
|
+
return new Promise((resolve4, reject) => {
|
|
3587
3678
|
execFile(
|
|
3588
3679
|
file,
|
|
3589
3680
|
args,
|
|
@@ -3593,7 +3684,7 @@ function execFileUtf8(file, args, cwd) {
|
|
|
3593
3684
|
reject(err);
|
|
3594
3685
|
return;
|
|
3595
3686
|
}
|
|
3596
|
-
|
|
3687
|
+
resolve4(typeof stdout === "string" ? stdout : String(stdout ?? ""));
|
|
3597
3688
|
}
|
|
3598
3689
|
);
|
|
3599
3690
|
});
|
|
@@ -3694,7 +3785,7 @@ function renderStatusLine(state, maxWidth) {
|
|
|
3694
3785
|
if (state.autoConfirm === true) {
|
|
3695
3786
|
emergency.push(themeText("\u23F5", "warning", colorEnabled));
|
|
3696
3787
|
}
|
|
3697
|
-
const runningTotal = runningTaskCount
|
|
3788
|
+
const runningTotal = runningTaskCount;
|
|
3698
3789
|
if (runningTotal > 0) {
|
|
3699
3790
|
emergency.push(themeText(`\u2699${runningTotal}`, "info", colorEnabled));
|
|
3700
3791
|
}
|
|
@@ -3908,6 +3999,9 @@ function renderKnownAgents(colorEnabled = resolveCliColorEnabled()) {
|
|
|
3908
3999
|
}
|
|
3909
4000
|
|
|
3910
4001
|
// packages/cli/tui/sessionInput.ts
|
|
4002
|
+
import { readdirSync, statSync } from "node:fs";
|
|
4003
|
+
import { homedir as homedir2 } from "node:os";
|
|
4004
|
+
import { resolve as resolve2 } from "node:path";
|
|
3911
4005
|
var PASTE_TOKEN_PREFIX = "\0PASTE\0";
|
|
3912
4006
|
function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
|
|
3913
4007
|
const seq = sequence ?? "";
|
|
@@ -4012,6 +4106,16 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
|
|
|
4012
4106
|
return { buffer, cursorPos: curPos };
|
|
4013
4107
|
}
|
|
4014
4108
|
if (seq === " " || key.name === "tab") {
|
|
4109
|
+
if (options?.cwd) {
|
|
4110
|
+
const pathCandidates = completeSlashCommand(buffer, options.cwd);
|
|
4111
|
+
if (pathCandidates.length === 1) {
|
|
4112
|
+
const [only] = pathCandidates;
|
|
4113
|
+
return { buffer: only, cursorPos: only.length };
|
|
4114
|
+
}
|
|
4115
|
+
if (pathCandidates.length > 1) {
|
|
4116
|
+
return { buffer, cursorPos: curPos };
|
|
4117
|
+
}
|
|
4118
|
+
}
|
|
4015
4119
|
const completed = completeSlashPrefix(buffer) ?? buffer;
|
|
4016
4120
|
return { buffer: completed, cursorPos: completed.length };
|
|
4017
4121
|
}
|
|
@@ -4064,9 +4168,9 @@ function deleteBufferRange(buffer, start, end, pasteStore) {
|
|
|
4064
4168
|
function releasePastesInRange(buffer, start, end, pasteStore) {
|
|
4065
4169
|
if (!pasteStore || start >= end) return;
|
|
4066
4170
|
const slice = buffer.slice(start, end);
|
|
4067
|
-
|
|
4171
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
|
|
4068
4172
|
let match;
|
|
4069
|
-
while ((match =
|
|
4173
|
+
while ((match = COLLAPSED_PASTE_PLACEHOLDER_RE.exec(slice)) !== null) {
|
|
4070
4174
|
releaseCollapsedPaste(pasteStore, Number(match[1]));
|
|
4071
4175
|
}
|
|
4072
4176
|
}
|
|
@@ -4120,12 +4224,10 @@ var SLASH_COMMANDS = [
|
|
|
4120
4224
|
"/clear",
|
|
4121
4225
|
"/compact",
|
|
4122
4226
|
"/theme",
|
|
4123
|
-
"/density",
|
|
4124
4227
|
"/context",
|
|
4125
4228
|
"/ctx",
|
|
4229
|
+
"/cd",
|
|
4126
4230
|
"/runtime",
|
|
4127
|
-
"/tools",
|
|
4128
|
-
"/thinking",
|
|
4129
4231
|
"/auto",
|
|
4130
4232
|
"/switch",
|
|
4131
4233
|
"/agent",
|
|
@@ -4163,12 +4265,49 @@ function completeSlashPrefix(buffer) {
|
|
|
4163
4265
|
}
|
|
4164
4266
|
return prefix.length > buffer.length ? prefix : null;
|
|
4165
4267
|
}
|
|
4166
|
-
function completeSlashCommand(buffer) {
|
|
4268
|
+
function completeSlashCommand(buffer, cwd) {
|
|
4167
4269
|
if (!buffer.startsWith("/")) return [];
|
|
4168
4270
|
const trimmed = buffer.trim();
|
|
4271
|
+
if (cwd && buffer.startsWith("/cd ")) {
|
|
4272
|
+
const prefix = buffer.slice("/cd ".length);
|
|
4273
|
+
return completeCdPathCandidates(prefix, cwd);
|
|
4274
|
+
}
|
|
4169
4275
|
if (trimmed.includes(" ")) return [];
|
|
4170
4276
|
return SLASH_COMMANDS.filter((cmd) => cmd.startsWith(trimmed) && cmd !== trimmed);
|
|
4171
4277
|
}
|
|
4278
|
+
function completeCdPathCandidates(prefix, cwd) {
|
|
4279
|
+
const lastSlash = prefix.lastIndexOf("/");
|
|
4280
|
+
const head = lastSlash >= 0 ? prefix.slice(0, lastSlash + 1) : "";
|
|
4281
|
+
const baseName = lastSlash >= 0 ? prefix.slice(lastSlash + 1) : prefix;
|
|
4282
|
+
let dirPath;
|
|
4283
|
+
if (head === "~" || head === "~/" || head === "~\\") {
|
|
4284
|
+
dirPath = homedir2();
|
|
4285
|
+
} else if (head.startsWith("~/") || head.startsWith("~\\")) {
|
|
4286
|
+
dirPath = resolve2(homedir2(), head.slice(2));
|
|
4287
|
+
} else {
|
|
4288
|
+
dirPath = head.startsWith("/") ? head : resolve2(cwd, head);
|
|
4289
|
+
}
|
|
4290
|
+
let entries;
|
|
4291
|
+
try {
|
|
4292
|
+
entries = readdirSync(dirPath, { withFileTypes: true });
|
|
4293
|
+
} catch {
|
|
4294
|
+
return [];
|
|
4295
|
+
}
|
|
4296
|
+
const hiddenRequested = baseName.startsWith(".");
|
|
4297
|
+
const names = entries.filter((e) => {
|
|
4298
|
+
if (e.isDirectory()) return true;
|
|
4299
|
+
if (!e.isSymbolicLink()) return false;
|
|
4300
|
+
try {
|
|
4301
|
+
return statSync(resolve2(dirPath, e.name)).isDirectory();
|
|
4302
|
+
} catch {
|
|
4303
|
+
return false;
|
|
4304
|
+
}
|
|
4305
|
+
}).map((e) => e.name).filter((name) => {
|
|
4306
|
+
if (!name.startsWith(baseName)) return false;
|
|
4307
|
+
return hiddenRequested || !name.startsWith(".");
|
|
4308
|
+
}).sort();
|
|
4309
|
+
return names.map((name) => `/cd ${head}${name}/`);
|
|
4310
|
+
}
|
|
4172
4311
|
function isLikelySlashCommand(input) {
|
|
4173
4312
|
const trimmed = input.trim();
|
|
4174
4313
|
if (!trimmed.startsWith("/")) return false;
|
|
@@ -4187,6 +4326,11 @@ function stripImageTokens(input, hints) {
|
|
|
4187
4326
|
return compactWhitespace(out);
|
|
4188
4327
|
}
|
|
4189
4328
|
|
|
4329
|
+
// packages/cli/tui/sessionDispatch.ts
|
|
4330
|
+
import { statSync as statSync2 } from "node:fs";
|
|
4331
|
+
import { homedir as homedir3 } from "node:os";
|
|
4332
|
+
import { resolve as resolve3 } from "node:path";
|
|
4333
|
+
|
|
4190
4334
|
// packages/cli/tui/agentPicker.ts
|
|
4191
4335
|
function toAgentPickerItems(entries) {
|
|
4192
4336
|
return entries.map((entry) => ({
|
|
@@ -4348,6 +4492,10 @@ function estimateDefaultCliContextTokens(opts = {}) {
|
|
|
4348
4492
|
|
|
4349
4493
|
// packages/cli/tui/sessionDispatch.ts
|
|
4350
4494
|
var DEFAULT_TUI_SERVER_URL = DEFAULT_NOLO_SERVER_URL;
|
|
4495
|
+
function resolveThinkingDisplayMode(env = process.env) {
|
|
4496
|
+
const raw = (env.NOLO_CLI_THINKING ?? "").trim().toLowerCase();
|
|
4497
|
+
return raw === "hide" || raw === "false" || raw === "0" ? "hide" : "show";
|
|
4498
|
+
}
|
|
4351
4499
|
function createInitialTuiState(env = process.env) {
|
|
4352
4500
|
const agentKey = asOptionalTrimmedString(env.NOLO_AGENT) ?? DEFAULT_TUI_AGENT_KEY;
|
|
4353
4501
|
const agentName = asOptionalTrimmedString(env.NOLO_AGENT_NAME) ?? "nolo";
|
|
@@ -4381,7 +4529,7 @@ function createInitialTuiState(env = process.env) {
|
|
|
4381
4529
|
userLanguage: asOptionalTrimmedString(env.NOLO_LANG),
|
|
4382
4530
|
gitStatus: void 0,
|
|
4383
4531
|
toolDisplay: normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "normal"),
|
|
4384
|
-
thinkingDisplay:
|
|
4532
|
+
thinkingDisplay: resolveThinkingDisplayMode(env),
|
|
4385
4533
|
contextWindow: resolveAgentContextWindow({ agentKey, agentName }),
|
|
4386
4534
|
estimatedContextTokens: estimateDefaultCliContextTokens({
|
|
4387
4535
|
cwd,
|
|
@@ -4505,28 +4653,53 @@ function handleTuiInput(input, state) {
|
|
|
4505
4653
|
};
|
|
4506
4654
|
}
|
|
4507
4655
|
}
|
|
4508
|
-
case "/
|
|
4509
|
-
|
|
4510
|
-
const sub = parts[0]?.trim();
|
|
4511
|
-
if (!sub) {
|
|
4656
|
+
case "/cd": {
|
|
4657
|
+
if (!argText) {
|
|
4512
4658
|
return {
|
|
4513
4659
|
nextState: state,
|
|
4514
|
-
output: t("
|
|
4660
|
+
output: `${t("cdCurrent", state.cwd)}
|
|
4661
|
+
${t("cdUsage")}`
|
|
4515
4662
|
};
|
|
4516
4663
|
}
|
|
4517
|
-
if (
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
} else {
|
|
4664
|
+
if (argText === "-") {
|
|
4665
|
+
if (!state.prevCwd) {
|
|
4666
|
+
return { nextState: state, output: t("cdNoPrevious") };
|
|
4667
|
+
}
|
|
4668
|
+
const previous = state.prevCwd;
|
|
4669
|
+
const switchMessage2 = t("cdSwitchedMessage", state.cwd, previous);
|
|
4524
4670
|
return {
|
|
4525
|
-
nextState: state,
|
|
4526
|
-
output: t("
|
|
4671
|
+
nextState: { ...state, cwd: previous, prevCwd: void 0, pendingCwdNotice: switchMessage2 },
|
|
4672
|
+
output: t("cdSwitched", previous),
|
|
4673
|
+
action: { type: "cwd-refresh", switchMessage: switchMessage2 }
|
|
4527
4674
|
};
|
|
4528
4675
|
}
|
|
4676
|
+
const expanded = argText === "~" ? homedir3() : argText.startsWith("~/") || argText.startsWith("~\\") ? resolve3(homedir3(), argText.slice(2)) : argText;
|
|
4677
|
+
const target = resolve3(state.cwd, expanded);
|
|
4678
|
+
try {
|
|
4679
|
+
if (!statSync2(target).isDirectory()) {
|
|
4680
|
+
return { nextState: state, output: t("cdNotDir", target) };
|
|
4681
|
+
}
|
|
4682
|
+
} catch {
|
|
4683
|
+
return { nextState: state, output: t("cdNotFound", target) };
|
|
4684
|
+
}
|
|
4685
|
+
const normalized = target === "/" ? "/" : target.replace(/\/+$/, "");
|
|
4686
|
+
if (normalized === state.cwd) {
|
|
4687
|
+
return { nextState: state, output: t("cdCurrent", state.cwd) };
|
|
4688
|
+
}
|
|
4689
|
+
const switchMessage = t("cdSwitchedMessage", state.cwd, normalized);
|
|
4690
|
+
return {
|
|
4691
|
+
nextState: { ...state, cwd: normalized, prevCwd: state.cwd, pendingCwdNotice: switchMessage },
|
|
4692
|
+
output: t("cdSwitched", normalized),
|
|
4693
|
+
action: { type: "cwd-refresh", switchMessage }
|
|
4694
|
+
};
|
|
4529
4695
|
}
|
|
4696
|
+
case "/density":
|
|
4697
|
+
case "/tools":
|
|
4698
|
+
case "/thinking":
|
|
4699
|
+
return {
|
|
4700
|
+
nextState: state,
|
|
4701
|
+
output: t("displayFixedHint")
|
|
4702
|
+
};
|
|
4530
4703
|
case "/context":
|
|
4531
4704
|
case "/ctx":
|
|
4532
4705
|
return { nextState: state, output: renderContextPanel(state) };
|
|
@@ -4542,45 +4715,6 @@ function handleTuiInput(input, state) {
|
|
|
4542
4715
|
output: t("runtimeSet", argText)
|
|
4543
4716
|
};
|
|
4544
4717
|
}
|
|
4545
|
-
case "/tools": {
|
|
4546
|
-
if (!argText) {
|
|
4547
|
-
return {
|
|
4548
|
-
nextState: state,
|
|
4549
|
-
output: t("toolsCurrent", state.toolDisplay)
|
|
4550
|
-
};
|
|
4551
|
-
}
|
|
4552
|
-
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
4553
|
-
if (!["normal", "pro", "hide", "compact", "verbose", "on", "off"].includes(normalizedArg)) {
|
|
4554
|
-
return {
|
|
4555
|
-
nextState: state,
|
|
4556
|
-
output: t("toolsUsage")
|
|
4557
|
-
};
|
|
4558
|
-
}
|
|
4559
|
-
const nextMode = normalizeToolDisplayMode(normalizedArg, state.toolDisplay);
|
|
4560
|
-
return {
|
|
4561
|
-
nextState: { ...state, toolDisplay: nextMode },
|
|
4562
|
-
output: t("toolsSet", nextMode)
|
|
4563
|
-
};
|
|
4564
|
-
}
|
|
4565
|
-
case "/thinking": {
|
|
4566
|
-
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
4567
|
-
if (!normalizedArg) {
|
|
4568
|
-
return {
|
|
4569
|
-
nextState: state,
|
|
4570
|
-
output: t("thinkingCurrent", state.thinkingDisplay)
|
|
4571
|
-
};
|
|
4572
|
-
}
|
|
4573
|
-
if (normalizedArg !== "show" && normalizedArg !== "hide") {
|
|
4574
|
-
return {
|
|
4575
|
-
nextState: state,
|
|
4576
|
-
output: t("thinkingUsage")
|
|
4577
|
-
};
|
|
4578
|
-
}
|
|
4579
|
-
return {
|
|
4580
|
-
nextState: { ...state, thinkingDisplay: normalizedArg },
|
|
4581
|
-
output: t("thinkingSet", normalizedArg)
|
|
4582
|
-
};
|
|
4583
|
-
}
|
|
4584
4718
|
case "/auto": {
|
|
4585
4719
|
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
4586
4720
|
if (!normalizedArg) {
|
|
@@ -4989,7 +5123,7 @@ async function probeTerminalBackground(args = {}) {
|
|
|
4989
5123
|
if (typeof stdin.setRawMode !== "function") return null;
|
|
4990
5124
|
if (!isTerminal(stdin)) return null;
|
|
4991
5125
|
const wasRaw = Boolean(stdin.isRaw);
|
|
4992
|
-
return await new Promise((
|
|
5126
|
+
return await new Promise((resolve4) => {
|
|
4993
5127
|
let buffer = "";
|
|
4994
5128
|
let settled = false;
|
|
4995
5129
|
let timer;
|
|
@@ -5002,7 +5136,7 @@ async function probeTerminalBackground(args = {}) {
|
|
|
5002
5136
|
if (!wasRaw) stdin.setRawMode?.(false);
|
|
5003
5137
|
} catch {
|
|
5004
5138
|
}
|
|
5005
|
-
|
|
5139
|
+
resolve4(result);
|
|
5006
5140
|
};
|
|
5007
5141
|
const onData = (chunk) => {
|
|
5008
5142
|
buffer += chunk.toString("latin1");
|
|
@@ -5926,6 +6060,7 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5926
6060
|
}
|
|
5927
6061
|
const memoryOverlayLayer = buildMemoryOverlayLayer({ promptBlock: memoryPromptBlock });
|
|
5928
6062
|
const memoryUseGuidanceLayer = buildMemoryUseGuidanceLayer({ promptBlock: memoryPromptBlock });
|
|
6063
|
+
const cwdNoticeBlocks = state.pendingCwdNotice ? [{ content: state.pendingCwdNotice, cacheScope: "turn" }] : [];
|
|
5929
6064
|
const contextBlockScopes = partitionScopedBlocks([
|
|
5930
6065
|
...renderTurnContextBlocksWithScope(layers),
|
|
5931
6066
|
...renderTurnContextBlocksWithScope([memoryUseGuidanceLayer]),
|
|
@@ -5933,7 +6068,8 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5933
6068
|
// buildSkillContextBlocks; they stay turn-scope because the user can
|
|
5934
6069
|
// attach/detach skills between turns.
|
|
5935
6070
|
...(skillContextBlocks ?? []).map((content) => content.trim()).filter((content) => content.length > 0).map((content) => ({ content, cacheScope: "turn" })),
|
|
5936
|
-
...renderTurnContextBlocksWithScope([memoryOverlayLayer])
|
|
6071
|
+
...renderTurnContextBlocksWithScope([memoryOverlayLayer]),
|
|
6072
|
+
...cwdNoticeBlocks
|
|
5937
6073
|
]);
|
|
5938
6074
|
const result = await agentRunner({
|
|
5939
6075
|
agentName: effectiveAgentName,
|
|
@@ -5997,12 +6133,47 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5997
6133
|
cachedMemoryOverlay: memoryPromptBlock
|
|
5998
6134
|
};
|
|
5999
6135
|
}
|
|
6000
|
-
|
|
6136
|
+
var ESC = "\x1B";
|
|
6137
|
+
var CTRL_C = "";
|
|
6138
|
+
function isApprovedConfirmationInput(answer) {
|
|
6139
|
+
const normalized = answer.trim().toLowerCase();
|
|
6140
|
+
return normalized === "" || normalized === "y" || normalized === "yes" || normalized === "\u786E\u8BA4";
|
|
6141
|
+
}
|
|
6142
|
+
function buildGateConfirmedResult(gate) {
|
|
6143
|
+
return {
|
|
6144
|
+
content: `action gate completed: ${gate.title}`,
|
|
6145
|
+
metadata: { actionGateResult: { gateId: gate.id, status: "completed", output: "confirmed" } }
|
|
6146
|
+
};
|
|
6147
|
+
}
|
|
6148
|
+
function buildGateCancelledResult(gate, reason) {
|
|
6149
|
+
return {
|
|
6150
|
+
content: `action gate cancelled: ${gate.title}`,
|
|
6151
|
+
metadata: {
|
|
6152
|
+
exitCode: 130,
|
|
6153
|
+
actionGateResult: { gateId: gate.id, status: "cancelled", output: reason }
|
|
6154
|
+
}
|
|
6155
|
+
};
|
|
6156
|
+
}
|
|
6157
|
+
function buildGateFailedResult(gate, message) {
|
|
6158
|
+
return {
|
|
6159
|
+
content: `action gate failed: ${gate.title}`,
|
|
6160
|
+
metadata: {
|
|
6161
|
+
exitCode: 1,
|
|
6162
|
+
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
6163
|
+
}
|
|
6164
|
+
};
|
|
6165
|
+
}
|
|
6166
|
+
function deriveGateMeta(gate) {
|
|
6001
6167
|
const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
|
|
6168
|
+
const isConfirmation = gate.kind === "confirm";
|
|
6002
6169
|
const displayCommand = commandPayload?.displayCommand ?? commandPayload?.command.join(" ") ?? gate.title;
|
|
6003
6170
|
const isInteractiveHandoff = gate.kind === "handoff" && gate.title === "This command requires an interactive terminal.";
|
|
6004
6171
|
const title = isInteractiveHandoff ? t("actionGateInteractiveTitle") : gate.title;
|
|
6005
6172
|
const body = isInteractiveHandoff ? t("actionGateInteractiveBody") : gate.body;
|
|
6173
|
+
return { commandPayload, isConfirmation, displayCommand, isInteractiveHandoff, title, body };
|
|
6174
|
+
}
|
|
6175
|
+
function writeGatePrompt(output, meta) {
|
|
6176
|
+
const { title, body, displayCommand, isConfirmation } = meta;
|
|
6006
6177
|
output.write(`
|
|
6007
6178
|
[nolo] ${t("actionGateNeeded")}
|
|
6008
6179
|
`);
|
|
@@ -6012,37 +6183,34 @@ function waitForActionGate(rl, input, output, gate, spawnRunner) {
|
|
|
6012
6183
|
`);
|
|
6013
6184
|
output.write(` ${displayCommand}
|
|
6014
6185
|
`);
|
|
6015
|
-
output.write(`[nolo] ${t("actionGateEnterHint")}
|
|
6186
|
+
output.write(`[nolo] ${isConfirmation ? t("actionGateConfirmHint") : t("actionGateEnterHint")}
|
|
6016
6187
|
`);
|
|
6017
|
-
|
|
6188
|
+
}
|
|
6189
|
+
function waitForActionGate(rl, input, output, gate, spawnRunner) {
|
|
6190
|
+
const meta = deriveGateMeta(gate);
|
|
6191
|
+
const { commandPayload, isConfirmation, displayCommand } = meta;
|
|
6192
|
+
writeGatePrompt(output, meta);
|
|
6193
|
+
return new Promise((resolve4) => {
|
|
6018
6194
|
let settled = false;
|
|
6019
6195
|
const finish = (result) => {
|
|
6020
6196
|
if (settled) return;
|
|
6021
6197
|
settled = true;
|
|
6022
6198
|
rl.off("close", onClose);
|
|
6023
6199
|
rl.off("SIGINT", onSigint);
|
|
6024
|
-
|
|
6200
|
+
resolve4(result);
|
|
6025
6201
|
};
|
|
6026
|
-
const cancelResult = (reason) => (
|
|
6027
|
-
|
|
6028
|
-
metadata: {
|
|
6029
|
-
exitCode: 130,
|
|
6030
|
-
actionGateResult: { gateId: gate.id, status: "cancelled", output: reason }
|
|
6031
|
-
}
|
|
6032
|
-
});
|
|
6033
|
-
const failResult = (message) => ({
|
|
6034
|
-
content: `action gate failed: ${gate.title}`,
|
|
6035
|
-
metadata: {
|
|
6036
|
-
exitCode: 1,
|
|
6037
|
-
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
6038
|
-
}
|
|
6039
|
-
});
|
|
6202
|
+
const cancelResult = (reason) => buildGateCancelledResult(gate, reason);
|
|
6203
|
+
const failResult = (message) => buildGateFailedResult(gate, message);
|
|
6040
6204
|
const onClose = () => finish(cancelResult("readline closed"));
|
|
6041
6205
|
const onSigint = () => finish(cancelResult("interrupted"));
|
|
6042
6206
|
rl.once("close", onClose);
|
|
6043
6207
|
rl.once("SIGINT", onSigint);
|
|
6044
|
-
rl.question("", async () => {
|
|
6208
|
+
rl.question("", async (answer) => {
|
|
6045
6209
|
if (settled) return;
|
|
6210
|
+
if (isConfirmation) {
|
|
6211
|
+
finish(isApprovedConfirmationInput(answer) ? buildGateConfirmedResult(gate) : cancelResult("confirmation declined"));
|
|
6212
|
+
return;
|
|
6213
|
+
}
|
|
6046
6214
|
if (!commandPayload) {
|
|
6047
6215
|
finish(failResult("unsupported gate payload"));
|
|
6048
6216
|
return;
|
|
@@ -6088,47 +6256,23 @@ function isInteractiveInput(input) {
|
|
|
6088
6256
|
return Boolean(candidate.isTTY) && typeof candidate.setRawMode === "function";
|
|
6089
6257
|
}
|
|
6090
6258
|
function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
6091
|
-
const
|
|
6092
|
-
const
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
const body = isInteractiveHandoff ? t("actionGateInteractiveBody") : gate.body;
|
|
6096
|
-
output.write(`
|
|
6097
|
-
[nolo] ${t("actionGateNeeded")}
|
|
6098
|
-
`);
|
|
6099
|
-
output.write(`[nolo] ${title}
|
|
6100
|
-
`);
|
|
6101
|
-
if (body) output.write(`[nolo] ${body}
|
|
6102
|
-
`);
|
|
6103
|
-
output.write(` ${displayCommand}
|
|
6104
|
-
`);
|
|
6105
|
-
output.write(`[nolo] ${t("actionGateEnterHint")}
|
|
6106
|
-
`);
|
|
6107
|
-
return new Promise((resolve2) => {
|
|
6259
|
+
const meta = deriveGateMeta(gate);
|
|
6260
|
+
const { commandPayload, isConfirmation, displayCommand } = meta;
|
|
6261
|
+
writeGatePrompt(output, meta);
|
|
6262
|
+
return new Promise((resolve4) => {
|
|
6108
6263
|
const rawInput = input;
|
|
6109
6264
|
let settled = false;
|
|
6110
6265
|
let commandRunning = false;
|
|
6266
|
+
let confirmationLine = "";
|
|
6111
6267
|
const finish = (result) => {
|
|
6112
6268
|
if (settled) return;
|
|
6113
6269
|
settled = true;
|
|
6114
6270
|
hooks?.registerToken?.(null);
|
|
6115
6271
|
input.off("data", onData);
|
|
6116
|
-
|
|
6272
|
+
resolve4(result);
|
|
6117
6273
|
};
|
|
6118
|
-
const cancel = (reason) => finish(
|
|
6119
|
-
|
|
6120
|
-
metadata: {
|
|
6121
|
-
exitCode: 130,
|
|
6122
|
-
actionGateResult: { gateId: gate.id, status: "cancelled", output: reason }
|
|
6123
|
-
}
|
|
6124
|
-
});
|
|
6125
|
-
const fail = (message) => finish({
|
|
6126
|
-
content: `action gate failed: ${gate.title}`,
|
|
6127
|
-
metadata: {
|
|
6128
|
-
exitCode: 1,
|
|
6129
|
-
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
6130
|
-
}
|
|
6131
|
-
});
|
|
6274
|
+
const cancel = (reason) => finish(buildGateCancelledResult(gate, reason));
|
|
6275
|
+
const fail = (message) => finish(buildGateFailedResult(gate, message));
|
|
6132
6276
|
const runCommand = async () => {
|
|
6133
6277
|
if (settled || commandRunning) return;
|
|
6134
6278
|
commandRunning = true;
|
|
@@ -6171,10 +6315,24 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
6171
6315
|
};
|
|
6172
6316
|
const handleToken = (text) => {
|
|
6173
6317
|
if (settled || commandRunning) return;
|
|
6174
|
-
if (text.includes(
|
|
6318
|
+
if (text.includes(CTRL_C) || isConfirmation && text === ESC) {
|
|
6175
6319
|
cancel("interrupted");
|
|
6176
6320
|
return;
|
|
6177
6321
|
}
|
|
6322
|
+
if (isConfirmation) {
|
|
6323
|
+
const newline = text.search(/[\r\n]/);
|
|
6324
|
+
confirmationLine += newline >= 0 ? text.slice(0, newline) : text;
|
|
6325
|
+
if (newline >= 0) {
|
|
6326
|
+
const normalized = confirmationLine.trim().toLowerCase();
|
|
6327
|
+
confirmationLine = "";
|
|
6328
|
+
if (!isApprovedConfirmationInput(normalized)) {
|
|
6329
|
+
cancel("confirmation declined");
|
|
6330
|
+
return;
|
|
6331
|
+
}
|
|
6332
|
+
finish(buildGateConfirmedResult(gate));
|
|
6333
|
+
}
|
|
6334
|
+
return;
|
|
6335
|
+
}
|
|
6178
6336
|
if (text.includes("\r") || text.includes("\n")) {
|
|
6179
6337
|
void runCommand();
|
|
6180
6338
|
}
|
|
@@ -6190,6 +6348,38 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
6190
6348
|
}
|
|
6191
6349
|
});
|
|
6192
6350
|
}
|
|
6351
|
+
function asConfirmPermissionRequest(gate) {
|
|
6352
|
+
return gate;
|
|
6353
|
+
}
|
|
6354
|
+
function isAutoConfirmableFileWriteGate(gate) {
|
|
6355
|
+
return gate.kind === "confirm" && asConfirmPermissionRequest(gate).action === "file_write";
|
|
6356
|
+
}
|
|
6357
|
+
async function resolveActionGate(gate, deps) {
|
|
6358
|
+
if (gate.kind === "confirm") {
|
|
6359
|
+
const approved = await deps.dialogHost.run(
|
|
6360
|
+
(anchor) => runConfirmDialog({
|
|
6361
|
+
request: asConfirmPermissionRequest(gate),
|
|
6362
|
+
input: deps.input,
|
|
6363
|
+
output: deps.output,
|
|
6364
|
+
...anchor
|
|
6365
|
+
})
|
|
6366
|
+
);
|
|
6367
|
+
return approved ? buildGateConfirmedResult(gate) : buildGateCancelledResult(gate, "confirmation declined");
|
|
6368
|
+
}
|
|
6369
|
+
let subprocessRan = false;
|
|
6370
|
+
deps.pauseComposer();
|
|
6371
|
+
try {
|
|
6372
|
+
return await waitForRawActionGate(deps.input, deps.output, gate, deps.spawnRunner, {
|
|
6373
|
+
beforeSubprocess: () => {
|
|
6374
|
+
subprocessRan = true;
|
|
6375
|
+
},
|
|
6376
|
+
afterSubprocess: deps.resumeComposerFromSubprocess,
|
|
6377
|
+
registerToken: deps.registerToken
|
|
6378
|
+
});
|
|
6379
|
+
} finally {
|
|
6380
|
+
if (!subprocessRan) deps.resumeComposerFromDialog();
|
|
6381
|
+
}
|
|
6382
|
+
}
|
|
6193
6383
|
async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, confirmDestructiveAction) {
|
|
6194
6384
|
const scheduleTitlePatchSync = (runResult) => {
|
|
6195
6385
|
if (!runResult.titlePatchPromise || !runResult.dialogId) return;
|
|
@@ -6320,7 +6510,9 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6320
6510
|
...runResult.title ? { dialogTitle: runResult.title } : {}
|
|
6321
6511
|
} : {},
|
|
6322
6512
|
...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {},
|
|
6323
|
-
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {}
|
|
6513
|
+
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {},
|
|
6514
|
+
// 本轮已发起 agent 调用(消息已注入),消费切换通知。
|
|
6515
|
+
pendingCwdNotice: void 0
|
|
6324
6516
|
};
|
|
6325
6517
|
if (runResult.dialogId && nextDialogKey) {
|
|
6326
6518
|
ctx.refreshDialogTotalCredits(runResult.dialogId, nextDialogKey);
|
|
@@ -6368,7 +6560,11 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6368
6560
|
// estimatedContextTokens:下一轮若 provider 不返回 usage,context
|
|
6369
6561
|
// chip 仍显示真实累计占用而不是回退到启动时的静态估算。
|
|
6370
6562
|
...runResult.turnTokens && runResult.turnTokens.input > 0 ? { estimatedContextTokens: runResult.turnTokens.input } : {},
|
|
6371
|
-
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {}
|
|
6563
|
+
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {},
|
|
6564
|
+
// 切换消息本轮已注入 agent 上下文(runAgentChat 已读),消费掉,
|
|
6565
|
+
// 避免下轮重复注入。仅当确实发起了 agent 调用(本轮是真实 turn、
|
|
6566
|
+
// 而非纯 child-run-completed 事件短路)时才清除。
|
|
6567
|
+
pendingCwdNotice: void 0
|
|
6372
6568
|
};
|
|
6373
6569
|
if (runResult.dialogId && nextDialogKey) {
|
|
6374
6570
|
ctx.refreshDialogTotalCredits(runResult.dialogId, nextDialogKey);
|
|
@@ -6978,7 +7174,7 @@ function createFixedInput(output, config) {
|
|
|
6978
7174
|
const renderInputArea = (buffer, cursorPos) => {
|
|
6979
7175
|
const colorEnabled = resolveCliColorEnabled();
|
|
6980
7176
|
const cols = Math.max(1, getColumns());
|
|
6981
|
-
const completions = completeSlashCommand(buffer);
|
|
7177
|
+
const completions = completeSlashCommand(buffer, config.getCwd?.());
|
|
6982
7178
|
const sections = [];
|
|
6983
7179
|
if (completions.length > 0) {
|
|
6984
7180
|
sections.push(fitAnsiLine(dimCliText(completions.join(" "), colorEnabled), cols));
|
|
@@ -6999,6 +7195,10 @@ function createFixedInput(output, config) {
|
|
|
6999
7195
|
for (const line of queueLines) {
|
|
7000
7196
|
sections.push(fitAnsiLine(line.replace(/\r?\n/g, " "), cols));
|
|
7001
7197
|
}
|
|
7198
|
+
const attachmentLine = config.getAttachmentLine?.() ?? null;
|
|
7199
|
+
if (attachmentLine) {
|
|
7200
|
+
sections.push(fitAnsiLine(attachmentLine.replace(/\r?\n/g, " "), cols));
|
|
7201
|
+
}
|
|
7002
7202
|
const promptRaw = t("promptLabel");
|
|
7003
7203
|
const promptWidth = displayWidth(promptRaw);
|
|
7004
7204
|
const prompt = colorEnabled ? `${themeColorSequence("accent")}${promptRaw}\x1B[39m` : promptRaw;
|
|
@@ -7048,7 +7248,7 @@ function createFixedInput(output, config) {
|
|
|
7048
7248
|
}
|
|
7049
7249
|
const text = sections.join("\n");
|
|
7050
7250
|
const lines = sections.length;
|
|
7051
|
-
const headerRows = (completions.length > 0 ? 1 : 0) + 2 + (titleLine ? 1 : 0) + activityLines.length + queueLines.length;
|
|
7251
|
+
const headerRows = (completions.length > 0 ? 1 : 0) + 2 + (titleLine ? 1 : 0) + activityLines.length + queueLines.length + (attachmentLine ? 1 : 0);
|
|
7052
7252
|
return { text, lines, cursorCol, cursorRow: headerRows + cursorRow };
|
|
7053
7253
|
};
|
|
7054
7254
|
const repaintAt = (buffer, cursorPos, force = false) => {
|
|
@@ -7458,6 +7658,7 @@ async function runSubmittedSlashLine(line, host, actionGateHandler, confirmDestr
|
|
|
7458
7658
|
turnCtx,
|
|
7459
7659
|
emitCommandOutput,
|
|
7460
7660
|
renderHistoryToOutput,
|
|
7661
|
+
scheduleRender,
|
|
7461
7662
|
refreshDialogTotalCredits,
|
|
7462
7663
|
persistExplicitAgentSwitch,
|
|
7463
7664
|
persistAgentSelection: persistAgentSelection2,
|
|
@@ -7631,6 +7832,18 @@ async function runSubmittedSlashLine(line, host, actionGateHandler, confirmDestr
|
|
|
7631
7832
|
emitCommandOutput(t("themeRefreshFailed"));
|
|
7632
7833
|
}
|
|
7633
7834
|
}
|
|
7835
|
+
if (result.action?.type === "cwd-refresh") {
|
|
7836
|
+
if ((options.env?.NOLO_CLI_GIT_STATUS ?? process.env.NOLO_CLI_GIT_STATUS) !== "0") {
|
|
7837
|
+
const gitStatus = await detectGitStatusAsync(host.state.cwd);
|
|
7838
|
+
if (gitStatus !== void 0) {
|
|
7839
|
+
host.state = { ...host.state, gitStatus };
|
|
7840
|
+
}
|
|
7841
|
+
}
|
|
7842
|
+
if (result.action.switchMessage) {
|
|
7843
|
+
emitCommandOutput(result.action.switchMessage);
|
|
7844
|
+
}
|
|
7845
|
+
scheduleRender();
|
|
7846
|
+
}
|
|
7634
7847
|
if (result.action?.type === "pick-agent") {
|
|
7635
7848
|
try {
|
|
7636
7849
|
const pickResult = await dialogHost.run(
|
|
@@ -8062,6 +8275,7 @@ async function runTuiWorkspace(options) {
|
|
|
8062
8275
|
isTurnActive: () => activeTurnAbort !== null,
|
|
8063
8276
|
fallbackLabel: () => `${state.agentName} -> working`,
|
|
8064
8277
|
stoppingLabel: () => t("turnStopping"),
|
|
8278
|
+
displayMode: () => state.toolDisplay,
|
|
8065
8279
|
onRepaint: () => {
|
|
8066
8280
|
if (fixedInput.active && !fixedInput.isPaused()) {
|
|
8067
8281
|
output.write("\x1B[?2026h\x1B[?25l");
|
|
@@ -8339,6 +8553,7 @@ async function runTuiWorkspace(options) {
|
|
|
8339
8553
|
turnCtx,
|
|
8340
8554
|
emitCommandOutput,
|
|
8341
8555
|
renderHistoryToOutput,
|
|
8556
|
+
scheduleRender,
|
|
8342
8557
|
refreshDialogTotalCredits,
|
|
8343
8558
|
persistExplicitAgentSwitch,
|
|
8344
8559
|
persistAgentSelection,
|
|
@@ -8371,9 +8586,16 @@ async function runTuiWorkspace(options) {
|
|
|
8371
8586
|
return dimCliText(` \u2937 ${i + 1}. ${oneLine}`, colorEnabled);
|
|
8372
8587
|
});
|
|
8373
8588
|
},
|
|
8589
|
+
getAttachmentLine: () => {
|
|
8590
|
+
const line = formatComposerAttachmentLine(state.attachedImages);
|
|
8591
|
+
return line ? dimCliText(line, resolveCliColorEnabled()) : null;
|
|
8592
|
+
},
|
|
8374
8593
|
onInputLinesChange: () => {
|
|
8375
8594
|
renderHistoryToOutput();
|
|
8376
|
-
}
|
|
8595
|
+
},
|
|
8596
|
+
// /cd 路径补全候选行渲染需要当前 cwd(读 state 而非入参,保证
|
|
8597
|
+
// /cd 切换后立即以新 cwd 渲染,composer 不必重建)。
|
|
8598
|
+
getCwd: () => state.cwd
|
|
8377
8599
|
});
|
|
8378
8600
|
fixedInput = {
|
|
8379
8601
|
...baseFixedInput,
|
|
@@ -8452,14 +8674,22 @@ async function runTuiWorkspace(options) {
|
|
|
8452
8674
|
modalOwnsKeyboard = false;
|
|
8453
8675
|
};
|
|
8454
8676
|
const actionGateHandler = async (gate) => {
|
|
8677
|
+
if (state.autoConfirm && isAutoConfirmableFileWriteGate(gate)) {
|
|
8678
|
+
return buildGateConfirmedResult(gate);
|
|
8679
|
+
}
|
|
8455
8680
|
modalOwnsKeyboard = true;
|
|
8456
8681
|
try {
|
|
8457
|
-
return await
|
|
8458
|
-
|
|
8459
|
-
|
|
8682
|
+
return await resolveActionGate(gate, {
|
|
8683
|
+
dialogHost,
|
|
8684
|
+
input,
|
|
8685
|
+
output,
|
|
8686
|
+
spawnRunner,
|
|
8460
8687
|
registerToken: (handler) => {
|
|
8461
8688
|
rawActionGateTokenHandler = handler;
|
|
8462
|
-
}
|
|
8689
|
+
},
|
|
8690
|
+
pauseComposer: () => fixedInput.pause(),
|
|
8691
|
+
resumeComposerFromSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
8692
|
+
resumeComposerFromDialog: () => fixedInput.resumeFromDialog()
|
|
8463
8693
|
});
|
|
8464
8694
|
} finally {
|
|
8465
8695
|
releaseKeyboardToComposer();
|
|
@@ -8657,6 +8887,19 @@ ${err.message}` : ""}`
|
|
|
8657
8887
|
output.write(`${refreshMsg}
|
|
8658
8888
|
`);
|
|
8659
8889
|
}
|
|
8890
|
+
} else if (res.action?.type === "cwd-refresh") {
|
|
8891
|
+
state = res.nextState;
|
|
8892
|
+
if (res.output) {
|
|
8893
|
+
output.write(`${res.output}
|
|
8894
|
+
`);
|
|
8895
|
+
}
|
|
8896
|
+
if ((options.env?.NOLO_CLI_GIT_STATUS ?? process.env.NOLO_CLI_GIT_STATUS) !== "0") {
|
|
8897
|
+
const gitStatus = await detectGitStatusAsync(state.cwd);
|
|
8898
|
+
if (gitStatus !== void 0) {
|
|
8899
|
+
state = { ...state, gitStatus };
|
|
8900
|
+
}
|
|
8901
|
+
}
|
|
8902
|
+
scheduleRender();
|
|
8660
8903
|
} else if (res.action) {
|
|
8661
8904
|
output.write(
|
|
8662
8905
|
"Model picker isn't available while a reply is running. Use `/switch <name>` to switch now (takes effect on the next turn), or wait for the reply to finish.\n"
|
|
@@ -8865,8 +9108,20 @@ ${merged}` : merged;
|
|
|
8865
9108
|
if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
|
|
8866
9109
|
return;
|
|
8867
9110
|
}
|
|
9111
|
+
if (isBackspaceSequence(sequence, {}) && buffer === "" && state.attachedImages.length > 0) {
|
|
9112
|
+
const undo = popLastAttachedImage(state.attachedImages);
|
|
9113
|
+
if (undo.handled && undo.removed) {
|
|
9114
|
+
state = { ...state, attachedImages: undo.images };
|
|
9115
|
+
emitCommandOutput(
|
|
9116
|
+
`[nolo] ${t("attachmentRemovedHint", undo.removed.filename, String(undo.images.length))}`
|
|
9117
|
+
);
|
|
9118
|
+
if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
|
|
9119
|
+
return;
|
|
9120
|
+
}
|
|
9121
|
+
}
|
|
8868
9122
|
const result = applyTuiInputKey(buffer, sequence, {}, cursorPos, {
|
|
8869
|
-
pasteStore
|
|
9123
|
+
pasteStore,
|
|
9124
|
+
cwd: state.cwd
|
|
8870
9125
|
});
|
|
8871
9126
|
if (result.redraw) {
|
|
8872
9127
|
resetHistoryFrameDiffCache(output);
|
|
@@ -8889,7 +9144,7 @@ ${merged}` : merged;
|
|
|
8889
9144
|
if (busyLock) {
|
|
8890
9145
|
const trimmedText = submittedText.trim();
|
|
8891
9146
|
const busySlashCommand = trimmedText.split(/\s+/)[0]?.toLowerCase();
|
|
8892
|
-
const isBusyLocalSlash = busySlashCommand === "/context" || busySlashCommand === "/ctx" || busySlashCommand === "/
|
|
9147
|
+
const isBusyLocalSlash = busySlashCommand === "/context" || busySlashCommand === "/ctx" || busySlashCommand === "/cd" || busySlashCommand === "/switch" || busySlashCommand === "/theme" || busySlashCommand === "/runtime" || busySlashCommand === "/tools" || busySlashCommand === "/thinking" || busySlashCommand === "/auto" || busySlashCommand === "/tasks" || busySlashCommand === "/jobs" || busySlashCommand === "/procs" || busySlashCommand === "/agents" || busySlashCommand === "/doc" || busySlashCommand === "/skill" || busySlashCommand === "/customize" || busySlashCommand === "/login" || busySlashCommand === "/profile" || busySlashCommand === "/version";
|
|
8893
9148
|
if (isBusyLocalSlash) {
|
|
8894
9149
|
await handleBusyLocalSlash(submittedText, busySlashCommand);
|
|
8895
9150
|
return;
|
|
@@ -8959,9 +9214,9 @@ ${merged}` : merged;
|
|
|
8959
9214
|
input.on("data", onData);
|
|
8960
9215
|
fixedInput.repaint(buffer, cursorPos);
|
|
8961
9216
|
refreshGitStatus();
|
|
8962
|
-
await new Promise((
|
|
8963
|
-
resolveDone =
|
|
8964
|
-
if (done)
|
|
9217
|
+
await new Promise((resolve4) => {
|
|
9218
|
+
resolveDone = resolve4;
|
|
9219
|
+
if (done) resolve4();
|
|
8965
9220
|
});
|
|
8966
9221
|
} finally {
|
|
8967
9222
|
finish();
|
|
@@ -8975,7 +9230,11 @@ ${merged}` : merged;
|
|
|
8975
9230
|
for await (const line of rl) {
|
|
8976
9231
|
const shouldExit = await runSubmittedLine(
|
|
8977
9232
|
line,
|
|
8978
|
-
(gate) =>
|
|
9233
|
+
(gate) => (
|
|
9234
|
+
// /auto on 同款短路,见上方交互路径的 actionGateHandler 注释:
|
|
9235
|
+
// 只放行 file_write 的 confirm gate,handoff/input 类仍要求真人操作。
|
|
9236
|
+
state.autoConfirm && isAutoConfirmableFileWriteGate(gate) ? Promise.resolve(buildGateConfirmedResult(gate)) : waitForActionGate(rl, input, output, gate, spawnRunner)
|
|
9237
|
+
),
|
|
8979
9238
|
async (request) => {
|
|
8980
9239
|
if (state.autoConfirm) return true;
|
|
8981
9240
|
rl.pause();
|
|
@@ -9014,12 +9273,16 @@ ${renderStatusLine(state)}
|
|
|
9014
9273
|
}
|
|
9015
9274
|
async function startTuiWorkspace(options) {
|
|
9016
9275
|
const themeOwner = ++latestWorkspaceThemeOwner;
|
|
9276
|
+
void sweepStaleClipboardFiles(getDefaultClipboardTempDir()).catch(() => {
|
|
9277
|
+
});
|
|
9017
9278
|
try {
|
|
9018
9279
|
return await runTuiWorkspace(options);
|
|
9019
9280
|
} finally {
|
|
9020
9281
|
if (themeOwner === latestWorkspaceThemeOwner) {
|
|
9021
9282
|
resetWorkspaceThemeState();
|
|
9022
9283
|
}
|
|
9284
|
+
void sweepStaleClipboardFiles(getDefaultClipboardTempDir()).catch(() => {
|
|
9285
|
+
});
|
|
9023
9286
|
}
|
|
9024
9287
|
}
|
|
9025
9288
|
export {
|