nolo-cli 0.54.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-IVEOJ7L6.js → _executeModel-ANY4SIAS.js} +35 -36
- 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-D7AFLKQN.js → agentDeleteCommand-JWIKNWWI.js} +17 -17
- package/{agentEmailCommands-MXFZGF54.js → agentEmailCommands-PL22BEU5.js} +40 -41
- package/{agentListCommands-MP732Q23.js → agentListCommands-6NR7AQEK.js} +19 -19
- package/{agentMachineCommands-352JFJX4.js → agentMachineCommands-TASPU6OA.js} +18 -18
- package/{agentRecordCommands-G6EFHU3G.js → agentRecordCommands-Z64TA63M.js} +39 -40
- package/{agentRunCommand-UUWJMH7J.js → agentRunCommand-4QJQLPRW.js} +40 -41
- package/{agentRuntimeLocal-KWBPJ53H.js → agentRuntimeLocal-PCJJ56J2.js} +17 -17
- package/{agentSlice-V742SNKC.js → agentSlice-KYLDUSNN.js} +6 -6
- package/{appDeleteCommands-GV4TF52A.js → appDeleteCommands-WLHMJAVT.js} +19 -19
- package/{appDeployCommands-EZMUPNSW.js → appDeployCommands-CKON7N2E.js} +19 -19
- package/{appDeployStatusCommands-AAGELKAN.js → appDeployStatusCommands-PXRLDASH.js} +19 -19
- package/{appGetCommands-W37KDAON.js → appGetCommands-RAB5RM4M.js} +19 -19
- package/{appListCommands-IFDWBBNV.js → appListCommands-GU57FB62.js} +19 -19
- package/{authCommand-5HM57KPL.js → authCommand-QOPOEYEK.js} +7 -7
- package/{chatQueueReduxAdapter-ZXXP6E4O.js → chatQueueReduxAdapter-5O2WLITN.js} +17 -17
- 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-ALMVQQPG.js → chunk-3Z3DXZBD.js} +12 -12
- package/{chunk-RO2IUWZE.js → chunk-4NN3EK7H.js} +1 -1
- package/{chunk-WJV3G7BM.js → chunk-56W233KG.js} +1 -1
- package/{chunk-GBXR3CSM.js → chunk-5WADL4O7.js} +1 -1
- package/{chunk-J4Z6UI4C.js → chunk-6BGAQ3KR.js} +20 -15
- package/{chunk-R63FNYSI.js → chunk-6FQ2552G.js} +66 -28
- package/{chunk-6XIE5ZGI.js → chunk-6HIGYUBQ.js} +1 -1
- package/{chunk-MC66ASS6.js → chunk-6SZ52ORL.js} +8 -8
- package/{chunk-CULR4XB4.js → chunk-757BGY6Y.js} +1 -1
- package/{chunk-SQTVMYMU.js → chunk-7APQB6R6.js} +3 -3
- package/{chunk-RBJD33HM.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-BKPUPZ6W.js → chunk-BJLYCOZK.js} +25 -25
- package/{chunk-2T6XO4PK.js → chunk-CVT7L2WZ.js} +1 -1
- package/{chunk-XXZULHJ7.js → chunk-D3JQPONH.js} +1 -1
- package/{chunk-M2CGG6VJ.js → chunk-EVBFYPDC.js} +1 -1
- package/{chunk-KHCLMKZZ.js → chunk-EY7V7REW.js} +280 -6
- package/{chunk-4RXXP6WD.js → chunk-FGEYVPPR.js} +2 -2
- package/{chunk-ZMV5PCRS.js → chunk-GBADO3SM.js} +1 -1
- package/chunk-GLGD2JGY.js +1766 -0
- package/{chunk-W6N3GLUU.js → chunk-GV35EHNA.js} +81 -69
- package/{chunk-HR5XDXYM.js → chunk-H4RYESI6.js} +3 -3
- package/{chunk-FZMM2KZC.js → chunk-IKTHA3JH.js} +2 -2
- package/{chunk-WUMYQ2FE.js → chunk-INXBNYCG.js} +3 -3
- package/{chunk-PTHLNXGY.js → chunk-KUUTWU4I.js} +3 -3
- package/{chunk-RVHPY5PC.js → chunk-LA4IDAK7.js} +12 -12
- package/{chunk-OU7NGN5Y.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-7UFH6THF.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-YFHUQLJF.js → chunk-RU5D3B22.js} +1 -1
- package/{chunk-5Y5G76BJ.js → chunk-SP3DPVBH.js} +2 -2
- package/{chunk-5SXS7T5Q.js → chunk-TI5BCZCH.js} +18 -18
- package/{chunk-K7CNV7GI.js → chunk-U2A47SVI.js} +5 -5
- package/{chunk-45E65JER.js → chunk-U5Z7LFZF.js} +1 -1
- package/{chunk-DIQCV4FR.js → chunk-UITMHBVK.js} +1 -1
- package/{chunk-VM7K5EJL.js → chunk-UW4INMD2.js} +2 -2
- package/{chunk-SUFDWBLV.js → chunk-V4KZGLOI.js} +30 -30
- package/{chunk-ET7BXWAW.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-J7KVJAUQ.js → chunk-WL3UOGYO.js} +0 -1
- package/{chunk-PEMGYJNS.js → chunk-Y7LNKP32.js} +3 -3
- package/{chunk-DMCFF4KE.js → chunk-YBV6QJKM.js} +14 -8
- package/{codingSkills-BYQI6EPT.js → codingSkills-BCQXRZOI.js} +3 -4
- package/{createAgentAutomationAction-LE3ZYDT6.js → createAgentAutomationAction-UJLNFFFC.js} +18 -18
- package/{createDialogAction-2C6SR62D.js → createDialogAction-TJCX6GUE.js} +21 -22
- package/{createPageAction-X4C7K3OD.js → createPageAction-N3IYABHV.js} +19 -20
- package/{dbSlice-FWF5F4L7.js → dbSlice-D5CNGWPD.js} +5 -5
- package/{deleteFile-NPZ64DFN.js → deleteFile-44TUM34Y.js} +3 -3
- package/{dialogCommands-CP2U44A7.js → dialogCommands-35M6RBAC.js} +18 -18
- package/{dialogSlice-2SH5636X.js → dialogSlice-KO7ADD7H.js} +17 -17
- package/{docCreateCommands-A2KIJSF7.js → docCreateCommands-VXHZWQ3P.js} +20 -21
- package/{docDeleteCommands-NZ7XO4Z4.js → docDeleteCommands-4WFAJR6A.js} +20 -21
- package/{docReadCommands-VWVK4ZAR.js → docReadCommands-OYREEFAR.js} +20 -21
- package/{docStore-J6GQYKHS.js → docStore-5BU76DFK.js} +19 -19
- package/{docUpdateCommands-YTUEC6PN.js → docUpdateCommands-A7QERSME.js} +20 -21
- package/{getPricing-I53UFOPH.js → getPricing-HAU62AFM.js} +3 -3
- package/{handleSendMessageAction-MD325XZS.js → handleSendMessageAction-OSGQJQ45.js} +17 -17
- package/index.js +58 -58
- package/{machineCommands-TCNZV2DC.js → machineCommands-J43U3TX5.js} +39 -40
- package/{machineWsRunDispatch-QSX5IWPH.js → machineWsRunDispatch-Z2Z6STXZ.js} +39 -40
- package/{models-E2CYP4IB.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-N3RGX7EK.js → readlineWorkspace-YRPV6JPN.js} +462 -235
- package/{removeDialogAgentAction-RMPISD42.js → removeDialogAgentAction-JYT73FU2.js} +7 -7
- package/{runAgentClientLoop-R3NTOERA.js → runAgentClientLoop-5YM5WMAY.js} +33 -34
- 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-RC7XMYQ7.js → spaceCommands-MY26V52L.js} +17 -17
- package/{spaceSlice-KBVKKO3M.js → spaceSlice-JUIXC365.js} +18 -18
- package/{streamAgentChatTurn-WLWEBWSF.js → streamAgentChatTurn-XV5X5TNQ.js} +37 -38
- package/{switchDialogAgentAction-WGMMQHDI.js → switchDialogAgentAction-CJ5H6SAR.js} +5 -5
- package/{tableCommands-P2TXJ3CF.js → tableCommands-R6WFRDYF.js} +1 -1
- package/{tools-LSLDSUWU.js → tools-MIMELA2Y.js} +28 -29
- package/{tuiSummaryLlmCaller-TPBL4BV2.js → tuiSummaryLlmCaller-XJ5BKNNS.js} +13 -13
- package/{updateDialogTitleAction-4HJEARM7.js → updateDialogTitleAction-EIZUSWHR.js} +18 -18
- 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-
|
|
159
|
-
import "./chunk-
|
|
156
|
+
} from "./chunk-BJLYCOZK.js";
|
|
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;
|
|
@@ -3327,6 +3314,20 @@ function summarizeAttachment(img) {
|
|
|
3327
3314
|
].join("\n");
|
|
3328
3315
|
return themeText(text, "chrome", colorEnabled);
|
|
3329
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
|
+
}
|
|
3330
3331
|
function mergeAttachedImages(existing, incoming) {
|
|
3331
3332
|
if (incoming.length === 0) return existing;
|
|
3332
3333
|
if (existing.length === 0) return [...incoming];
|
|
@@ -3348,12 +3349,12 @@ function mergeAttachedImages(existing, incoming) {
|
|
|
3348
3349
|
return out;
|
|
3349
3350
|
}
|
|
3350
3351
|
async function readImagePaths(paths, options = {}) {
|
|
3351
|
-
const
|
|
3352
|
+
const resolve4 = options.resolve ?? ((p) => p);
|
|
3352
3353
|
const reportedFailures = /* @__PURE__ */ new Set();
|
|
3353
3354
|
const images = [];
|
|
3354
3355
|
const failures = [];
|
|
3355
3356
|
for (const raw of paths) {
|
|
3356
|
-
const absolute =
|
|
3357
|
+
const absolute = resolve4(raw);
|
|
3357
3358
|
try {
|
|
3358
3359
|
const img = await readImageAsDataUrl(absolute, {
|
|
3359
3360
|
...options.maxBytes !== void 0 ? { maxBytes: options.maxBytes } : {}
|
|
@@ -3393,7 +3394,7 @@ async function resolveAttachmentImageUrls({
|
|
|
3393
3394
|
// packages/cli/tui/clipboardImage.ts
|
|
3394
3395
|
import { createHash } from "node:crypto";
|
|
3395
3396
|
import { mkdirSync } from "node:fs";
|
|
3396
|
-
import { writeFile } from "node:fs/promises";
|
|
3397
|
+
import { readdir, stat as stat2, unlink, writeFile } from "node:fs/promises";
|
|
3397
3398
|
import { tmpdir } from "node:os";
|
|
3398
3399
|
import { join } from "node:path";
|
|
3399
3400
|
var ClipboardImageError = class extends Error {
|
|
@@ -3405,6 +3406,34 @@ var ClipboardImageError = class extends Error {
|
|
|
3405
3406
|
}
|
|
3406
3407
|
};
|
|
3407
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
|
+
}
|
|
3408
3437
|
function isRemoteSession(env = process.env) {
|
|
3409
3438
|
return Boolean(env.SSH_CONNECTION || env.SSH_TTY || env.SSH_CLIENT);
|
|
3410
3439
|
}
|
|
@@ -3420,13 +3449,20 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3420
3449
|
}
|
|
3421
3450
|
if (platform === "darwin") {
|
|
3422
3451
|
const pngpaste = which("pngpaste");
|
|
3423
|
-
if (
|
|
3452
|
+
if (pngpaste) {
|
|
3453
|
+
return { command: [pngpaste, "-"], outputFormat: "raw" };
|
|
3454
|
+
}
|
|
3455
|
+
const osascript = which("osascript");
|
|
3456
|
+
if (!osascript) {
|
|
3424
3457
|
throw new ClipboardImageError(
|
|
3425
3458
|
"binary-missing",
|
|
3426
|
-
"\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"
|
|
3427
3460
|
);
|
|
3428
3461
|
}
|
|
3429
|
-
return {
|
|
3462
|
+
return {
|
|
3463
|
+
command: [osascript, "-e", "the clipboard as \xABclass PNGf\xBB"],
|
|
3464
|
+
outputFormat: "osascript-hex"
|
|
3465
|
+
};
|
|
3430
3466
|
}
|
|
3431
3467
|
if (platform === "win32") {
|
|
3432
3468
|
const ps = which("powershell.exe") || which("powershell") || which("pwsh.exe") || which("pwsh");
|
|
@@ -3443,7 +3479,8 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3443
3479
|
"-NonInteractive",
|
|
3444
3480
|
"-Command",
|
|
3445
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) }"
|
|
3446
|
-
]
|
|
3482
|
+
],
|
|
3483
|
+
outputFormat: "raw"
|
|
3447
3484
|
};
|
|
3448
3485
|
}
|
|
3449
3486
|
if (platform === "linux") {
|
|
@@ -3456,17 +3493,18 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3456
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"
|
|
3457
3494
|
);
|
|
3458
3495
|
}
|
|
3459
|
-
return { command: [wlPaste2, "--type", "image/png"] };
|
|
3496
|
+
return { command: [wlPaste2, "--type", "image/png"], outputFormat: "raw" };
|
|
3460
3497
|
}
|
|
3461
3498
|
const xclip = which("xclip");
|
|
3462
3499
|
if (xclip) {
|
|
3463
3500
|
return {
|
|
3464
|
-
command: [xclip, "-selection", "clipboard", "-t", "image/png", "-o"]
|
|
3501
|
+
command: [xclip, "-selection", "clipboard", "-t", "image/png", "-o"],
|
|
3502
|
+
outputFormat: "raw"
|
|
3465
3503
|
};
|
|
3466
3504
|
}
|
|
3467
3505
|
const wlPaste = which("wl-paste");
|
|
3468
3506
|
if (wlPaste) {
|
|
3469
|
-
return { command: [wlPaste, "--type", "image/png"] };
|
|
3507
|
+
return { command: [wlPaste, "--type", "image/png"], outputFormat: "raw" };
|
|
3470
3508
|
}
|
|
3471
3509
|
throw new ClipboardImageError(
|
|
3472
3510
|
"binary-missing",
|
|
@@ -3478,6 +3516,21 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3478
3516
|
`\u5F53\u524D\u64CD\u4F5C\u7CFB\u7EDF\u6682\u4E0D\u652F\u6301\u526A\u8D34\u677F\u56FE\u50CF\u8BFB\u53D6: ${platform}`
|
|
3479
3517
|
);
|
|
3480
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
|
+
}
|
|
3481
3534
|
async function readClipboardImage(deps = {}) {
|
|
3482
3535
|
const env = deps.env ?? process.env;
|
|
3483
3536
|
const platform = deps.platform ?? process.platform;
|
|
@@ -3485,8 +3538,8 @@ async function readClipboardImage(deps = {}) {
|
|
|
3485
3538
|
const spawn = deps.spawn ?? Bun.spawn;
|
|
3486
3539
|
const maxBytes = deps.maxBytes ?? DEFAULT_MAX_IMAGE_BYTES;
|
|
3487
3540
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_CLIPBOARD_TIMEOUT_MS;
|
|
3488
|
-
const tempDir = deps.tempDir ??
|
|
3489
|
-
const { command } = getClipboardImageCommand({
|
|
3541
|
+
const tempDir = deps.tempDir ?? getDefaultClipboardTempDir();
|
|
3542
|
+
const { command, outputFormat } = getClipboardImageCommand({
|
|
3490
3543
|
env,
|
|
3491
3544
|
platform,
|
|
3492
3545
|
which
|
|
@@ -3520,6 +3573,12 @@ async function readClipboardImage(deps = {}) {
|
|
|
3520
3573
|
timeoutPromise
|
|
3521
3574
|
]);
|
|
3522
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
|
+
}
|
|
3523
3582
|
throw new ClipboardImageError(
|
|
3524
3583
|
"empty-clipboard",
|
|
3525
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()}` : "")
|
|
@@ -3538,6 +3597,23 @@ async function readClipboardImage(deps = {}) {
|
|
|
3538
3597
|
`\u8BFB\u53D6\u526A\u8D34\u677F\u56FE\u50CF\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`
|
|
3539
3598
|
);
|
|
3540
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
|
+
}
|
|
3541
3617
|
const compressResult = await compressImage(stdoutBuf, "image/png");
|
|
3542
3618
|
const finalBuf = compressResult.buffer;
|
|
3543
3619
|
const finalMime = compressResult.mime;
|
|
@@ -3598,7 +3674,7 @@ function parseStatusOutput(branch, status) {
|
|
|
3598
3674
|
return { branch, modified, untracked };
|
|
3599
3675
|
}
|
|
3600
3676
|
function execFileUtf8(file, args, cwd) {
|
|
3601
|
-
return new Promise((
|
|
3677
|
+
return new Promise((resolve4, reject) => {
|
|
3602
3678
|
execFile(
|
|
3603
3679
|
file,
|
|
3604
3680
|
args,
|
|
@@ -3608,7 +3684,7 @@ function execFileUtf8(file, args, cwd) {
|
|
|
3608
3684
|
reject(err);
|
|
3609
3685
|
return;
|
|
3610
3686
|
}
|
|
3611
|
-
|
|
3687
|
+
resolve4(typeof stdout === "string" ? stdout : String(stdout ?? ""));
|
|
3612
3688
|
}
|
|
3613
3689
|
);
|
|
3614
3690
|
});
|
|
@@ -3923,6 +3999,9 @@ function renderKnownAgents(colorEnabled = resolveCliColorEnabled()) {
|
|
|
3923
3999
|
}
|
|
3924
4000
|
|
|
3925
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";
|
|
3926
4005
|
var PASTE_TOKEN_PREFIX = "\0PASTE\0";
|
|
3927
4006
|
function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
|
|
3928
4007
|
const seq = sequence ?? "";
|
|
@@ -4027,6 +4106,16 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
|
|
|
4027
4106
|
return { buffer, cursorPos: curPos };
|
|
4028
4107
|
}
|
|
4029
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
|
+
}
|
|
4030
4119
|
const completed = completeSlashPrefix(buffer) ?? buffer;
|
|
4031
4120
|
return { buffer: completed, cursorPos: completed.length };
|
|
4032
4121
|
}
|
|
@@ -4079,9 +4168,9 @@ function deleteBufferRange(buffer, start, end, pasteStore) {
|
|
|
4079
4168
|
function releasePastesInRange(buffer, start, end, pasteStore) {
|
|
4080
4169
|
if (!pasteStore || start >= end) return;
|
|
4081
4170
|
const slice = buffer.slice(start, end);
|
|
4082
|
-
|
|
4171
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
|
|
4083
4172
|
let match;
|
|
4084
|
-
while ((match =
|
|
4173
|
+
while ((match = COLLAPSED_PASTE_PLACEHOLDER_RE.exec(slice)) !== null) {
|
|
4085
4174
|
releaseCollapsedPaste(pasteStore, Number(match[1]));
|
|
4086
4175
|
}
|
|
4087
4176
|
}
|
|
@@ -4135,12 +4224,10 @@ var SLASH_COMMANDS = [
|
|
|
4135
4224
|
"/clear",
|
|
4136
4225
|
"/compact",
|
|
4137
4226
|
"/theme",
|
|
4138
|
-
"/density",
|
|
4139
4227
|
"/context",
|
|
4140
4228
|
"/ctx",
|
|
4229
|
+
"/cd",
|
|
4141
4230
|
"/runtime",
|
|
4142
|
-
"/tools",
|
|
4143
|
-
"/thinking",
|
|
4144
4231
|
"/auto",
|
|
4145
4232
|
"/switch",
|
|
4146
4233
|
"/agent",
|
|
@@ -4178,12 +4265,49 @@ function completeSlashPrefix(buffer) {
|
|
|
4178
4265
|
}
|
|
4179
4266
|
return prefix.length > buffer.length ? prefix : null;
|
|
4180
4267
|
}
|
|
4181
|
-
function completeSlashCommand(buffer) {
|
|
4268
|
+
function completeSlashCommand(buffer, cwd) {
|
|
4182
4269
|
if (!buffer.startsWith("/")) return [];
|
|
4183
4270
|
const trimmed = buffer.trim();
|
|
4271
|
+
if (cwd && buffer.startsWith("/cd ")) {
|
|
4272
|
+
const prefix = buffer.slice("/cd ".length);
|
|
4273
|
+
return completeCdPathCandidates(prefix, cwd);
|
|
4274
|
+
}
|
|
4184
4275
|
if (trimmed.includes(" ")) return [];
|
|
4185
4276
|
return SLASH_COMMANDS.filter((cmd) => cmd.startsWith(trimmed) && cmd !== trimmed);
|
|
4186
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
|
+
}
|
|
4187
4311
|
function isLikelySlashCommand(input) {
|
|
4188
4312
|
const trimmed = input.trim();
|
|
4189
4313
|
if (!trimmed.startsWith("/")) return false;
|
|
@@ -4202,6 +4326,11 @@ function stripImageTokens(input, hints) {
|
|
|
4202
4326
|
return compactWhitespace(out);
|
|
4203
4327
|
}
|
|
4204
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
|
+
|
|
4205
4334
|
// packages/cli/tui/agentPicker.ts
|
|
4206
4335
|
function toAgentPickerItems(entries) {
|
|
4207
4336
|
return entries.map((entry) => ({
|
|
@@ -4363,6 +4492,10 @@ function estimateDefaultCliContextTokens(opts = {}) {
|
|
|
4363
4492
|
|
|
4364
4493
|
// packages/cli/tui/sessionDispatch.ts
|
|
4365
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
|
+
}
|
|
4366
4499
|
function createInitialTuiState(env = process.env) {
|
|
4367
4500
|
const agentKey = asOptionalTrimmedString(env.NOLO_AGENT) ?? DEFAULT_TUI_AGENT_KEY;
|
|
4368
4501
|
const agentName = asOptionalTrimmedString(env.NOLO_AGENT_NAME) ?? "nolo";
|
|
@@ -4396,7 +4529,7 @@ function createInitialTuiState(env = process.env) {
|
|
|
4396
4529
|
userLanguage: asOptionalTrimmedString(env.NOLO_LANG),
|
|
4397
4530
|
gitStatus: void 0,
|
|
4398
4531
|
toolDisplay: normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "normal"),
|
|
4399
|
-
thinkingDisplay:
|
|
4532
|
+
thinkingDisplay: resolveThinkingDisplayMode(env),
|
|
4400
4533
|
contextWindow: resolveAgentContextWindow({ agentKey, agentName }),
|
|
4401
4534
|
estimatedContextTokens: estimateDefaultCliContextTokens({
|
|
4402
4535
|
cwd,
|
|
@@ -4520,28 +4653,53 @@ function handleTuiInput(input, state) {
|
|
|
4520
4653
|
};
|
|
4521
4654
|
}
|
|
4522
4655
|
}
|
|
4523
|
-
case "/
|
|
4524
|
-
|
|
4525
|
-
const sub = parts[0]?.trim();
|
|
4526
|
-
if (!sub) {
|
|
4656
|
+
case "/cd": {
|
|
4657
|
+
if (!argText) {
|
|
4527
4658
|
return {
|
|
4528
4659
|
nextState: state,
|
|
4529
|
-
output: t("
|
|
4660
|
+
output: `${t("cdCurrent", state.cwd)}
|
|
4661
|
+
${t("cdUsage")}`
|
|
4530
4662
|
};
|
|
4531
4663
|
}
|
|
4532
|
-
if (
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
} 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);
|
|
4539
4670
|
return {
|
|
4540
|
-
nextState: state,
|
|
4541
|
-
output: t("
|
|
4671
|
+
nextState: { ...state, cwd: previous, prevCwd: void 0, pendingCwdNotice: switchMessage2 },
|
|
4672
|
+
output: t("cdSwitched", previous),
|
|
4673
|
+
action: { type: "cwd-refresh", switchMessage: switchMessage2 }
|
|
4542
4674
|
};
|
|
4543
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
|
+
};
|
|
4544
4695
|
}
|
|
4696
|
+
case "/density":
|
|
4697
|
+
case "/tools":
|
|
4698
|
+
case "/thinking":
|
|
4699
|
+
return {
|
|
4700
|
+
nextState: state,
|
|
4701
|
+
output: t("displayFixedHint")
|
|
4702
|
+
};
|
|
4545
4703
|
case "/context":
|
|
4546
4704
|
case "/ctx":
|
|
4547
4705
|
return { nextState: state, output: renderContextPanel(state) };
|
|
@@ -4557,45 +4715,6 @@ function handleTuiInput(input, state) {
|
|
|
4557
4715
|
output: t("runtimeSet", argText)
|
|
4558
4716
|
};
|
|
4559
4717
|
}
|
|
4560
|
-
case "/tools": {
|
|
4561
|
-
if (!argText) {
|
|
4562
|
-
return {
|
|
4563
|
-
nextState: state,
|
|
4564
|
-
output: t("toolsCurrent", state.toolDisplay)
|
|
4565
|
-
};
|
|
4566
|
-
}
|
|
4567
|
-
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
4568
|
-
if (!["normal", "pro", "hide", "compact", "verbose", "on", "off"].includes(normalizedArg)) {
|
|
4569
|
-
return {
|
|
4570
|
-
nextState: state,
|
|
4571
|
-
output: t("toolsUsage")
|
|
4572
|
-
};
|
|
4573
|
-
}
|
|
4574
|
-
const nextMode = normalizeToolDisplayMode(normalizedArg, state.toolDisplay);
|
|
4575
|
-
return {
|
|
4576
|
-
nextState: { ...state, toolDisplay: nextMode },
|
|
4577
|
-
output: t("toolsSet", nextMode)
|
|
4578
|
-
};
|
|
4579
|
-
}
|
|
4580
|
-
case "/thinking": {
|
|
4581
|
-
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
4582
|
-
if (!normalizedArg) {
|
|
4583
|
-
return {
|
|
4584
|
-
nextState: state,
|
|
4585
|
-
output: t("thinkingCurrent", state.thinkingDisplay)
|
|
4586
|
-
};
|
|
4587
|
-
}
|
|
4588
|
-
if (normalizedArg !== "show" && normalizedArg !== "hide") {
|
|
4589
|
-
return {
|
|
4590
|
-
nextState: state,
|
|
4591
|
-
output: t("thinkingUsage")
|
|
4592
|
-
};
|
|
4593
|
-
}
|
|
4594
|
-
return {
|
|
4595
|
-
nextState: { ...state, thinkingDisplay: normalizedArg },
|
|
4596
|
-
output: t("thinkingSet", normalizedArg)
|
|
4597
|
-
};
|
|
4598
|
-
}
|
|
4599
4718
|
case "/auto": {
|
|
4600
4719
|
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
4601
4720
|
if (!normalizedArg) {
|
|
@@ -5004,7 +5123,7 @@ async function probeTerminalBackground(args = {}) {
|
|
|
5004
5123
|
if (typeof stdin.setRawMode !== "function") return null;
|
|
5005
5124
|
if (!isTerminal(stdin)) return null;
|
|
5006
5125
|
const wasRaw = Boolean(stdin.isRaw);
|
|
5007
|
-
return await new Promise((
|
|
5126
|
+
return await new Promise((resolve4) => {
|
|
5008
5127
|
let buffer = "";
|
|
5009
5128
|
let settled = false;
|
|
5010
5129
|
let timer;
|
|
@@ -5017,7 +5136,7 @@ async function probeTerminalBackground(args = {}) {
|
|
|
5017
5136
|
if (!wasRaw) stdin.setRawMode?.(false);
|
|
5018
5137
|
} catch {
|
|
5019
5138
|
}
|
|
5020
|
-
|
|
5139
|
+
resolve4(result);
|
|
5021
5140
|
};
|
|
5022
5141
|
const onData = (chunk) => {
|
|
5023
5142
|
buffer += chunk.toString("latin1");
|
|
@@ -5941,6 +6060,7 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5941
6060
|
}
|
|
5942
6061
|
const memoryOverlayLayer = buildMemoryOverlayLayer({ promptBlock: memoryPromptBlock });
|
|
5943
6062
|
const memoryUseGuidanceLayer = buildMemoryUseGuidanceLayer({ promptBlock: memoryPromptBlock });
|
|
6063
|
+
const cwdNoticeBlocks = state.pendingCwdNotice ? [{ content: state.pendingCwdNotice, cacheScope: "turn" }] : [];
|
|
5944
6064
|
const contextBlockScopes = partitionScopedBlocks([
|
|
5945
6065
|
...renderTurnContextBlocksWithScope(layers),
|
|
5946
6066
|
...renderTurnContextBlocksWithScope([memoryUseGuidanceLayer]),
|
|
@@ -5948,7 +6068,8 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5948
6068
|
// buildSkillContextBlocks; they stay turn-scope because the user can
|
|
5949
6069
|
// attach/detach skills between turns.
|
|
5950
6070
|
...(skillContextBlocks ?? []).map((content) => content.trim()).filter((content) => content.length > 0).map((content) => ({ content, cacheScope: "turn" })),
|
|
5951
|
-
...renderTurnContextBlocksWithScope([memoryOverlayLayer])
|
|
6071
|
+
...renderTurnContextBlocksWithScope([memoryOverlayLayer]),
|
|
6072
|
+
...cwdNoticeBlocks
|
|
5952
6073
|
]);
|
|
5953
6074
|
const result = await agentRunner({
|
|
5954
6075
|
agentName: effectiveAgentName,
|
|
@@ -6012,13 +6133,47 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
6012
6133
|
cachedMemoryOverlay: memoryPromptBlock
|
|
6013
6134
|
};
|
|
6014
6135
|
}
|
|
6015
|
-
|
|
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) {
|
|
6016
6167
|
const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
|
|
6017
6168
|
const isConfirmation = gate.kind === "confirm";
|
|
6018
6169
|
const displayCommand = commandPayload?.displayCommand ?? commandPayload?.command.join(" ") ?? gate.title;
|
|
6019
6170
|
const isInteractiveHandoff = gate.kind === "handoff" && gate.title === "This command requires an interactive terminal.";
|
|
6020
6171
|
const title = isInteractiveHandoff ? t("actionGateInteractiveTitle") : gate.title;
|
|
6021
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;
|
|
6022
6177
|
output.write(`
|
|
6023
6178
|
[nolo] ${t("actionGateNeeded")}
|
|
6024
6179
|
`);
|
|
@@ -6028,44 +6183,32 @@ function waitForActionGate(rl, input, output, gate, spawnRunner) {
|
|
|
6028
6183
|
`);
|
|
6029
6184
|
output.write(` ${displayCommand}
|
|
6030
6185
|
`);
|
|
6031
|
-
output.write(`[nolo] ${t("actionGateEnterHint")}
|
|
6186
|
+
output.write(`[nolo] ${isConfirmation ? t("actionGateConfirmHint") : t("actionGateEnterHint")}
|
|
6032
6187
|
`);
|
|
6033
|
-
|
|
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) => {
|
|
6034
6194
|
let settled = false;
|
|
6035
6195
|
const finish = (result) => {
|
|
6036
6196
|
if (settled) return;
|
|
6037
6197
|
settled = true;
|
|
6038
6198
|
rl.off("close", onClose);
|
|
6039
6199
|
rl.off("SIGINT", onSigint);
|
|
6040
|
-
|
|
6200
|
+
resolve4(result);
|
|
6041
6201
|
};
|
|
6042
|
-
const cancelResult = (reason) => (
|
|
6043
|
-
|
|
6044
|
-
metadata: {
|
|
6045
|
-
exitCode: 130,
|
|
6046
|
-
actionGateResult: { gateId: gate.id, status: "cancelled", output: reason }
|
|
6047
|
-
}
|
|
6048
|
-
});
|
|
6049
|
-
const failResult = (message) => ({
|
|
6050
|
-
content: `action gate failed: ${gate.title}`,
|
|
6051
|
-
metadata: {
|
|
6052
|
-
exitCode: 1,
|
|
6053
|
-
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
6054
|
-
}
|
|
6055
|
-
});
|
|
6202
|
+
const cancelResult = (reason) => buildGateCancelledResult(gate, reason);
|
|
6203
|
+
const failResult = (message) => buildGateFailedResult(gate, message);
|
|
6056
6204
|
const onClose = () => finish(cancelResult("readline closed"));
|
|
6057
6205
|
const onSigint = () => finish(cancelResult("interrupted"));
|
|
6058
6206
|
rl.once("close", onClose);
|
|
6059
6207
|
rl.once("SIGINT", onSigint);
|
|
6060
|
-
rl.question("", async () => {
|
|
6208
|
+
rl.question("", async (answer) => {
|
|
6061
6209
|
if (settled) return;
|
|
6062
6210
|
if (isConfirmation) {
|
|
6063
|
-
finish(
|
|
6064
|
-
content: `action gate completed: ${gate.title}`,
|
|
6065
|
-
metadata: {
|
|
6066
|
-
actionGateResult: { gateId: gate.id, status: "completed", output: "confirmed" }
|
|
6067
|
-
}
|
|
6068
|
-
});
|
|
6211
|
+
finish(isApprovedConfirmationInput(answer) ? buildGateConfirmedResult(gate) : cancelResult("confirmation declined"));
|
|
6069
6212
|
return;
|
|
6070
6213
|
}
|
|
6071
6214
|
if (!commandPayload) {
|
|
@@ -6113,48 +6256,23 @@ function isInteractiveInput(input) {
|
|
|
6113
6256
|
return Boolean(candidate.isTTY) && typeof candidate.setRawMode === "function";
|
|
6114
6257
|
}
|
|
6115
6258
|
function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
6116
|
-
const
|
|
6117
|
-
const isConfirmation
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
const title = isInteractiveHandoff ? t("actionGateInteractiveTitle") : gate.title;
|
|
6121
|
-
const body = isInteractiveHandoff ? t("actionGateInteractiveBody") : gate.body;
|
|
6122
|
-
output.write(`
|
|
6123
|
-
[nolo] ${t("actionGateNeeded")}
|
|
6124
|
-
`);
|
|
6125
|
-
output.write(`[nolo] ${title}
|
|
6126
|
-
`);
|
|
6127
|
-
if (body) output.write(`[nolo] ${body}
|
|
6128
|
-
`);
|
|
6129
|
-
output.write(` ${displayCommand}
|
|
6130
|
-
`);
|
|
6131
|
-
output.write(`[nolo] ${t("actionGateEnterHint")}
|
|
6132
|
-
`);
|
|
6133
|
-
return new Promise((resolve2) => {
|
|
6259
|
+
const meta = deriveGateMeta(gate);
|
|
6260
|
+
const { commandPayload, isConfirmation, displayCommand } = meta;
|
|
6261
|
+
writeGatePrompt(output, meta);
|
|
6262
|
+
return new Promise((resolve4) => {
|
|
6134
6263
|
const rawInput = input;
|
|
6135
6264
|
let settled = false;
|
|
6136
6265
|
let commandRunning = false;
|
|
6266
|
+
let confirmationLine = "";
|
|
6137
6267
|
const finish = (result) => {
|
|
6138
6268
|
if (settled) return;
|
|
6139
6269
|
settled = true;
|
|
6140
6270
|
hooks?.registerToken?.(null);
|
|
6141
6271
|
input.off("data", onData);
|
|
6142
|
-
|
|
6272
|
+
resolve4(result);
|
|
6143
6273
|
};
|
|
6144
|
-
const cancel = (reason) => finish(
|
|
6145
|
-
|
|
6146
|
-
metadata: {
|
|
6147
|
-
exitCode: 130,
|
|
6148
|
-
actionGateResult: { gateId: gate.id, status: "cancelled", output: reason }
|
|
6149
|
-
}
|
|
6150
|
-
});
|
|
6151
|
-
const fail = (message) => finish({
|
|
6152
|
-
content: `action gate failed: ${gate.title}`,
|
|
6153
|
-
metadata: {
|
|
6154
|
-
exitCode: 1,
|
|
6155
|
-
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
6156
|
-
}
|
|
6157
|
-
});
|
|
6274
|
+
const cancel = (reason) => finish(buildGateCancelledResult(gate, reason));
|
|
6275
|
+
const fail = (message) => finish(buildGateFailedResult(gate, message));
|
|
6158
6276
|
const runCommand = async () => {
|
|
6159
6277
|
if (settled || commandRunning) return;
|
|
6160
6278
|
commandRunning = true;
|
|
@@ -6197,21 +6315,26 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
6197
6315
|
};
|
|
6198
6316
|
const handleToken = (text) => {
|
|
6199
6317
|
if (settled || commandRunning) return;
|
|
6200
|
-
if (text.includes(
|
|
6318
|
+
if (text.includes(CTRL_C) || isConfirmation && text === ESC) {
|
|
6201
6319
|
cancel("interrupted");
|
|
6202
6320
|
return;
|
|
6203
6321
|
}
|
|
6204
|
-
if (
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
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));
|
|
6214
6333
|
}
|
|
6334
|
+
return;
|
|
6335
|
+
}
|
|
6336
|
+
if (text.includes("\r") || text.includes("\n")) {
|
|
6337
|
+
void runCommand();
|
|
6215
6338
|
}
|
|
6216
6339
|
};
|
|
6217
6340
|
const onData = (chunk) => {
|
|
@@ -6225,6 +6348,38 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
6225
6348
|
}
|
|
6226
6349
|
});
|
|
6227
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
|
+
}
|
|
6228
6383
|
async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, confirmDestructiveAction) {
|
|
6229
6384
|
const scheduleTitlePatchSync = (runResult) => {
|
|
6230
6385
|
if (!runResult.titlePatchPromise || !runResult.dialogId) return;
|
|
@@ -6355,7 +6510,9 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6355
6510
|
...runResult.title ? { dialogTitle: runResult.title } : {}
|
|
6356
6511
|
} : {},
|
|
6357
6512
|
...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {},
|
|
6358
|
-
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {}
|
|
6513
|
+
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {},
|
|
6514
|
+
// 本轮已发起 agent 调用(消息已注入),消费切换通知。
|
|
6515
|
+
pendingCwdNotice: void 0
|
|
6359
6516
|
};
|
|
6360
6517
|
if (runResult.dialogId && nextDialogKey) {
|
|
6361
6518
|
ctx.refreshDialogTotalCredits(runResult.dialogId, nextDialogKey);
|
|
@@ -6403,7 +6560,11 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6403
6560
|
// estimatedContextTokens:下一轮若 provider 不返回 usage,context
|
|
6404
6561
|
// chip 仍显示真实累计占用而不是回退到启动时的静态估算。
|
|
6405
6562
|
...runResult.turnTokens && runResult.turnTokens.input > 0 ? { estimatedContextTokens: runResult.turnTokens.input } : {},
|
|
6406
|
-
...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
|
|
6407
6568
|
};
|
|
6408
6569
|
if (runResult.dialogId && nextDialogKey) {
|
|
6409
6570
|
ctx.refreshDialogTotalCredits(runResult.dialogId, nextDialogKey);
|
|
@@ -7013,7 +7174,7 @@ function createFixedInput(output, config) {
|
|
|
7013
7174
|
const renderInputArea = (buffer, cursorPos) => {
|
|
7014
7175
|
const colorEnabled = resolveCliColorEnabled();
|
|
7015
7176
|
const cols = Math.max(1, getColumns());
|
|
7016
|
-
const completions = completeSlashCommand(buffer);
|
|
7177
|
+
const completions = completeSlashCommand(buffer, config.getCwd?.());
|
|
7017
7178
|
const sections = [];
|
|
7018
7179
|
if (completions.length > 0) {
|
|
7019
7180
|
sections.push(fitAnsiLine(dimCliText(completions.join(" "), colorEnabled), cols));
|
|
@@ -7034,6 +7195,10 @@ function createFixedInput(output, config) {
|
|
|
7034
7195
|
for (const line of queueLines) {
|
|
7035
7196
|
sections.push(fitAnsiLine(line.replace(/\r?\n/g, " "), cols));
|
|
7036
7197
|
}
|
|
7198
|
+
const attachmentLine = config.getAttachmentLine?.() ?? null;
|
|
7199
|
+
if (attachmentLine) {
|
|
7200
|
+
sections.push(fitAnsiLine(attachmentLine.replace(/\r?\n/g, " "), cols));
|
|
7201
|
+
}
|
|
7037
7202
|
const promptRaw = t("promptLabel");
|
|
7038
7203
|
const promptWidth = displayWidth(promptRaw);
|
|
7039
7204
|
const prompt = colorEnabled ? `${themeColorSequence("accent")}${promptRaw}\x1B[39m` : promptRaw;
|
|
@@ -7083,7 +7248,7 @@ function createFixedInput(output, config) {
|
|
|
7083
7248
|
}
|
|
7084
7249
|
const text = sections.join("\n");
|
|
7085
7250
|
const lines = sections.length;
|
|
7086
|
-
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);
|
|
7087
7252
|
return { text, lines, cursorCol, cursorRow: headerRows + cursorRow };
|
|
7088
7253
|
};
|
|
7089
7254
|
const repaintAt = (buffer, cursorPos, force = false) => {
|
|
@@ -7493,6 +7658,7 @@ async function runSubmittedSlashLine(line, host, actionGateHandler, confirmDestr
|
|
|
7493
7658
|
turnCtx,
|
|
7494
7659
|
emitCommandOutput,
|
|
7495
7660
|
renderHistoryToOutput,
|
|
7661
|
+
scheduleRender,
|
|
7496
7662
|
refreshDialogTotalCredits,
|
|
7497
7663
|
persistExplicitAgentSwitch,
|
|
7498
7664
|
persistAgentSelection: persistAgentSelection2,
|
|
@@ -7666,6 +7832,18 @@ async function runSubmittedSlashLine(line, host, actionGateHandler, confirmDestr
|
|
|
7666
7832
|
emitCommandOutput(t("themeRefreshFailed"));
|
|
7667
7833
|
}
|
|
7668
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
|
+
}
|
|
7669
7847
|
if (result.action?.type === "pick-agent") {
|
|
7670
7848
|
try {
|
|
7671
7849
|
const pickResult = await dialogHost.run(
|
|
@@ -8375,6 +8553,7 @@ async function runTuiWorkspace(options) {
|
|
|
8375
8553
|
turnCtx,
|
|
8376
8554
|
emitCommandOutput,
|
|
8377
8555
|
renderHistoryToOutput,
|
|
8556
|
+
scheduleRender,
|
|
8378
8557
|
refreshDialogTotalCredits,
|
|
8379
8558
|
persistExplicitAgentSwitch,
|
|
8380
8559
|
persistAgentSelection,
|
|
@@ -8407,9 +8586,16 @@ async function runTuiWorkspace(options) {
|
|
|
8407
8586
|
return dimCliText(` \u2937 ${i + 1}. ${oneLine}`, colorEnabled);
|
|
8408
8587
|
});
|
|
8409
8588
|
},
|
|
8589
|
+
getAttachmentLine: () => {
|
|
8590
|
+
const line = formatComposerAttachmentLine(state.attachedImages);
|
|
8591
|
+
return line ? dimCliText(line, resolveCliColorEnabled()) : null;
|
|
8592
|
+
},
|
|
8410
8593
|
onInputLinesChange: () => {
|
|
8411
8594
|
renderHistoryToOutput();
|
|
8412
|
-
}
|
|
8595
|
+
},
|
|
8596
|
+
// /cd 路径补全候选行渲染需要当前 cwd(读 state 而非入参,保证
|
|
8597
|
+
// /cd 切换后立即以新 cwd 渲染,composer 不必重建)。
|
|
8598
|
+
getCwd: () => state.cwd
|
|
8413
8599
|
});
|
|
8414
8600
|
fixedInput = {
|
|
8415
8601
|
...baseFixedInput,
|
|
@@ -8488,14 +8674,22 @@ async function runTuiWorkspace(options) {
|
|
|
8488
8674
|
modalOwnsKeyboard = false;
|
|
8489
8675
|
};
|
|
8490
8676
|
const actionGateHandler = async (gate) => {
|
|
8677
|
+
if (state.autoConfirm && isAutoConfirmableFileWriteGate(gate)) {
|
|
8678
|
+
return buildGateConfirmedResult(gate);
|
|
8679
|
+
}
|
|
8491
8680
|
modalOwnsKeyboard = true;
|
|
8492
8681
|
try {
|
|
8493
|
-
return await
|
|
8494
|
-
|
|
8495
|
-
|
|
8682
|
+
return await resolveActionGate(gate, {
|
|
8683
|
+
dialogHost,
|
|
8684
|
+
input,
|
|
8685
|
+
output,
|
|
8686
|
+
spawnRunner,
|
|
8496
8687
|
registerToken: (handler) => {
|
|
8497
8688
|
rawActionGateTokenHandler = handler;
|
|
8498
|
-
}
|
|
8689
|
+
},
|
|
8690
|
+
pauseComposer: () => fixedInput.pause(),
|
|
8691
|
+
resumeComposerFromSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
8692
|
+
resumeComposerFromDialog: () => fixedInput.resumeFromDialog()
|
|
8499
8693
|
});
|
|
8500
8694
|
} finally {
|
|
8501
8695
|
releaseKeyboardToComposer();
|
|
@@ -8693,6 +8887,19 @@ ${err.message}` : ""}`
|
|
|
8693
8887
|
output.write(`${refreshMsg}
|
|
8694
8888
|
`);
|
|
8695
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();
|
|
8696
8903
|
} else if (res.action) {
|
|
8697
8904
|
output.write(
|
|
8698
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"
|
|
@@ -8901,8 +9108,20 @@ ${merged}` : merged;
|
|
|
8901
9108
|
if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
|
|
8902
9109
|
return;
|
|
8903
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
|
+
}
|
|
8904
9122
|
const result = applyTuiInputKey(buffer, sequence, {}, cursorPos, {
|
|
8905
|
-
pasteStore
|
|
9123
|
+
pasteStore,
|
|
9124
|
+
cwd: state.cwd
|
|
8906
9125
|
});
|
|
8907
9126
|
if (result.redraw) {
|
|
8908
9127
|
resetHistoryFrameDiffCache(output);
|
|
@@ -8925,7 +9144,7 @@ ${merged}` : merged;
|
|
|
8925
9144
|
if (busyLock) {
|
|
8926
9145
|
const trimmedText = submittedText.trim();
|
|
8927
9146
|
const busySlashCommand = trimmedText.split(/\s+/)[0]?.toLowerCase();
|
|
8928
|
-
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";
|
|
8929
9148
|
if (isBusyLocalSlash) {
|
|
8930
9149
|
await handleBusyLocalSlash(submittedText, busySlashCommand);
|
|
8931
9150
|
return;
|
|
@@ -8995,9 +9214,9 @@ ${merged}` : merged;
|
|
|
8995
9214
|
input.on("data", onData);
|
|
8996
9215
|
fixedInput.repaint(buffer, cursorPos);
|
|
8997
9216
|
refreshGitStatus();
|
|
8998
|
-
await new Promise((
|
|
8999
|
-
resolveDone =
|
|
9000
|
-
if (done)
|
|
9217
|
+
await new Promise((resolve4) => {
|
|
9218
|
+
resolveDone = resolve4;
|
|
9219
|
+
if (done) resolve4();
|
|
9001
9220
|
});
|
|
9002
9221
|
} finally {
|
|
9003
9222
|
finish();
|
|
@@ -9011,7 +9230,11 @@ ${merged}` : merged;
|
|
|
9011
9230
|
for await (const line of rl) {
|
|
9012
9231
|
const shouldExit = await runSubmittedLine(
|
|
9013
9232
|
line,
|
|
9014
|
-
(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
|
+
),
|
|
9015
9238
|
async (request) => {
|
|
9016
9239
|
if (state.autoConfirm) return true;
|
|
9017
9240
|
rl.pause();
|
|
@@ -9050,12 +9273,16 @@ ${renderStatusLine(state)}
|
|
|
9050
9273
|
}
|
|
9051
9274
|
async function startTuiWorkspace(options) {
|
|
9052
9275
|
const themeOwner = ++latestWorkspaceThemeOwner;
|
|
9276
|
+
void sweepStaleClipboardFiles(getDefaultClipboardTempDir()).catch(() => {
|
|
9277
|
+
});
|
|
9053
9278
|
try {
|
|
9054
9279
|
return await runTuiWorkspace(options);
|
|
9055
9280
|
} finally {
|
|
9056
9281
|
if (themeOwner === latestWorkspaceThemeOwner) {
|
|
9057
9282
|
resetWorkspaceThemeState();
|
|
9058
9283
|
}
|
|
9284
|
+
void sweepStaleClipboardFiles(getDefaultClipboardTempDir()).catch(() => {
|
|
9285
|
+
});
|
|
9059
9286
|
}
|
|
9060
9287
|
}
|
|
9061
9288
|
export {
|