nolo-cli 0.49.1 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{_executeModel-KE4PQSZ3.js → _executeModel-JKEH7ACW.js} +48 -42
- package/{action-IU6ON7ZB.js → action-VSG2IYP3.js} +8 -8
- package/{addContentAction-5V5CCI3I.js → addContentAction-2HJJITDI.js} +8 -7
- package/{addDialogAgentAction-KF3KZZNZ.js → addDialogAgentAction-7BSQVVL5.js} +10 -9
- package/{agentDeleteCommand-Z67TJG3W.js → agentDeleteCommand-SVXKS5SC.js} +30 -28
- package/{agentEmailCommands-7LPIK7JE.js → agentEmailCommands-WN7QBTP3.js} +57 -52
- package/{agentListCommands-5J2IM3IT.js → agentListCommands-2BEBOQIG.js} +42 -33
- package/{agentMachineCommands-YXH6FXUQ.js → agentMachineCommands-WALP3ONU.js} +30 -28
- package/{agentRecordCommands-GZLCDVUS.js → agentRecordCommands-E652SW57.js} +55 -50
- package/{agentRunCommand-WYH5Q54Q.js → agentRunCommand-6VXWXKCS.js} +60 -53
- package/{agentRunControl-4GHHSXFZ.js → agentRunControl-LJVFDJGU.js} +3 -1
- package/{agentRuntimeLocal-A6EF3RUY.js → agentRuntimeLocal-SBG7BDFQ.js} +30 -26
- package/{agentSlice-ARTDF6VD.js → agentSlice-3WYXIGEO.js} +8 -8
- package/{agentSuperviseCommands-VB6BUS5H.js → agentSuperviseCommands-F3RFAL7K.js} +2 -2
- package/{appDeleteCommands-V2B7ZCLC.js → appDeleteCommands-NTUNMEXY.js} +31 -29
- package/{appDeployCommands-AXQU44RD.js → appDeployCommands-DISWXRTL.js} +31 -29
- package/{appDeployStatusCommands-FWGSC2UM.js → appDeployStatusCommands-IKRA6B6F.js} +31 -29
- package/{appGetCommands-67R3RFZK.js → appGetCommands-UMOP2DFV.js} +31 -29
- package/{appListCommands-TTASJPGV.js → appListCommands-ZKFD2AKS.js} +31 -29
- package/{authCommand-QOPOEYEK.js → authCommand-BS3CQC6I.js} +11 -11
- package/{chatQueueReduxAdapter-6CAHUQ4O.js → chatQueueReduxAdapter-A3YH4MT4.js} +24 -21
- package/{chunk-76UA7376.js → chunk-273FJUYI.js} +6 -6
- package/{chunk-7CH6U3FL.js → chunk-2GRGFCF6.js} +2 -4
- package/{chunk-T27IEBNQ.js → chunk-2QDDKFG5.js} +74 -1
- package/{chunk-IRJVFYOH.js → chunk-2TLYVDTN.js} +321 -1100
- package/{chunk-6BYAXNH5.js → chunk-3QOCS5IF.js} +11 -2
- package/chunk-6IGD47IC.js +19 -0
- package/{chunk-GFD7TIZU.js → chunk-6TUT5ZJD.js} +4 -6
- package/chunk-6YTOJY35.js +352 -0
- package/{chunk-B54WOZ77.js → chunk-7H7GQL6V.js} +2 -2
- package/{chunk-OYNDYVSE.js → chunk-B45YNDAE.js} +1 -1
- package/{chunk-UQWFIWHX.js → chunk-BKIDF5LV.js} +1 -1
- package/{chunk-5XCW6RQG.js → chunk-BUBPRCIU.js} +1 -1
- package/chunk-BYXBJQAS.js +0 -0
- package/{chunk-X7S7OFUX.js → chunk-CEVCRRHU.js} +4 -4
- package/{chunk-SP3DPVBH.js → chunk-DEIGUGP6.js} +2 -2
- package/{chunk-V2IPBG5U.js → chunk-DGEPT6FH.js} +1 -1
- package/{chunk-3AOLVADY.js → chunk-DVINR3PL.js} +1 -1
- package/{chunk-NN3AMBY3.js → chunk-DXOELY7S.js} +64 -69
- package/{chunk-OFZPJ3NT.js → chunk-E4MARS3Q.js} +1 -1
- package/{chunk-QUCSAM43.js → chunk-EAYBPWHX.js} +87 -66
- package/{chunk-DQLYEGP7.js → chunk-EGVY3GMT.js} +1 -1
- package/{chunk-2JYSSXLY.js → chunk-EJFW7TRP.js} +5 -26
- package/{chunk-HPZL4IBN.js → chunk-FGRCSLPV.js} +34 -45
- package/{chunk-WL3UOGYO.js → chunk-G4WSLTQF.js} +31 -97
- package/{chunk-HR5XDXYM.js → chunk-G5SQVIFZ.js} +3 -3
- package/{chunk-J3UALFHL.js → chunk-GHE5XMVR.js} +1 -1
- package/{chunk-6SMMK7MD.js → chunk-GKB4AZKV.js} +440 -2981
- package/{chunk-IKSFDJXB.js → chunk-GKNGRBE6.js} +150 -27
- package/{chunk-Q24S4NDF.js → chunk-HQTK2SFT.js} +1 -1
- package/{chunk-GDGIEGHV.js → chunk-IPTZ5TVU.js} +7 -6
- package/{chunk-4RXXP6WD.js → chunk-J7KDNHUO.js} +5 -64
- package/{chunk-QDHZCAH3.js → chunk-KNQ5LYVZ.js} +57 -2
- package/{chunk-VRJUIUIY.js → chunk-KVVNC5V3.js} +2 -2
- package/{chunk-CVT7L2WZ.js → chunk-LVCAWHI5.js} +4 -4
- package/{chunk-WX5E6HZS.js → chunk-N6SLQMSA.js} +6 -6
- package/{chunk-SQTVMYMU.js → chunk-NTZO3KX2.js} +3 -3
- package/{chunk-LGUQHYAL.js → chunk-O5FLGN2L.js} +3 -2
- package/{chunk-WKOEOQCI.js → chunk-OSUZKICS.js} +1600 -190
- package/{chunk-EXDR5D6X.js → chunk-Q2QN2RHG.js} +7 -7
- package/{chunk-L3JWI7WX.js → chunk-QOKAKDPE.js} +15 -11
- package/{chunk-757BGY6Y.js → chunk-RFYXK6KI.js} +1 -1
- package/chunk-RQSN75DW.js +1766 -0
- package/{chunk-HCMFFI2G.js → chunk-S3JNURSO.js} +2 -2
- package/{chunk-YZ2WE6CW.js → chunk-SAJSBPI2.js} +2 -2
- package/{chunk-WHVQA7PJ.js → chunk-SCBBGS2N.js} +23 -5
- package/chunk-SGSJBBKP.js +297 -0
- package/{chunk-GFUOVFQA.js → chunk-TUBNQ3OF.js} +2 -2
- package/{chunk-BANYWEYY.js → chunk-TY3ADTX5.js} +1 -1
- package/chunk-UAD2WT54.js +64 -0
- package/{chunk-SW7RCUGA.js → chunk-UEV5WVQV.js} +3 -3
- package/{chunk-EURF2SV6.js → chunk-UMCMW5R3.js} +51 -34
- package/{chunk-K524MUQC.js → chunk-VFDRZHPM.js} +16 -16
- package/{chunk-5WADL4O7.js → chunk-W22UTILW.js} +3 -3
- package/{chunk-IKTHA3JH.js → chunk-WERPP2S7.js} +2 -2
- package/{chunk-GBADO3SM.js → chunk-WSUHBABG.js} +1 -1
- package/{chunk-U5Z7LFZF.js → chunk-X3OGKR5Q.js} +4 -4
- package/{chunk-AVKUDHJO.js → chunk-X5LRMXTS.js} +10 -10
- package/{chunk-DIQCV4FR.js → chunk-X665UCNM.js} +1 -1
- package/{chunk-HCBQVVFZ.js → chunk-X7P6EJUY.js} +4 -4
- package/{chunk-HHBXCRJS.js → chunk-XOJRZUPF.js} +4 -4
- package/{chunk-MRWGHF56.js → chunk-YDH3FDFQ.js} +12 -356
- package/{chunk-TNPCQNGQ.js → chunk-YEFRCO5N.js} +4 -9
- package/{chunk-RO2IUWZE.js → chunk-YUKTCDVN.js} +1 -1
- package/{chunk-56W233KG.js → chunk-YWY25N4V.js} +1 -1
- package/{chunk-RU5D3B22.js → chunk-ZDS63Y4O.js} +2 -2
- package/chunk-ZJ7UHBJS.js +89 -0
- package/{chunk-SG65C33A.js → chunk-ZLMG6NRV.js} +4 -4
- package/{codingSkills-BYQI6EPT.js → codingSkills-FQPCEIWL.js} +2 -2
- package/contentThunks-J33BZB3E.js +71 -0
- package/{createAgentAutomationAction-7BBF5YXN.js → createAgentAutomationAction-HTMTGX6Q.js} +25 -21
- package/{createDialogAction-B5URPHP4.js → createDialogAction-WYQBSN6A.js} +27 -23
- package/{createPageAction-ISJKM5Q3.js → createPageAction-ICRRK3SA.js} +27 -22
- package/{dbSlice-FWF5F4L7.js → dbSlice-YORO4VL4.js} +6 -6
- package/{deleteFile-NPZ64DFN.js → deleteFile-JYKRT7C3.js} +4 -4
- package/{dialogCommands-XHH4MVA4.js → dialogCommands-FRSIAPKY.js} +31 -29
- package/{dialogSlice-NRAN5X7F.js → dialogSlice-5KPVIAWH.js} +24 -21
- package/{docCreateCommands-FUN2Z7HQ.js → docCreateCommands-DBRJMPDX.js} +30 -28
- package/{docDeleteCommands-OZDPFXPF.js → docDeleteCommands-BCYPLWXN.js} +31 -29
- package/{docReadCommands-FIPK7LE3.js → docReadCommands-L5JX4Q7G.js} +30 -28
- package/{docStore-LUS7SWC3.js → docStore-34NXLCEO.js} +8 -33
- package/{docUpdateCommands-BZ5GKAN4.js → docUpdateCommands-RELG7XJD.js} +30 -28
- package/fetchMessages-KZQVBXKY.js +1 -1
- package/{getPricing-HAU62AFM.js → getPricing-FM7TJZFV.js} +4 -4
- package/{handleSendMessageAction-RA4OD2ZH.js → handleSendMessageAction-MEYK7RPD.js} +25 -22
- package/index.js +64 -64
- package/{machineCommands-WDAYEFBE.js → machineCommands-YSXTOWHQ.js} +59 -54
- package/{machineWsRunDispatch-TPQ2FQVS.js → machineWsRunDispatch-DNAYOPQT.js} +54 -49
- package/memberThunks-KVPBG4V7.js +638 -0
- package/{models-4QF4BJVY.js → models-CW5EL6Z7.js} +2 -2
- package/package.json +2 -3
- package/{read-J7RVVCHH.js → read-NIOV5F7W.js} +4 -4
- package/{readDocTool-G2WBM4IH.js → readDocTool-ULKJ5BEM.js} +1 -1
- package/{readlineWorkspace-HN44KGIF.js → readlineWorkspace-KZ3LPQG2.js} +829 -393
- package/{removeDialogAgentAction-RMPISD42.js → removeDialogAgentAction-JGSCPML3.js} +12 -11
- package/{runAgentClientLoop-ZYUI22EA.js → runAgentClientLoop-O2AUHIJT.js} +46 -40
- package/{setDialogExtraReferencesAction-7BUTHDAL.js → setDialogExtraReferencesAction-CORU64NM.js} +9 -8
- package/{setPrimaryDialogAgentAction-WCYIBGZ4.js → setPrimaryDialogAgentAction-5VS2VKLZ.js} +12 -11
- package/{settingSlice-7NN2MI6Y.js → settingSlice-3GNGTC2T.js} +7 -7
- package/{skillDiscovery-COX56OBO.js → skillDiscovery-CYUCJMAG.js} +3 -3
- package/{spaceCommands-OJ2567D4.js → spaceCommands-OI7RIB2T.js} +30 -28
- package/{streamAgentChatTurn-FNFMMGNN.js → streamAgentChatTurn-TA3PGS6C.js} +61 -54
- package/{switchDialogAgentAction-WGMMQHDI.js → switchDialogAgentAction-LP433X4D.js} +10 -9
- package/{tableCommands-P2TXJ3CF.js → tableCommands-R6WFRDYF.js} +1 -1
- package/{toolApiClient-B2MFXMEG.js → toolApiClient-53U4UDFF.js} +3 -2
- package/{tools-QCDR3UMD.js → tools-6ZPQ75XA.js} +37 -32
- package/{tuiSummaryLlmCaller-LCGT62QC.js → tuiSummaryLlmCaller-YKYQB4ZL.js} +17 -15
- package/{updateDialogTitleAction-Y3OGJWDB.js → updateDialogTitleAction-LRJ7NSOS.js} +26 -22
- package/chunk-EUG45QJR.js +0 -6104
- package/spaceSlice-F7JCOZEF.js +0 -127
- package/{chunk-NQ4N4IGO.js → chunk-CS6TCJ7E.js} +3 -3
|
@@ -3,11 +3,12 @@ import {
|
|
|
3
3
|
normalizeDialogRecord,
|
|
4
4
|
readDialogSnapshot,
|
|
5
5
|
sortDialogs
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RQSN75DW.js";
|
|
7
7
|
import {
|
|
8
8
|
ANSI_ESCAPE_REGEX,
|
|
9
9
|
COLLAPSED_PASTE_PLACEHOLDER_RE,
|
|
10
10
|
THEME_PALETTES,
|
|
11
|
+
TUI_TREE_MARKER,
|
|
11
12
|
allocateCollapsedPaste,
|
|
12
13
|
applyDetectedBackground,
|
|
13
14
|
applyTerminalOutputToText,
|
|
@@ -25,12 +26,12 @@ import {
|
|
|
25
26
|
fitAnsiLine,
|
|
26
27
|
formatAssistantDisplay,
|
|
27
28
|
formatTokenCount,
|
|
28
|
-
getActiveDensity,
|
|
29
29
|
getActiveThemeMode,
|
|
30
30
|
getActiveThemeName,
|
|
31
31
|
isBalanceExhaustedError,
|
|
32
|
-
normalizeToolDisplayMode,
|
|
33
32
|
padOrTruncateToWidth,
|
|
33
|
+
polishBreathInsertsBlankBetween,
|
|
34
|
+
readAgentsMdLayerFromDisk,
|
|
34
35
|
releaseCollapsedPaste,
|
|
35
36
|
releaseCollapsedPasteReferences,
|
|
36
37
|
renderSurfaceLine,
|
|
@@ -46,7 +47,6 @@ import {
|
|
|
46
47
|
resolveTuiThemeMode,
|
|
47
48
|
runAgentTurn,
|
|
48
49
|
setActiveBrightness,
|
|
49
|
-
setActiveDensity,
|
|
50
50
|
setActiveThemeMode,
|
|
51
51
|
setActiveThemeName,
|
|
52
52
|
setMathRenderingEnabled,
|
|
@@ -64,21 +64,21 @@ import {
|
|
|
64
64
|
wrapTextToLines,
|
|
65
65
|
wrapTranscriptLine,
|
|
66
66
|
wrapTranscriptLineWithLayout
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-2TLYVDTN.js";
|
|
68
|
+
import "./chunk-LYGNQHUW.js";
|
|
69
|
+
import "./chunk-ESHYE7WU.js";
|
|
68
70
|
import {
|
|
69
71
|
listFavoriteAgentIdsAcrossServers,
|
|
70
72
|
listLocalCachedAgents,
|
|
71
73
|
listRemoteAgents,
|
|
72
74
|
listRemoteAgentsAcrossServers,
|
|
73
75
|
normalizeListedAgent
|
|
74
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-W22UTILW.js";
|
|
75
77
|
import "./chunk-ID4G2MAR.js";
|
|
76
78
|
import {
|
|
77
79
|
listUserRecordsFromServers,
|
|
78
80
|
readLiveDbRecordAfterTombstoneMerge
|
|
79
|
-
} from "./chunk-
|
|
80
|
-
import "./chunk-J3UALFHL.js";
|
|
81
|
-
import "./chunk-LYGNQHUW.js";
|
|
81
|
+
} from "./chunk-HQTK2SFT.js";
|
|
82
82
|
import {
|
|
83
83
|
createCliLocalRuntimeAdapter,
|
|
84
84
|
initCliLocale,
|
|
@@ -86,8 +86,8 @@ import {
|
|
|
86
86
|
readTimestamp,
|
|
87
87
|
setCliLocale,
|
|
88
88
|
t
|
|
89
|
-
} from "./chunk-
|
|
90
|
-
import "./chunk-
|
|
89
|
+
} from "./chunk-EAYBPWHX.js";
|
|
90
|
+
import "./chunk-X3OGKR5Q.js";
|
|
91
91
|
import "./chunk-EADNWBAZ.js";
|
|
92
92
|
import "./chunk-NI2BS6UD.js";
|
|
93
93
|
import {
|
|
@@ -97,37 +97,46 @@ import {
|
|
|
97
97
|
deleteDbRecord,
|
|
98
98
|
queryUserRecords,
|
|
99
99
|
readDbRecord
|
|
100
|
-
} from "./chunk-
|
|
101
|
-
import "./chunk-
|
|
100
|
+
} from "./chunk-EGVY3GMT.js";
|
|
101
|
+
import "./chunk-B45YNDAE.js";
|
|
102
102
|
import {
|
|
103
103
|
NOLO_DEFAULT_AGENT_KEY,
|
|
104
104
|
resolveCliAgentKeyInput
|
|
105
105
|
} from "./chunk-EKLRRZIN.js";
|
|
106
|
+
import "./chunk-GHE5XMVR.js";
|
|
107
|
+
import {
|
|
108
|
+
createChatQueueRuntime,
|
|
109
|
+
createTurnRequest,
|
|
110
|
+
normalizeRunCompletionShape
|
|
111
|
+
} from "./chunk-YPREESF4.js";
|
|
106
112
|
import "./chunk-JDSUTNYY.js";
|
|
113
|
+
import "./chunk-JBTJAPUF.js";
|
|
107
114
|
import {
|
|
115
|
+
backfillRunRecordParentDialog,
|
|
108
116
|
checkStaleRun,
|
|
109
117
|
isRunRecordClaimed,
|
|
110
118
|
listRunRecords,
|
|
111
119
|
readRunRecord
|
|
112
|
-
} from "./chunk-
|
|
113
|
-
import "./chunk-ESHYE7WU.js";
|
|
114
|
-
import "./chunk-JBTJAPUF.js";
|
|
120
|
+
} from "./chunk-SCBBGS2N.js";
|
|
115
121
|
import "./chunk-LTRXGFMS.js";
|
|
116
|
-
import "./chunk-
|
|
122
|
+
import "./chunk-YUKTCDVN.js";
|
|
117
123
|
import "./chunk-ATNTHIZI.js";
|
|
118
124
|
import "./chunk-JEXVIMYZ.js";
|
|
119
125
|
import {
|
|
120
126
|
prepareTools
|
|
121
|
-
} from "./chunk-
|
|
127
|
+
} from "./chunk-S3JNURSO.js";
|
|
128
|
+
import {
|
|
129
|
+
buildResponseGuidelines
|
|
130
|
+
} from "./chunk-6IGD47IC.js";
|
|
122
131
|
import "./chunk-HS7MLR74.js";
|
|
123
|
-
import "./chunk-
|
|
124
|
-
import "./chunk-
|
|
132
|
+
import "./chunk-RFYXK6KI.js";
|
|
133
|
+
import "./chunk-OSUZKICS.js";
|
|
125
134
|
import "./chunk-5XTOKQLW.js";
|
|
126
135
|
import "./chunk-NF64D32W.js";
|
|
127
136
|
import "./chunk-3L2WKC3W.js";
|
|
128
|
-
import "./chunk-
|
|
137
|
+
import "./chunk-ZDS63Y4O.js";
|
|
129
138
|
import "./chunk-KQHGZWSV.js";
|
|
130
|
-
import "./chunk-
|
|
139
|
+
import "./chunk-BUBPRCIU.js";
|
|
131
140
|
import {
|
|
132
141
|
clipText,
|
|
133
142
|
formatDuration,
|
|
@@ -139,43 +148,41 @@ import {
|
|
|
139
148
|
runShowsLogTail,
|
|
140
149
|
shortRunId
|
|
141
150
|
} from "./chunk-KXKQO4Q6.js";
|
|
151
|
+
import "./chunk-SGSJBBKP.js";
|
|
152
|
+
import "./chunk-TY3ADTX5.js";
|
|
153
|
+
import "./chunk-X7P6EJUY.js";
|
|
142
154
|
import "./chunk-INZZJSQF.js";
|
|
143
|
-
import "./chunk-GFD7TIZU.js";
|
|
144
|
-
import "./chunk-BANYWEYY.js";
|
|
145
|
-
import "./chunk-HCBQVVFZ.js";
|
|
146
155
|
import "./chunk-MEYIRKDN.js";
|
|
147
156
|
import "./chunk-63W5N6P3.js";
|
|
148
157
|
import "./chunk-VF4K2QE6.js";
|
|
149
|
-
import
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
} from "./chunk-YPREESF4.js";
|
|
154
|
-
import "./chunk-AVKUDHJO.js";
|
|
155
|
-
import "./chunk-6SMMK7MD.js";
|
|
158
|
+
import "./chunk-6TUT5ZJD.js";
|
|
159
|
+
import "./chunk-X5LRMXTS.js";
|
|
160
|
+
import "./chunk-GKB4AZKV.js";
|
|
161
|
+
import "./chunk-ZJ7UHBJS.js";
|
|
156
162
|
import {
|
|
157
163
|
extractReferenceKeysFromMessage
|
|
158
|
-
} from "./chunk-
|
|
164
|
+
} from "./chunk-UMCMW5R3.js";
|
|
159
165
|
import "./chunk-EVBFYPDC.js";
|
|
160
166
|
import "./chunk-H2G6JXTR.js";
|
|
161
167
|
import "./chunk-YYLHWIW6.js";
|
|
162
|
-
import "./chunk-WX5E6HZS.js";
|
|
163
168
|
import "./chunk-AGGIDPCZ.js";
|
|
164
|
-
import "./chunk-
|
|
169
|
+
import "./chunk-N6SLQMSA.js";
|
|
170
|
+
import "./chunk-ZLMG6NRV.js";
|
|
165
171
|
import "./chunk-5RGU3J7P.js";
|
|
172
|
+
import "./chunk-6YTOJY35.js";
|
|
166
173
|
import "./chunk-M76ECQRD.js";
|
|
167
|
-
import "./chunk-
|
|
174
|
+
import "./chunk-YDH3FDFQ.js";
|
|
168
175
|
import "./chunk-URMS4XY2.js";
|
|
169
176
|
import "./chunk-IA3A5373.js";
|
|
170
177
|
import "./chunk-GLKOYSRU.js";
|
|
171
178
|
import {
|
|
172
179
|
buildSkillDiscoveryContextBlock,
|
|
173
180
|
buildSkillDiscoveryContextLayer
|
|
174
|
-
} from "./chunk-
|
|
175
|
-
import "./chunk-
|
|
181
|
+
} from "./chunk-E4MARS3Q.js";
|
|
182
|
+
import "./chunk-DGEPT6FH.js";
|
|
176
183
|
import {
|
|
177
184
|
expandEnabledPacks
|
|
178
|
-
} from "./chunk-
|
|
185
|
+
} from "./chunk-O5FLGN2L.js";
|
|
179
186
|
import "./chunk-AETZ7AD6.js";
|
|
180
187
|
import "./chunk-KHCLMKZZ.js";
|
|
181
188
|
import {
|
|
@@ -183,23 +190,23 @@ import {
|
|
|
183
190
|
buildLocalWorkspaceToolset,
|
|
184
191
|
getProcessRegistry,
|
|
185
192
|
readCommandActionGatePayload
|
|
186
|
-
} from "./chunk-
|
|
187
|
-
import "./chunk-GDGIEGHV.js";
|
|
193
|
+
} from "./chunk-GKNGRBE6.js";
|
|
188
194
|
import "./chunk-ZNFJWEN4.js";
|
|
189
|
-
import "./chunk-
|
|
190
|
-
import "./chunk-
|
|
195
|
+
import "./chunk-IPTZ5TVU.js";
|
|
196
|
+
import "./chunk-LVCAWHI5.js";
|
|
197
|
+
import "./chunk-2QDDKFG5.js";
|
|
191
198
|
import "./chunk-N7J63Q6C.js";
|
|
192
199
|
import {
|
|
193
200
|
buildCurrentTimeBlock,
|
|
194
201
|
buildIdentityBlock,
|
|
195
202
|
buildRuntimeGuidanceBlocks,
|
|
196
203
|
resolveToolGuidedSections
|
|
197
|
-
} from "./chunk-
|
|
198
|
-
import "./chunk-
|
|
204
|
+
} from "./chunk-DXOELY7S.js";
|
|
205
|
+
import "./chunk-3QOCS5IF.js";
|
|
199
206
|
import {
|
|
200
207
|
resolvePlatformAuthToken
|
|
201
|
-
} from "./chunk-
|
|
202
|
-
import "./chunk-
|
|
208
|
+
} from "./chunk-DEIGUGP6.js";
|
|
209
|
+
import "./chunk-YEFRCO5N.js";
|
|
203
210
|
import {
|
|
204
211
|
isQuotaExhaustedError
|
|
205
212
|
} from "./chunk-IWUMSAQF.js";
|
|
@@ -207,7 +214,7 @@ import "./chunk-2MBTWINN.js";
|
|
|
207
214
|
import {
|
|
208
215
|
DEFAULT_CONTEXT_WINDOW,
|
|
209
216
|
getModelContextWindow
|
|
210
|
-
} from "./chunk-
|
|
217
|
+
} from "./chunk-UEV5WVQV.js";
|
|
211
218
|
import {
|
|
212
219
|
buildCompactionMetricsFromPlan,
|
|
213
220
|
buildCompactionUserContent,
|
|
@@ -218,28 +225,28 @@ import {
|
|
|
218
225
|
formatMessagesForSummaryWithTruncation,
|
|
219
226
|
planCompression,
|
|
220
227
|
serializeMessageContent
|
|
221
|
-
} from "./chunk-
|
|
222
|
-
import "./chunk-
|
|
223
|
-
import "./chunk-
|
|
224
|
-
import "./chunk-
|
|
225
|
-
import "./chunk-QDHZCAH3.js";
|
|
228
|
+
} from "./chunk-G5SQVIFZ.js";
|
|
229
|
+
import "./chunk-KVVNC5V3.js";
|
|
230
|
+
import "./chunk-BYXBJQAS.js";
|
|
231
|
+
import "./chunk-KNQ5LYVZ.js";
|
|
226
232
|
import {
|
|
227
233
|
compactWhitespace
|
|
228
234
|
} from "./chunk-DWLEOOGR.js";
|
|
235
|
+
import "./chunk-CS6TCJ7E.js";
|
|
236
|
+
import "./chunk-FD36SCCD.js";
|
|
229
237
|
import "./chunk-ZHXJ6M7T.js";
|
|
230
238
|
import {
|
|
231
239
|
toErrorMessage
|
|
232
240
|
} from "./chunk-HNMXYYJR.js";
|
|
233
241
|
import {
|
|
234
|
-
buildAgentsMdLayer,
|
|
235
242
|
buildMemoryOverlayLayer,
|
|
236
243
|
buildMemoryUseGuidanceLayer,
|
|
237
244
|
partitionScopedBlocks,
|
|
238
245
|
renderTurnContextBlocksWithScope
|
|
239
|
-
} from "./chunk-
|
|
246
|
+
} from "./chunk-DVINR3PL.js";
|
|
240
247
|
import {
|
|
241
248
|
buildUserResponseLanguageContext
|
|
242
|
-
} from "./chunk-
|
|
249
|
+
} from "./chunk-2GRGFCF6.js";
|
|
243
250
|
import {
|
|
244
251
|
canonicalizeToolNames
|
|
245
252
|
} from "./chunk-O6OSWFZQ.js";
|
|
@@ -268,19 +275,20 @@ import {
|
|
|
268
275
|
import {
|
|
269
276
|
DEFAULT_NOLO_SERVER_URL
|
|
270
277
|
} from "./chunk-OLZBQWZU.js";
|
|
271
|
-
import "./chunk-
|
|
272
|
-
import "./chunk-
|
|
273
|
-
import "./chunk-
|
|
274
|
-
import "./chunk-
|
|
278
|
+
import "./chunk-YWY25N4V.js";
|
|
279
|
+
import "./chunk-G4WSLTQF.js";
|
|
280
|
+
import "./chunk-NTZO3KX2.js";
|
|
281
|
+
import "./chunk-CEVCRRHU.js";
|
|
275
282
|
import "./chunk-Y5GCAMGP.js";
|
|
276
283
|
import "./chunk-UZ6XXCVR.js";
|
|
277
284
|
import "./chunk-KX6YBIHG.js";
|
|
278
|
-
import "./chunk-
|
|
279
|
-
import "./chunk-
|
|
285
|
+
import "./chunk-J7KDNHUO.js";
|
|
286
|
+
import "./chunk-UAD2WT54.js";
|
|
287
|
+
import "./chunk-273FJUYI.js";
|
|
280
288
|
import "./chunk-SVEUG45B.js";
|
|
281
289
|
import "./chunk-WWC7I6TA.js";
|
|
282
290
|
import "./chunk-I42VC5KR.js";
|
|
283
|
-
import "./chunk-
|
|
291
|
+
import "./chunk-SAJSBPI2.js";
|
|
284
292
|
import {
|
|
285
293
|
asTrimmedLowercaseString
|
|
286
294
|
} from "./chunk-QSJ3HFEF.js";
|
|
@@ -289,18 +297,18 @@ import {
|
|
|
289
297
|
BUILTIN_NOLO_AGENT_MODEL,
|
|
290
298
|
BUILTIN_NOLO_AGENT_NAME,
|
|
291
299
|
builtinAgentCatalogEntryById
|
|
292
|
-
} from "./chunk-
|
|
300
|
+
} from "./chunk-EJFW7TRP.js";
|
|
293
301
|
import {
|
|
294
302
|
extractCustomId,
|
|
295
303
|
parsePublicAgentId
|
|
296
304
|
} from "./chunk-BJIRLHJR.js";
|
|
297
|
-
import "./chunk-
|
|
298
|
-
import "./chunk-
|
|
305
|
+
import "./chunk-XOJRZUPF.js";
|
|
306
|
+
import "./chunk-QOKAKDPE.js";
|
|
299
307
|
import "./chunk-OW765XBU.js";
|
|
300
308
|
import "./chunk-GBRG75BQ.js";
|
|
301
|
-
import "./chunk-KUG52IAP.js";
|
|
302
309
|
import "./chunk-3EUW3WEO.js";
|
|
303
310
|
import "./chunk-U6VC4MU4.js";
|
|
311
|
+
import "./chunk-KUG52IAP.js";
|
|
304
312
|
import "./chunk-LCBAMY2M.js";
|
|
305
313
|
import "./chunk-4SN6J65J.js";
|
|
306
314
|
import "./chunk-CF7PE763.js";
|
|
@@ -624,9 +632,9 @@ function createRawKeyReader(input) {
|
|
|
624
632
|
};
|
|
625
633
|
const resolveWaiter = (value) => {
|
|
626
634
|
if (!waiter) return;
|
|
627
|
-
const
|
|
635
|
+
const resolve4 = waiter;
|
|
628
636
|
waiter = null;
|
|
629
|
-
|
|
637
|
+
resolve4(value);
|
|
630
638
|
};
|
|
631
639
|
const tryDeliver = () => {
|
|
632
640
|
if (!waiter) return;
|
|
@@ -683,12 +691,12 @@ function createRawKeyReader(input) {
|
|
|
683
691
|
input.on("close", onClose);
|
|
684
692
|
input.on("end", onClose);
|
|
685
693
|
input.resume?.();
|
|
686
|
-
const reader = () => new Promise((
|
|
694
|
+
const reader = () => new Promise((resolve4) => {
|
|
687
695
|
if (closed) {
|
|
688
|
-
|
|
696
|
+
resolve4(drainClosed());
|
|
689
697
|
return;
|
|
690
698
|
}
|
|
691
|
-
waiter =
|
|
699
|
+
waiter = resolve4;
|
|
692
700
|
tryDeliver();
|
|
693
701
|
});
|
|
694
702
|
reader.dispose = () => {
|
|
@@ -1225,7 +1233,81 @@ function appendLocalTurn(history, command, output) {
|
|
|
1225
1233
|
trimHistoryToBudget(history);
|
|
1226
1234
|
resetStreamingTurnCache();
|
|
1227
1235
|
}
|
|
1236
|
+
var TOOL_SUCCESS_LINE_RE = /^(▸ .*?)(?: ×(\d+))?( ✓)$/;
|
|
1237
|
+
function applyTreeRewrite(text, chunk) {
|
|
1238
|
+
if (!chunk.startsWith(TUI_TREE_MARKER)) return null;
|
|
1239
|
+
const payload = chunk.slice(TUI_TREE_MARKER.length).replace(/\u0002\n?$/, "");
|
|
1240
|
+
const tree = `\u2022 ${payload}`;
|
|
1241
|
+
const hadTrailingNewline = text.endsWith("\n");
|
|
1242
|
+
const body = hadTrailingNewline ? text.slice(0, -1) : text;
|
|
1243
|
+
const bodyLines = body.split("\n");
|
|
1244
|
+
const plainLines = bodyLines.map((line) => stripAnsi(line));
|
|
1245
|
+
const tail = plainLines.at(-1) ?? "";
|
|
1246
|
+
let prefix;
|
|
1247
|
+
if (tail.trimStart().startsWith("\u25B8 ")) {
|
|
1248
|
+
prefix = bodyLines.length < 2 ? "" : `${bodyLines.slice(0, -1).join("\n")}
|
|
1249
|
+
`;
|
|
1250
|
+
} else if (tail.trimStart().startsWith("\u2514\u2500\u2500 ")) {
|
|
1251
|
+
const headerIndex = plainLines.findLastIndex((line) => line.trimStart().startsWith("\u2022 "));
|
|
1252
|
+
if (headerIndex < 0) return null;
|
|
1253
|
+
prefix = `${bodyLines.slice(0, headerIndex).join("\n")}${headerIndex > 0 ? "\n" : ""}`;
|
|
1254
|
+
} else return null;
|
|
1255
|
+
return `${prefix}${tree}
|
|
1256
|
+
`;
|
|
1257
|
+
}
|
|
1258
|
+
function foldToolSuccessLine(text, chunk) {
|
|
1259
|
+
const plain = stripAnsi(chunk).replace(/\n+$/, "");
|
|
1260
|
+
if (!plain || plain.includes("\n") || !TOOL_SUCCESS_LINE_RE.test(plain)) return null;
|
|
1261
|
+
const hadTrailingNewline = text.endsWith("\n");
|
|
1262
|
+
const body = hadTrailingNewline ? text.slice(0, -1) : text;
|
|
1263
|
+
const newlineAt = body.lastIndexOf("\n");
|
|
1264
|
+
const tail = newlineAt === -1 ? body : body.slice(newlineAt + 1);
|
|
1265
|
+
const match = TOOL_SUCCESS_LINE_RE.exec(stripAnsi(tail));
|
|
1266
|
+
if (!match || `${match[1]}${match[3]}` !== plain) return null;
|
|
1267
|
+
const count = (match[2] ? Number(match[2]) : 1) + 1;
|
|
1268
|
+
const anchor = tail.lastIndexOf(" ");
|
|
1269
|
+
if (anchor < 0) return null;
|
|
1270
|
+
const head = tail.slice(0, anchor).replace(/\s×\d+$/, "");
|
|
1271
|
+
const merged = `${head} \xD7${count}${tail.slice(anchor)}`;
|
|
1272
|
+
const prefix = newlineAt === -1 ? "" : body.slice(0, newlineAt + 1);
|
|
1273
|
+
return `${prefix}${merged}${hadTrailingNewline ? "\n" : ""}`;
|
|
1274
|
+
}
|
|
1228
1275
|
function applyOutputChunkToCurrentTurn(history, chunk, kind = "assistant") {
|
|
1276
|
+
if (kind === "tool") {
|
|
1277
|
+
if (chunk.startsWith(TUI_TREE_MARKER)) {
|
|
1278
|
+
const rewrittenTree = applyTreeRewrite(history.currentContent, chunk);
|
|
1279
|
+
if (rewrittenTree === null) {
|
|
1280
|
+
const safe = chunk.slice(TUI_TREE_MARKER.length).replace(/\u0002/g, "");
|
|
1281
|
+
const leaves = safe.split("\n").filter((line) => /^(?:├── |└── )/.test(line));
|
|
1282
|
+
const newest = leaves.at(-1)?.replace(/^(?:├── |└── )/, "\u25B8 ") ?? "";
|
|
1283
|
+
if (!newest) return false;
|
|
1284
|
+
const flat = `${newest}
|
|
1285
|
+
`;
|
|
1286
|
+
history.currentContent = applyTerminalOutputToText(history.currentContent, flat);
|
|
1287
|
+
appendCurrentBlock(history, kind, flat);
|
|
1288
|
+
return false;
|
|
1289
|
+
}
|
|
1290
|
+
const treeContent = rewrittenTree;
|
|
1291
|
+
history.currentContent = treeContent;
|
|
1292
|
+
const lastBlock = history.currentBlocks.at(-1);
|
|
1293
|
+
const treeLines = treeContent.split("\n");
|
|
1294
|
+
const treeHeaderIndex = treeLines.findIndex((line) => line.trimStart().startsWith("\u2022 "));
|
|
1295
|
+
const treeBlock = treeHeaderIndex >= 0 ? treeLines.slice(treeHeaderIndex).join("\n") : treeContent;
|
|
1296
|
+
if (lastBlock?.kind === "tool") lastBlock.content = lastBlock.content.replace(/[^\n]*$/, "") + treeBlock;
|
|
1297
|
+
else history.currentBlocks.push({ kind: "tool", content: treeBlock });
|
|
1298
|
+
return true;
|
|
1299
|
+
}
|
|
1300
|
+
const foldedContent = foldToolSuccessLine(history.currentContent, chunk);
|
|
1301
|
+
if (foldedContent !== null) {
|
|
1302
|
+
history.currentContent = foldedContent;
|
|
1303
|
+
const lastBlock = history.currentBlocks.at(-1);
|
|
1304
|
+
if (lastBlock?.kind === "tool") {
|
|
1305
|
+
const foldedBlock = foldToolSuccessLine(lastBlock.content, chunk);
|
|
1306
|
+
if (foldedBlock !== null) lastBlock.content = foldedBlock;
|
|
1307
|
+
}
|
|
1308
|
+
return true;
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1229
1311
|
const next = applyTerminalOutputToText(history.currentContent, chunk);
|
|
1230
1312
|
if (next === history.currentContent) return false;
|
|
1231
1313
|
history.currentContent = next;
|
|
@@ -1385,9 +1467,9 @@ function layoutTurnRows(role, content, contentWidth, colorEnabled, command) {
|
|
|
1385
1467
|
}
|
|
1386
1468
|
return rows.length > 0 ? rows : [{ rendered: "", sourceStart: 0, sourceEnd: 0, prefixWidth: 0 }];
|
|
1387
1469
|
}
|
|
1388
|
-
function getTurnLayoutRows(turn, contentWidth, colorEnabled,
|
|
1470
|
+
function getTurnLayoutRows(turn, contentWidth, colorEnabled, themeFingerprint) {
|
|
1389
1471
|
const cached = getCachedTurnLine(turn);
|
|
1390
|
-
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.
|
|
1472
|
+
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.themeFingerprint === themeFingerprint) {
|
|
1391
1473
|
return cached.layoutRows;
|
|
1392
1474
|
}
|
|
1393
1475
|
const layoutRows = layoutTurnRows(turn.role, turn.content, contentWidth, colorEnabled, turn.command);
|
|
@@ -1395,7 +1477,6 @@ function getTurnLayoutRows(turn, contentWidth, colorEnabled, density, themeFinge
|
|
|
1395
1477
|
setCachedTurnLine(turn, {
|
|
1396
1478
|
width: contentWidth,
|
|
1397
1479
|
color: colorEnabled,
|
|
1398
|
-
density,
|
|
1399
1480
|
themeFingerprint,
|
|
1400
1481
|
lines,
|
|
1401
1482
|
layoutRows
|
|
@@ -1409,6 +1490,40 @@ var streamingTurnCache = null;
|
|
|
1409
1490
|
function resetStreamingTurnCache() {
|
|
1410
1491
|
streamingTurnCache = null;
|
|
1411
1492
|
}
|
|
1493
|
+
function countFenceFlips(text) {
|
|
1494
|
+
const matches = text.match(/^[ \t]*```/gm);
|
|
1495
|
+
return matches ? matches.length : 0;
|
|
1496
|
+
}
|
|
1497
|
+
var HEADING_LIKE_RE = /^#{1,3} /;
|
|
1498
|
+
function isPipeRowLike(line) {
|
|
1499
|
+
const trimmed = line.trim();
|
|
1500
|
+
return trimmed.length > 0 && trimmed.startsWith("|");
|
|
1501
|
+
}
|
|
1502
|
+
function isSuspiciousAppend(newTail, fenceParityEven) {
|
|
1503
|
+
if (!fenceParityEven) return true;
|
|
1504
|
+
if (newTail.includes("\r")) return true;
|
|
1505
|
+
if (newTail.includes("```")) return true;
|
|
1506
|
+
if (newTail.includes("$$") || newTail.includes("\\[") || newTail.includes("\\]")) {
|
|
1507
|
+
return true;
|
|
1508
|
+
}
|
|
1509
|
+
if (/\n{4,}/.test(newTail)) return true;
|
|
1510
|
+
if (newTail.includes("\0")) return true;
|
|
1511
|
+
return hasPipeRowLine(newTail);
|
|
1512
|
+
}
|
|
1513
|
+
function hasPipeRowLine(text) {
|
|
1514
|
+
const lines = text.split("\n");
|
|
1515
|
+
return lines.some((line) => isPipeRowLike(line));
|
|
1516
|
+
}
|
|
1517
|
+
function isSuspiciousBoundary(committedLastLine, newTail) {
|
|
1518
|
+
const newlineIdx = newTail.indexOf("\n");
|
|
1519
|
+
const firstLine = newlineIdx === -1 ? newTail : newTail.slice(0, newlineIdx);
|
|
1520
|
+
if (HEADING_LIKE_RE.test(firstLine) && committedLastLine !== "") return true;
|
|
1521
|
+
if (HEADING_LIKE_RE.test(committedLastLine) && firstLine !== "") return true;
|
|
1522
|
+
if (isPipeRowLike(firstLine) || isPipeRowLike(committedLastLine)) {
|
|
1523
|
+
return true;
|
|
1524
|
+
}
|
|
1525
|
+
return polishBreathInsertsBlankBetween(committedLastLine, firstLine);
|
|
1526
|
+
}
|
|
1412
1527
|
function renderPrefixTurnBlock(role, content, contentWidth, colorEnabled) {
|
|
1413
1528
|
content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1414
1529
|
if (role === "user") {
|
|
@@ -1450,75 +1565,105 @@ function renderTailTurnBlock(role, content, contentWidth, colorEnabled) {
|
|
|
1450
1565
|
return lines;
|
|
1451
1566
|
}
|
|
1452
1567
|
}
|
|
1453
|
-
function getStreamingTurnLines(role, content, contentWidth, colorEnabled,
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
if (!
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1568
|
+
function getStreamingTurnLines(role, content, contentWidth, colorEnabled, themeFingerprint) {
|
|
1569
|
+
const forceValidate = process.env.NOLO_TUI_RENDER_VALIDATE === "1";
|
|
1570
|
+
let cache = streamingTurnCache;
|
|
1571
|
+
const geometryChanged = !cache || cache.role !== role || cache.contentWidth !== contentWidth || cache.colorEnabled !== colorEnabled || cache.themeFingerprint !== themeFingerprint;
|
|
1572
|
+
if (geometryChanged || !content.startsWith(cache.fullContent)) {
|
|
1573
|
+
return rebuildStreamingCache(content, role, contentWidth, colorEnabled, themeFingerprint);
|
|
1574
|
+
}
|
|
1575
|
+
if (content === cache.fullContent && cache.lastResult) {
|
|
1576
|
+
return cache.lastResult;
|
|
1577
|
+
}
|
|
1578
|
+
const suffix = content.slice(cache.fullContent.length);
|
|
1579
|
+
if (suffix === "") {
|
|
1580
|
+
return cache.lastResult ?? cache.committedLines;
|
|
1581
|
+
}
|
|
1582
|
+
const renderFull = () => {
|
|
1583
|
+
const lines = renderTurnBlock(role, content, contentWidth, colorEnabled);
|
|
1584
|
+
cache.fullContent = content;
|
|
1585
|
+
cache.fenceFlips = countFenceFlips(content);
|
|
1586
|
+
const lastNewline = content.lastIndexOf("\n");
|
|
1587
|
+
cache.completeContentLength = lastNewline + 1;
|
|
1588
|
+
cache.committedLines = lastNewline === -1 ? [] : renderTurnBlock(role, content.slice(0, lastNewline), contentWidth, colorEnabled);
|
|
1589
|
+
cache.pendingTail = content.slice(lastNewline + 1);
|
|
1590
|
+
cache.committedLastLine = lastNewline === -1 ? "" : lastLogicalLineOf(content.slice(0, lastNewline + 1));
|
|
1591
|
+
cache.lastResult = lines;
|
|
1592
|
+
return lines;
|
|
1593
|
+
};
|
|
1594
|
+
const newTail = cache.pendingTail + suffix;
|
|
1595
|
+
if (!cache.fastPathEnabled || isSuspiciousAppend(newTail, cache.fenceFlips % 2 === 0) || isSuspiciousBoundary(cache.committedLastLine, newTail)) {
|
|
1596
|
+
return renderFull();
|
|
1597
|
+
}
|
|
1598
|
+
const tailRenderer = cache.completeContentLength === 0 ? renderPrefixTurnBlock : renderTailTurnBlock;
|
|
1599
|
+
const tailLines = tailRenderer(role, newTail, contentWidth, colorEnabled);
|
|
1600
|
+
const composed = cache.completeContentLength === 0 ? tailLines : [...cache.committedLines, ...tailLines];
|
|
1601
|
+
if (!cache.spliceValidated || forceValidate) {
|
|
1602
|
+
const full = renderTurnBlock(role, content, contentWidth, colorEnabled);
|
|
1603
|
+
cache.spliceValidated = true;
|
|
1604
|
+
if (composed.length === full.length && composed.every((line, index) => line === full[index])) {
|
|
1605
|
+
commitCompletedTail(cache, content, newTail, role, contentWidth, colorEnabled);
|
|
1606
|
+
cache.lastResult = composed;
|
|
1607
|
+
return composed;
|
|
1608
|
+
}
|
|
1609
|
+
cache.fastPathEnabled = false;
|
|
1610
|
+
return renderFull();
|
|
1611
|
+
}
|
|
1612
|
+
commitCompletedTail(cache, content, newTail, role, contentWidth, colorEnabled);
|
|
1613
|
+
cache.lastResult = composed;
|
|
1614
|
+
return composed;
|
|
1615
|
+
}
|
|
1616
|
+
function lastLogicalLineOf(content) {
|
|
1617
|
+
const trimmed = content.replace(/\n$/, "");
|
|
1618
|
+
const idx = trimmed.lastIndexOf("\n");
|
|
1619
|
+
return idx === -1 ? trimmed : trimmed.slice(idx + 1);
|
|
1620
|
+
}
|
|
1621
|
+
function rebuildStreamingCache(content, role, contentWidth, colorEnabled, themeFingerprint) {
|
|
1622
|
+
const lines = renderTurnBlock(role, content, contentWidth, colorEnabled);
|
|
1623
|
+
const lastNewline = content.lastIndexOf("\n");
|
|
1624
|
+
streamingTurnCache = {
|
|
1625
|
+
role,
|
|
1626
|
+
contentWidth,
|
|
1627
|
+
colorEnabled,
|
|
1628
|
+
themeFingerprint,
|
|
1629
|
+
fullContent: content,
|
|
1630
|
+
// committed 渲染源剥掉段尾 \n(幽灵空行修正,见 renderFull 注释)。
|
|
1631
|
+
committedLines: lastNewline === -1 ? [] : renderTurnBlock(role, content.slice(0, lastNewline), contentWidth, colorEnabled),
|
|
1632
|
+
completeContentLength: lastNewline + 1,
|
|
1633
|
+
pendingTail: content.slice(lastNewline + 1),
|
|
1634
|
+
fenceFlips: countFenceFlips(content),
|
|
1635
|
+
committedLastLine: lastNewline === -1 ? "" : lastLogicalLineOf(content.slice(0, lastNewline + 1)),
|
|
1636
|
+
fastPathEnabled: true,
|
|
1637
|
+
spliceValidated: false,
|
|
1638
|
+
lastResult: lines
|
|
1639
|
+
};
|
|
1640
|
+
return lines;
|
|
1641
|
+
}
|
|
1642
|
+
function commitCompletedTail(cache, content, newTail, role, contentWidth, colorEnabled) {
|
|
1643
|
+
const lastNewline = newTail.lastIndexOf("\n");
|
|
1644
|
+
if (lastNewline !== -1) {
|
|
1645
|
+
const completePart = newTail.slice(0, lastNewline + 1);
|
|
1646
|
+
const renderSource = completePart.slice(0, -1);
|
|
1647
|
+
const renderer = cache.completeContentLength === 0 ? renderPrefixTurnBlock : renderTailTurnBlock;
|
|
1648
|
+
cache.committedLines.push(
|
|
1649
|
+
...renderer(role, renderSource, contentWidth, colorEnabled)
|
|
1650
|
+
);
|
|
1651
|
+
cache.completeContentLength += completePart.length;
|
|
1652
|
+
cache.fenceFlips += countFenceFlips(completePart);
|
|
1653
|
+
cache.committedLastLine = lastLogicalLineOf(completePart);
|
|
1654
|
+
cache.pendingTail = newTail.slice(lastNewline + 1);
|
|
1507
1655
|
}
|
|
1508
|
-
|
|
1509
|
-
const tailLines = renderTailTurnBlock(role, tailContent, contentWidth, colorEnabled);
|
|
1510
|
-
return [...streamingTurnCache.prefixLines, ...tailLines];
|
|
1656
|
+
cache.fullContent = content;
|
|
1511
1657
|
}
|
|
1512
1658
|
function countTurnLines(role, content, contentWidth, command) {
|
|
1513
1659
|
return layoutTurnRows(role, content, contentWidth, false, command).length;
|
|
1514
1660
|
}
|
|
1515
1661
|
function buildTurnOffsets(history, contentWidth) {
|
|
1516
|
-
const density = getActiveDensity();
|
|
1517
1662
|
const entries = [];
|
|
1518
1663
|
let offset = 0;
|
|
1519
1664
|
for (let i = 0; i < history.turns.length; i++) {
|
|
1520
1665
|
const turn = history.turns[i];
|
|
1521
|
-
const separatorAbove =
|
|
1666
|
+
const separatorAbove = i > 0 && turn.role === "user" ? 1 : 0;
|
|
1522
1667
|
offset += separatorAbove;
|
|
1523
1668
|
const cacheMap = turnLineCountCache.get(turn);
|
|
1524
1669
|
let lineCount;
|
|
@@ -1547,7 +1692,6 @@ function getAllTurnEntries(history, contentWidth) {
|
|
|
1547
1692
|
const { entries, totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
1548
1693
|
const turns = [...history.turns];
|
|
1549
1694
|
if (history.currentRole !== null && history.currentContent) {
|
|
1550
|
-
const density = getActiveDensity();
|
|
1551
1695
|
const colorEnabled = resolveCliColorEnabled();
|
|
1552
1696
|
const themeFingerprint = tuiRenderThemeFingerprint(colorEnabled);
|
|
1553
1697
|
const streamingLines = getStreamingTurnLines(
|
|
@@ -1555,10 +1699,9 @@ function getAllTurnEntries(history, contentWidth) {
|
|
|
1555
1699
|
history.currentContent,
|
|
1556
1700
|
contentWidth,
|
|
1557
1701
|
colorEnabled,
|
|
1558
|
-
density,
|
|
1559
1702
|
themeFingerprint
|
|
1560
1703
|
);
|
|
1561
|
-
const sep = currentTurnSeparator(history
|
|
1704
|
+
const sep = currentTurnSeparator(history);
|
|
1562
1705
|
const startRow = finalizedLines + sep;
|
|
1563
1706
|
entries.push({
|
|
1564
1707
|
startRow,
|
|
@@ -1573,12 +1716,11 @@ function getAllTurnEntries(history, contentWidth) {
|
|
|
1573
1716
|
}
|
|
1574
1717
|
return { entries, totalLines: finalizedLines, turns };
|
|
1575
1718
|
}
|
|
1576
|
-
function currentTurnSeparator(history
|
|
1577
|
-
return
|
|
1719
|
+
function currentTurnSeparator(history) {
|
|
1720
|
+
return history.turns.length > 0 && history.currentRole === "user" ? 1 : 0;
|
|
1578
1721
|
}
|
|
1579
1722
|
function buildHistoryLayoutRows(history, contentWidth) {
|
|
1580
1723
|
const colorEnabled = resolveCliColorEnabled();
|
|
1581
|
-
const density = getActiveDensity();
|
|
1582
1724
|
const themeFingerprint = tuiRenderThemeFingerprint(colorEnabled);
|
|
1583
1725
|
const rows = [];
|
|
1584
1726
|
const separatorRow = () => ({
|
|
@@ -1589,20 +1731,19 @@ function buildHistoryLayoutRows(history, contentWidth) {
|
|
|
1589
1731
|
});
|
|
1590
1732
|
for (let i = 0; i < history.turns.length; i++) {
|
|
1591
1733
|
const turn = history.turns[i];
|
|
1592
|
-
if (
|
|
1734
|
+
if (i > 0 && turn.role === "user") {
|
|
1593
1735
|
rows.push(separatorRow());
|
|
1594
1736
|
}
|
|
1595
1737
|
rows.push(...getTurnLayoutRows(
|
|
1596
1738
|
turn,
|
|
1597
1739
|
contentWidth,
|
|
1598
1740
|
colorEnabled,
|
|
1599
|
-
density,
|
|
1600
1741
|
themeFingerprint
|
|
1601
1742
|
));
|
|
1602
1743
|
}
|
|
1603
1744
|
if (history.currentRole !== null && history.currentContent) {
|
|
1604
1745
|
const i = history.turns.length;
|
|
1605
|
-
if (
|
|
1746
|
+
if (i > 0 && history.currentRole === "user") {
|
|
1606
1747
|
rows.push(separatorRow());
|
|
1607
1748
|
}
|
|
1608
1749
|
rows.push(
|
|
@@ -1625,7 +1766,6 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
1625
1766
|
const visibleHeight = Math.max(1, rows - inputLines);
|
|
1626
1767
|
const contentWidth = Math.max(1, columns - 1);
|
|
1627
1768
|
const colorEnabled = resolveCliColorEnabled();
|
|
1628
|
-
const density = getActiveDensity();
|
|
1629
1769
|
const themeFingerprint = tuiRenderThemeFingerprint(colorEnabled);
|
|
1630
1770
|
const { entries, totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
1631
1771
|
let currentLines = [];
|
|
@@ -1636,10 +1776,9 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
1636
1776
|
history.currentContent,
|
|
1637
1777
|
contentWidth,
|
|
1638
1778
|
colorEnabled,
|
|
1639
|
-
density,
|
|
1640
1779
|
themeFingerprint
|
|
1641
1780
|
);
|
|
1642
|
-
const sep = currentTurnSeparator(history
|
|
1781
|
+
const sep = currentTurnSeparator(history);
|
|
1643
1782
|
currentStart = finalizedLines + sep;
|
|
1644
1783
|
}
|
|
1645
1784
|
const totalLines = currentStart >= 0 ? currentStart + currentLines.length : finalizedLines;
|
|
@@ -1670,7 +1809,7 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
1670
1809
|
const turn = history.turns[i];
|
|
1671
1810
|
const cached = getCachedTurnLine(turn);
|
|
1672
1811
|
let layoutRows;
|
|
1673
|
-
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.
|
|
1812
|
+
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.themeFingerprint === themeFingerprint) {
|
|
1674
1813
|
layoutRows = cached.layoutRows;
|
|
1675
1814
|
} else {
|
|
1676
1815
|
renderCacheMissCount += 1;
|
|
@@ -1678,7 +1817,6 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
1678
1817
|
turn,
|
|
1679
1818
|
contentWidth,
|
|
1680
1819
|
colorEnabled,
|
|
1681
|
-
density,
|
|
1682
1820
|
themeFingerprint
|
|
1683
1821
|
);
|
|
1684
1822
|
}
|
|
@@ -1690,7 +1828,7 @@ function renderHistory(output, history, inputLines, selection) {
|
|
|
1690
1828
|
}
|
|
1691
1829
|
}
|
|
1692
1830
|
if (currentStart >= 0) {
|
|
1693
|
-
const separatorAbove = currentTurnSeparator(history
|
|
1831
|
+
const separatorAbove = currentTurnSeparator(history);
|
|
1694
1832
|
if (separatorAbove > 0) {
|
|
1695
1833
|
const sepRow = currentStart - 1;
|
|
1696
1834
|
if (sepRow >= winStart && sepRow < winEnd) {
|
|
@@ -1750,6 +1888,7 @@ function createHistoryOutputStream(history, onUpdate) {
|
|
|
1750
1888
|
const stream = {
|
|
1751
1889
|
isTTY: true,
|
|
1752
1890
|
assistantLabelManaged: true,
|
|
1891
|
+
tuiTrees: true,
|
|
1753
1892
|
write(chunk) {
|
|
1754
1893
|
const text = typeof chunk === "string" ? chunk : chunk.toString();
|
|
1755
1894
|
if (applyOutputChunkToCurrentTurn(history, text)) {
|
|
@@ -1758,9 +1897,9 @@ function createHistoryOutputStream(history, onUpdate) {
|
|
|
1758
1897
|
return true;
|
|
1759
1898
|
},
|
|
1760
1899
|
writeToolBlock(chunk) {
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1900
|
+
const applied = applyOutputChunkToCurrentTurn(history, chunk, "tool");
|
|
1901
|
+
if (applied) onUpdate();
|
|
1902
|
+
return applied;
|
|
1764
1903
|
}
|
|
1765
1904
|
};
|
|
1766
1905
|
return stream;
|
|
@@ -1774,7 +1913,7 @@ function applyScrollAction(history, action, output, inputLines) {
|
|
|
1774
1913
|
const { totalLines: finalizedLines } = buildTurnOffsets(history, contentWidth);
|
|
1775
1914
|
let totalLines = finalizedLines;
|
|
1776
1915
|
if (history.currentRole !== null && history.currentContent) {
|
|
1777
|
-
totalLines += currentTurnSeparator(history
|
|
1916
|
+
totalLines += currentTurnSeparator(history) + countTurnLines(history.currentRole, history.currentContent, contentWidth);
|
|
1778
1917
|
}
|
|
1779
1918
|
const maxScrollTop = Math.max(0, totalLines - visibleHeight);
|
|
1780
1919
|
history.followBottom = false;
|
|
@@ -1823,6 +1962,14 @@ function resolveDialogBottomRow(args) {
|
|
|
1823
1962
|
return Math.max(1, resolveTtyRows(args.output) - args.inputLines);
|
|
1824
1963
|
}
|
|
1825
1964
|
function createDialogHost(args) {
|
|
1965
|
+
let keyboardClaimed = false;
|
|
1966
|
+
const claimKeyboard = () => {
|
|
1967
|
+
keyboardClaimed = true;
|
|
1968
|
+
};
|
|
1969
|
+
const releaseKeyboard = () => {
|
|
1970
|
+
args.drainDecoder?.();
|
|
1971
|
+
keyboardClaimed = false;
|
|
1972
|
+
};
|
|
1826
1973
|
return {
|
|
1827
1974
|
async run(body) {
|
|
1828
1975
|
const anchor = {
|
|
@@ -1832,14 +1979,25 @@ function createDialogHost(args) {
|
|
|
1832
1979
|
inputLines: args.composer.getInputLines()
|
|
1833
1980
|
})
|
|
1834
1981
|
};
|
|
1982
|
+
claimKeyboard();
|
|
1835
1983
|
args.composer.pause();
|
|
1836
1984
|
try {
|
|
1837
1985
|
return await body(anchor);
|
|
1838
1986
|
} finally {
|
|
1839
1987
|
resetHistoryFrameDiffCache(args.output);
|
|
1840
1988
|
args.composer.resumeFromDialog();
|
|
1989
|
+
releaseKeyboard();
|
|
1841
1990
|
}
|
|
1842
|
-
}
|
|
1991
|
+
},
|
|
1992
|
+
async withKeyboard(body) {
|
|
1993
|
+
claimKeyboard();
|
|
1994
|
+
try {
|
|
1995
|
+
return await body();
|
|
1996
|
+
} finally {
|
|
1997
|
+
releaseKeyboard();
|
|
1998
|
+
}
|
|
1999
|
+
},
|
|
2000
|
+
isKeyboardClaimed: () => keyboardClaimed
|
|
1843
2001
|
};
|
|
1844
2002
|
}
|
|
1845
2003
|
|
|
@@ -2049,8 +2207,7 @@ function createRunDock(deps) {
|
|
|
2049
2207
|
const ordered = orderedEntries();
|
|
2050
2208
|
if (ordered.length === 0) return [];
|
|
2051
2209
|
const at = now();
|
|
2052
|
-
const
|
|
2053
|
-
const displaySnapshots = mode === "normal" || mode === "hide" ? ordered.map((entry) => sanitizeRunSnapshotForNormal(entry.snapshot)) : ordered.map((entry) => entry.snapshot);
|
|
2210
|
+
const displaySnapshots = ordered.map((entry) => sanitizeRunSnapshotForNormal(entry.snapshot));
|
|
2054
2211
|
if (displaySnapshots.length === 1) {
|
|
2055
2212
|
return formatAgentRunPanelLines(displaySnapshots[0], colorEnabled, at);
|
|
2056
2213
|
}
|
|
@@ -2224,8 +2381,7 @@ function createActivityIndicator(deps) {
|
|
|
2224
2381
|
onRepaint: deps.onRepaint,
|
|
2225
2382
|
now,
|
|
2226
2383
|
setIntervalFn,
|
|
2227
|
-
clearIntervalFn
|
|
2228
|
-
displayMode: deps.displayMode
|
|
2384
|
+
clearIntervalFn
|
|
2229
2385
|
});
|
|
2230
2386
|
const updateAgentRun = (snapshot) => {
|
|
2231
2387
|
runDock.update(snapshot);
|
|
@@ -3327,6 +3483,20 @@ function summarizeAttachment(img) {
|
|
|
3327
3483
|
].join("\n");
|
|
3328
3484
|
return themeText(text, "chrome", colorEnabled);
|
|
3329
3485
|
}
|
|
3486
|
+
function formatComposerAttachmentLine(images) {
|
|
3487
|
+
if (images.length === 0) return null;
|
|
3488
|
+
const head = images.slice(0, 2).map((img) => `\u{1F4CE} ${img.filename} (${formatBytes(img.sizeBytes)})`);
|
|
3489
|
+
const extra = images.length - head.length;
|
|
3490
|
+
return extra > 0 ? `${head.join(", ")} +${extra}` : head.join(", ");
|
|
3491
|
+
}
|
|
3492
|
+
function popLastAttachedImage(images) {
|
|
3493
|
+
if (images.length === 0) return { handled: false, images };
|
|
3494
|
+
return {
|
|
3495
|
+
handled: true,
|
|
3496
|
+
images: images.slice(0, -1),
|
|
3497
|
+
removed: images[images.length - 1]
|
|
3498
|
+
};
|
|
3499
|
+
}
|
|
3330
3500
|
function mergeAttachedImages(existing, incoming) {
|
|
3331
3501
|
if (incoming.length === 0) return existing;
|
|
3332
3502
|
if (existing.length === 0) return [...incoming];
|
|
@@ -3348,12 +3518,12 @@ function mergeAttachedImages(existing, incoming) {
|
|
|
3348
3518
|
return out;
|
|
3349
3519
|
}
|
|
3350
3520
|
async function readImagePaths(paths, options = {}) {
|
|
3351
|
-
const
|
|
3521
|
+
const resolve4 = options.resolve ?? ((p) => p);
|
|
3352
3522
|
const reportedFailures = /* @__PURE__ */ new Set();
|
|
3353
3523
|
const images = [];
|
|
3354
3524
|
const failures = [];
|
|
3355
3525
|
for (const raw of paths) {
|
|
3356
|
-
const absolute =
|
|
3526
|
+
const absolute = resolve4(raw);
|
|
3357
3527
|
try {
|
|
3358
3528
|
const img = await readImageAsDataUrl(absolute, {
|
|
3359
3529
|
...options.maxBytes !== void 0 ? { maxBytes: options.maxBytes } : {}
|
|
@@ -3393,7 +3563,7 @@ async function resolveAttachmentImageUrls({
|
|
|
3393
3563
|
// packages/cli/tui/clipboardImage.ts
|
|
3394
3564
|
import { createHash } from "node:crypto";
|
|
3395
3565
|
import { mkdirSync } from "node:fs";
|
|
3396
|
-
import { writeFile } from "node:fs/promises";
|
|
3566
|
+
import { readdir, stat as stat2, unlink, writeFile } from "node:fs/promises";
|
|
3397
3567
|
import { tmpdir } from "node:os";
|
|
3398
3568
|
import { join } from "node:path";
|
|
3399
3569
|
var ClipboardImageError = class extends Error {
|
|
@@ -3405,6 +3575,34 @@ var ClipboardImageError = class extends Error {
|
|
|
3405
3575
|
}
|
|
3406
3576
|
};
|
|
3407
3577
|
var DEFAULT_CLIPBOARD_TIMEOUT_MS = 3e4;
|
|
3578
|
+
var CLIPBOARD_TEMP_DIR_NAME = "nolo-clipboard";
|
|
3579
|
+
function getDefaultClipboardTempDir() {
|
|
3580
|
+
return join(tmpdir(), CLIPBOARD_TEMP_DIR_NAME);
|
|
3581
|
+
}
|
|
3582
|
+
var CLIPBOARD_SWEEP_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
3583
|
+
var CLIPBOARD_SWEEP_FILE_RE = /^clip-[0-9a-f]{8,}\.(png|jpg|jpeg|gif|webp)$/;
|
|
3584
|
+
async function sweepStaleClipboardFiles(tempDir, opts = {}) {
|
|
3585
|
+
try {
|
|
3586
|
+
const maxAgeMs = opts.maxAgeMs ?? CLIPBOARD_SWEEP_MAX_AGE_MS;
|
|
3587
|
+
const now = opts.now ?? Date.now();
|
|
3588
|
+
const entries = await readdir(tempDir);
|
|
3589
|
+
let removed = 0;
|
|
3590
|
+
for (const name of entries) {
|
|
3591
|
+
if (!CLIPBOARD_SWEEP_FILE_RE.test(name)) continue;
|
|
3592
|
+
try {
|
|
3593
|
+
const fullPath = join(tempDir, name);
|
|
3594
|
+
const stats = await stat2(fullPath);
|
|
3595
|
+
if (stats.mtimeMs >= now - maxAgeMs) continue;
|
|
3596
|
+
await unlink(fullPath);
|
|
3597
|
+
removed += 1;
|
|
3598
|
+
} catch {
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
return removed;
|
|
3602
|
+
} catch {
|
|
3603
|
+
return 0;
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3408
3606
|
function isRemoteSession(env = process.env) {
|
|
3409
3607
|
return Boolean(env.SSH_CONNECTION || env.SSH_TTY || env.SSH_CLIENT);
|
|
3410
3608
|
}
|
|
@@ -3420,13 +3618,20 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3420
3618
|
}
|
|
3421
3619
|
if (platform === "darwin") {
|
|
3422
3620
|
const pngpaste = which("pngpaste");
|
|
3423
|
-
if (
|
|
3621
|
+
if (pngpaste) {
|
|
3622
|
+
return { command: [pngpaste, "-"], outputFormat: "raw" };
|
|
3623
|
+
}
|
|
3624
|
+
const osascript = which("osascript");
|
|
3625
|
+
if (!osascript) {
|
|
3424
3626
|
throw new ClipboardImageError(
|
|
3425
3627
|
"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"
|
|
3628
|
+
"\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
3629
|
);
|
|
3428
3630
|
}
|
|
3429
|
-
return {
|
|
3631
|
+
return {
|
|
3632
|
+
command: [osascript, "-e", "the clipboard as \xABclass PNGf\xBB"],
|
|
3633
|
+
outputFormat: "osascript-hex"
|
|
3634
|
+
};
|
|
3430
3635
|
}
|
|
3431
3636
|
if (platform === "win32") {
|
|
3432
3637
|
const ps = which("powershell.exe") || which("powershell") || which("pwsh.exe") || which("pwsh");
|
|
@@ -3443,7 +3648,8 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3443
3648
|
"-NonInteractive",
|
|
3444
3649
|
"-Command",
|
|
3445
3650
|
"$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
|
-
]
|
|
3651
|
+
],
|
|
3652
|
+
outputFormat: "raw"
|
|
3447
3653
|
};
|
|
3448
3654
|
}
|
|
3449
3655
|
if (platform === "linux") {
|
|
@@ -3456,17 +3662,18 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3456
3662
|
"\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
3663
|
);
|
|
3458
3664
|
}
|
|
3459
|
-
return { command: [wlPaste2, "--type", "image/png"] };
|
|
3665
|
+
return { command: [wlPaste2, "--type", "image/png"], outputFormat: "raw" };
|
|
3460
3666
|
}
|
|
3461
3667
|
const xclip = which("xclip");
|
|
3462
3668
|
if (xclip) {
|
|
3463
3669
|
return {
|
|
3464
|
-
command: [xclip, "-selection", "clipboard", "-t", "image/png", "-o"]
|
|
3670
|
+
command: [xclip, "-selection", "clipboard", "-t", "image/png", "-o"],
|
|
3671
|
+
outputFormat: "raw"
|
|
3465
3672
|
};
|
|
3466
3673
|
}
|
|
3467
3674
|
const wlPaste = which("wl-paste");
|
|
3468
3675
|
if (wlPaste) {
|
|
3469
|
-
return { command: [wlPaste, "--type", "image/png"] };
|
|
3676
|
+
return { command: [wlPaste, "--type", "image/png"], outputFormat: "raw" };
|
|
3470
3677
|
}
|
|
3471
3678
|
throw new ClipboardImageError(
|
|
3472
3679
|
"binary-missing",
|
|
@@ -3478,6 +3685,21 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3478
3685
|
`\u5F53\u524D\u64CD\u4F5C\u7CFB\u7EDF\u6682\u4E0D\u652F\u6301\u526A\u8D34\u677F\u56FE\u50CF\u8BFB\u53D6: ${platform}`
|
|
3479
3686
|
);
|
|
3480
3687
|
}
|
|
3688
|
+
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";
|
|
3689
|
+
function decodeOsascriptPngHex(text) {
|
|
3690
|
+
const match = /PNGf\s*([0-9A-Fa-f]*)/.exec(text);
|
|
3691
|
+
if (!match) return { kind: "empty" };
|
|
3692
|
+
const hex = match[1] ?? "";
|
|
3693
|
+
const tail = text.slice(match.index + match[0].length).replace(/[\s»]*$/, "");
|
|
3694
|
+
if (tail.length > 0) return { kind: "invalid" };
|
|
3695
|
+
if (hex.length === 0) return { kind: "empty" };
|
|
3696
|
+
if (hex.length % 2 !== 0) return { kind: "invalid" };
|
|
3697
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
3698
|
+
for (let i = 0; i < bytes.length; i += 1) {
|
|
3699
|
+
bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
3700
|
+
}
|
|
3701
|
+
return { kind: "bytes", bytes };
|
|
3702
|
+
}
|
|
3481
3703
|
async function readClipboardImage(deps = {}) {
|
|
3482
3704
|
const env = deps.env ?? process.env;
|
|
3483
3705
|
const platform = deps.platform ?? process.platform;
|
|
@@ -3485,8 +3707,8 @@ async function readClipboardImage(deps = {}) {
|
|
|
3485
3707
|
const spawn = deps.spawn ?? Bun.spawn;
|
|
3486
3708
|
const maxBytes = deps.maxBytes ?? DEFAULT_MAX_IMAGE_BYTES;
|
|
3487
3709
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_CLIPBOARD_TIMEOUT_MS;
|
|
3488
|
-
const tempDir = deps.tempDir ??
|
|
3489
|
-
const { command } = getClipboardImageCommand({
|
|
3710
|
+
const tempDir = deps.tempDir ?? getDefaultClipboardTempDir();
|
|
3711
|
+
const { command, outputFormat } = getClipboardImageCommand({
|
|
3490
3712
|
env,
|
|
3491
3713
|
platform,
|
|
3492
3714
|
which
|
|
@@ -3520,6 +3742,12 @@ async function readClipboardImage(deps = {}) {
|
|
|
3520
3742
|
timeoutPromise
|
|
3521
3743
|
]);
|
|
3522
3744
|
if (exitCode !== 0 || stdoutArrayBuffer.byteLength === 0) {
|
|
3745
|
+
if (outputFormat === "osascript-hex") {
|
|
3746
|
+
throw new ClipboardImageError(
|
|
3747
|
+
"empty-clipboard",
|
|
3748
|
+
OSASCRIPT_EMPTY_CLIPBOARD_MESSAGE + (stderrText.trim() ? `: ${stderrText.trim()}` : "")
|
|
3749
|
+
);
|
|
3750
|
+
}
|
|
3523
3751
|
throw new ClipboardImageError(
|
|
3524
3752
|
"empty-clipboard",
|
|
3525
3753
|
"\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 +3766,23 @@ async function readClipboardImage(deps = {}) {
|
|
|
3538
3766
|
`\u8BFB\u53D6\u526A\u8D34\u677F\u56FE\u50CF\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`
|
|
3539
3767
|
);
|
|
3540
3768
|
}
|
|
3769
|
+
if (outputFormat === "osascript-hex") {
|
|
3770
|
+
const text = Buffer.from(stdoutBuf).toString("utf8");
|
|
3771
|
+
const decoded = decodeOsascriptPngHex(text);
|
|
3772
|
+
if (decoded.kind === "empty") {
|
|
3773
|
+
throw new ClipboardImageError(
|
|
3774
|
+
"empty-clipboard",
|
|
3775
|
+
OSASCRIPT_EMPTY_CLIPBOARD_MESSAGE
|
|
3776
|
+
);
|
|
3777
|
+
}
|
|
3778
|
+
if (decoded.kind === "invalid") {
|
|
3779
|
+
throw new ClipboardImageError(
|
|
3780
|
+
"read-failed",
|
|
3781
|
+
"\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"
|
|
3782
|
+
);
|
|
3783
|
+
}
|
|
3784
|
+
stdoutBuf = decoded.bytes;
|
|
3785
|
+
}
|
|
3541
3786
|
const compressResult = await compressImage(stdoutBuf, "image/png");
|
|
3542
3787
|
const finalBuf = compressResult.buffer;
|
|
3543
3788
|
const finalMime = compressResult.mime;
|
|
@@ -3598,7 +3843,7 @@ function parseStatusOutput(branch, status) {
|
|
|
3598
3843
|
return { branch, modified, untracked };
|
|
3599
3844
|
}
|
|
3600
3845
|
function execFileUtf8(file, args, cwd) {
|
|
3601
|
-
return new Promise((
|
|
3846
|
+
return new Promise((resolve4, reject) => {
|
|
3602
3847
|
execFile(
|
|
3603
3848
|
file,
|
|
3604
3849
|
args,
|
|
@@ -3608,7 +3853,7 @@ function execFileUtf8(file, args, cwd) {
|
|
|
3608
3853
|
reject(err);
|
|
3609
3854
|
return;
|
|
3610
3855
|
}
|
|
3611
|
-
|
|
3856
|
+
resolve4(typeof stdout === "string" ? stdout : String(stdout ?? ""));
|
|
3612
3857
|
}
|
|
3613
3858
|
);
|
|
3614
3859
|
});
|
|
@@ -3862,7 +4107,6 @@ function renderContextPanel(state, colorEnabled = resolveCliColorEnabled()) {
|
|
|
3862
4107
|
t("contextFieldSkills"),
|
|
3863
4108
|
t("contextFieldProfile"),
|
|
3864
4109
|
t("contextFieldRuntime"),
|
|
3865
|
-
t("contextFieldTools"),
|
|
3866
4110
|
t("contextFieldServer")
|
|
3867
4111
|
];
|
|
3868
4112
|
let maxW = 0;
|
|
@@ -3892,8 +4136,7 @@ function renderContextPanel(state, colorEnabled = resolveCliColorEnabled()) {
|
|
|
3892
4136
|
field(labels[4], skills),
|
|
3893
4137
|
field(labels[5], state.profileName),
|
|
3894
4138
|
field(labels[6], state.runtimeMode),
|
|
3895
|
-
field(labels[7], state.
|
|
3896
|
-
field(labels[8], state.serverUrl),
|
|
4139
|
+
field(labels[7], state.serverUrl),
|
|
3897
4140
|
"",
|
|
3898
4141
|
themeText(t("contextNext"), "chrome", colorEnabled),
|
|
3899
4142
|
next("/agents ", ` ${t("contextNextAgents")}`),
|
|
@@ -3923,6 +4166,9 @@ function renderKnownAgents(colorEnabled = resolveCliColorEnabled()) {
|
|
|
3923
4166
|
}
|
|
3924
4167
|
|
|
3925
4168
|
// packages/cli/tui/sessionInput.ts
|
|
4169
|
+
import { readdirSync, statSync } from "node:fs";
|
|
4170
|
+
import { homedir as homedir2 } from "node:os";
|
|
4171
|
+
import { resolve as resolve2 } from "node:path";
|
|
3926
4172
|
var PASTE_TOKEN_PREFIX = "\0PASTE\0";
|
|
3927
4173
|
function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
|
|
3928
4174
|
const seq = sequence ?? "";
|
|
@@ -4027,6 +4273,16 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
|
|
|
4027
4273
|
return { buffer, cursorPos: curPos };
|
|
4028
4274
|
}
|
|
4029
4275
|
if (seq === " " || key.name === "tab") {
|
|
4276
|
+
if (options?.cwd) {
|
|
4277
|
+
const pathCandidates = completeSlashCommand(buffer, options.cwd);
|
|
4278
|
+
if (pathCandidates.length === 1) {
|
|
4279
|
+
const [only] = pathCandidates;
|
|
4280
|
+
return { buffer: only, cursorPos: only.length };
|
|
4281
|
+
}
|
|
4282
|
+
if (pathCandidates.length > 1) {
|
|
4283
|
+
return { buffer, cursorPos: curPos };
|
|
4284
|
+
}
|
|
4285
|
+
}
|
|
4030
4286
|
const completed = completeSlashPrefix(buffer) ?? buffer;
|
|
4031
4287
|
return { buffer: completed, cursorPos: completed.length };
|
|
4032
4288
|
}
|
|
@@ -4079,9 +4335,9 @@ function deleteBufferRange(buffer, start, end, pasteStore) {
|
|
|
4079
4335
|
function releasePastesInRange(buffer, start, end, pasteStore) {
|
|
4080
4336
|
if (!pasteStore || start >= end) return;
|
|
4081
4337
|
const slice = buffer.slice(start, end);
|
|
4082
|
-
|
|
4338
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
|
|
4083
4339
|
let match;
|
|
4084
|
-
while ((match =
|
|
4340
|
+
while ((match = COLLAPSED_PASTE_PLACEHOLDER_RE.exec(slice)) !== null) {
|
|
4085
4341
|
releaseCollapsedPaste(pasteStore, Number(match[1]));
|
|
4086
4342
|
}
|
|
4087
4343
|
}
|
|
@@ -4135,12 +4391,10 @@ var SLASH_COMMANDS = [
|
|
|
4135
4391
|
"/clear",
|
|
4136
4392
|
"/compact",
|
|
4137
4393
|
"/theme",
|
|
4138
|
-
"/density",
|
|
4139
4394
|
"/context",
|
|
4140
4395
|
"/ctx",
|
|
4396
|
+
"/cd",
|
|
4141
4397
|
"/runtime",
|
|
4142
|
-
"/tools",
|
|
4143
|
-
"/thinking",
|
|
4144
4398
|
"/auto",
|
|
4145
4399
|
"/switch",
|
|
4146
4400
|
"/agent",
|
|
@@ -4178,12 +4432,49 @@ function completeSlashPrefix(buffer) {
|
|
|
4178
4432
|
}
|
|
4179
4433
|
return prefix.length > buffer.length ? prefix : null;
|
|
4180
4434
|
}
|
|
4181
|
-
function completeSlashCommand(buffer) {
|
|
4435
|
+
function completeSlashCommand(buffer, cwd) {
|
|
4182
4436
|
if (!buffer.startsWith("/")) return [];
|
|
4183
4437
|
const trimmed = buffer.trim();
|
|
4438
|
+
if (cwd && buffer.startsWith("/cd ")) {
|
|
4439
|
+
const prefix = buffer.slice("/cd ".length);
|
|
4440
|
+
return completeCdPathCandidates(prefix, cwd);
|
|
4441
|
+
}
|
|
4184
4442
|
if (trimmed.includes(" ")) return [];
|
|
4185
4443
|
return SLASH_COMMANDS.filter((cmd) => cmd.startsWith(trimmed) && cmd !== trimmed);
|
|
4186
4444
|
}
|
|
4445
|
+
function completeCdPathCandidates(prefix, cwd) {
|
|
4446
|
+
const lastSlash = prefix.lastIndexOf("/");
|
|
4447
|
+
const head = lastSlash >= 0 ? prefix.slice(0, lastSlash + 1) : "";
|
|
4448
|
+
const baseName = lastSlash >= 0 ? prefix.slice(lastSlash + 1) : prefix;
|
|
4449
|
+
let dirPath;
|
|
4450
|
+
if (head === "~" || head === "~/" || head === "~\\") {
|
|
4451
|
+
dirPath = homedir2();
|
|
4452
|
+
} else if (head.startsWith("~/") || head.startsWith("~\\")) {
|
|
4453
|
+
dirPath = resolve2(homedir2(), head.slice(2));
|
|
4454
|
+
} else {
|
|
4455
|
+
dirPath = head.startsWith("/") ? head : resolve2(cwd, head);
|
|
4456
|
+
}
|
|
4457
|
+
let entries;
|
|
4458
|
+
try {
|
|
4459
|
+
entries = readdirSync(dirPath, { withFileTypes: true });
|
|
4460
|
+
} catch {
|
|
4461
|
+
return [];
|
|
4462
|
+
}
|
|
4463
|
+
const hiddenRequested = baseName.startsWith(".");
|
|
4464
|
+
const names = entries.filter((e) => {
|
|
4465
|
+
if (e.isDirectory()) return true;
|
|
4466
|
+
if (!e.isSymbolicLink()) return false;
|
|
4467
|
+
try {
|
|
4468
|
+
return statSync(resolve2(dirPath, e.name)).isDirectory();
|
|
4469
|
+
} catch {
|
|
4470
|
+
return false;
|
|
4471
|
+
}
|
|
4472
|
+
}).map((e) => e.name).filter((name) => {
|
|
4473
|
+
if (!name.startsWith(baseName)) return false;
|
|
4474
|
+
return hiddenRequested || !name.startsWith(".");
|
|
4475
|
+
}).sort();
|
|
4476
|
+
return names.map((name) => `/cd ${head}${name}/`);
|
|
4477
|
+
}
|
|
4187
4478
|
function isLikelySlashCommand(input) {
|
|
4188
4479
|
const trimmed = input.trim();
|
|
4189
4480
|
if (!trimmed.startsWith("/")) return false;
|
|
@@ -4202,6 +4493,11 @@ function stripImageTokens(input, hints) {
|
|
|
4202
4493
|
return compactWhitespace(out);
|
|
4203
4494
|
}
|
|
4204
4495
|
|
|
4496
|
+
// packages/cli/tui/sessionDispatch.ts
|
|
4497
|
+
import { statSync as statSync2 } from "node:fs";
|
|
4498
|
+
import { homedir as homedir3 } from "node:os";
|
|
4499
|
+
import { resolve as resolve3 } from "node:path";
|
|
4500
|
+
|
|
4205
4501
|
// packages/cli/tui/agentPicker.ts
|
|
4206
4502
|
function toAgentPickerItems(entries) {
|
|
4207
4503
|
return entries.map((entry) => ({
|
|
@@ -4363,6 +4659,10 @@ function estimateDefaultCliContextTokens(opts = {}) {
|
|
|
4363
4659
|
|
|
4364
4660
|
// packages/cli/tui/sessionDispatch.ts
|
|
4365
4661
|
var DEFAULT_TUI_SERVER_URL = DEFAULT_NOLO_SERVER_URL;
|
|
4662
|
+
function resolveThinkingDisplayMode(env = process.env) {
|
|
4663
|
+
const raw = (env.NOLO_CLI_THINKING ?? "").trim().toLowerCase();
|
|
4664
|
+
return raw === "hide" || raw === "false" || raw === "0" ? "hide" : "show";
|
|
4665
|
+
}
|
|
4366
4666
|
function createInitialTuiState(env = process.env) {
|
|
4367
4667
|
const agentKey = asOptionalTrimmedString(env.NOLO_AGENT) ?? DEFAULT_TUI_AGENT_KEY;
|
|
4368
4668
|
const agentName = asOptionalTrimmedString(env.NOLO_AGENT_NAME) ?? "nolo";
|
|
@@ -4395,8 +4695,7 @@ function createInitialTuiState(env = process.env) {
|
|
|
4395
4695
|
modeLabel: asOptionalTrimmedString(env.NOLO_CLI_STATUS_MODE) ?? runtimeMode,
|
|
4396
4696
|
userLanguage: asOptionalTrimmedString(env.NOLO_LANG),
|
|
4397
4697
|
gitStatus: void 0,
|
|
4398
|
-
|
|
4399
|
-
thinkingDisplay: "show",
|
|
4698
|
+
thinkingDisplay: resolveThinkingDisplayMode(env),
|
|
4400
4699
|
contextWindow: resolveAgentContextWindow({ agentKey, agentName }),
|
|
4401
4700
|
estimatedContextTokens: estimateDefaultCliContextTokens({
|
|
4402
4701
|
cwd,
|
|
@@ -4520,28 +4819,53 @@ function handleTuiInput(input, state) {
|
|
|
4520
4819
|
};
|
|
4521
4820
|
}
|
|
4522
4821
|
}
|
|
4523
|
-
case "/
|
|
4524
|
-
|
|
4525
|
-
const sub = parts[0]?.trim();
|
|
4526
|
-
if (!sub) {
|
|
4822
|
+
case "/cd": {
|
|
4823
|
+
if (!argText) {
|
|
4527
4824
|
return {
|
|
4528
4825
|
nextState: state,
|
|
4529
|
-
output: t("
|
|
4826
|
+
output: `${t("cdCurrent", state.cwd)}
|
|
4827
|
+
${t("cdUsage")}`
|
|
4530
4828
|
};
|
|
4531
4829
|
}
|
|
4532
|
-
if (
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
} else {
|
|
4830
|
+
if (argText === "-") {
|
|
4831
|
+
if (!state.prevCwd) {
|
|
4832
|
+
return { nextState: state, output: t("cdNoPrevious") };
|
|
4833
|
+
}
|
|
4834
|
+
const previous = state.prevCwd;
|
|
4835
|
+
const switchMessage2 = t("cdSwitchedMessage", state.cwd, previous);
|
|
4539
4836
|
return {
|
|
4540
|
-
nextState: state,
|
|
4541
|
-
output: t("
|
|
4837
|
+
nextState: { ...state, cwd: previous, prevCwd: void 0, pendingCwdNotice: switchMessage2 },
|
|
4838
|
+
output: t("cdSwitched", previous),
|
|
4839
|
+
action: { type: "cwd-refresh", switchMessage: switchMessage2 }
|
|
4542
4840
|
};
|
|
4543
4841
|
}
|
|
4842
|
+
const expanded = argText === "~" ? homedir3() : argText.startsWith("~/") || argText.startsWith("~\\") ? resolve3(homedir3(), argText.slice(2)) : argText;
|
|
4843
|
+
const target = resolve3(state.cwd, expanded);
|
|
4844
|
+
try {
|
|
4845
|
+
if (!statSync2(target).isDirectory()) {
|
|
4846
|
+
return { nextState: state, output: t("cdNotDir", target) };
|
|
4847
|
+
}
|
|
4848
|
+
} catch {
|
|
4849
|
+
return { nextState: state, output: t("cdNotFound", target) };
|
|
4850
|
+
}
|
|
4851
|
+
const normalized = target === "/" ? "/" : target.replace(/\/+$/, "");
|
|
4852
|
+
if (normalized === state.cwd) {
|
|
4853
|
+
return { nextState: state, output: t("cdCurrent", state.cwd) };
|
|
4854
|
+
}
|
|
4855
|
+
const switchMessage = t("cdSwitchedMessage", state.cwd, normalized);
|
|
4856
|
+
return {
|
|
4857
|
+
nextState: { ...state, cwd: normalized, prevCwd: state.cwd, pendingCwdNotice: switchMessage },
|
|
4858
|
+
output: t("cdSwitched", normalized),
|
|
4859
|
+
action: { type: "cwd-refresh", switchMessage }
|
|
4860
|
+
};
|
|
4544
4861
|
}
|
|
4862
|
+
case "/density":
|
|
4863
|
+
case "/tools":
|
|
4864
|
+
case "/thinking":
|
|
4865
|
+
return {
|
|
4866
|
+
nextState: state,
|
|
4867
|
+
output: t("displayFixedHint")
|
|
4868
|
+
};
|
|
4545
4869
|
case "/context":
|
|
4546
4870
|
case "/ctx":
|
|
4547
4871
|
return { nextState: state, output: renderContextPanel(state) };
|
|
@@ -4557,45 +4881,6 @@ function handleTuiInput(input, state) {
|
|
|
4557
4881
|
output: t("runtimeSet", argText)
|
|
4558
4882
|
};
|
|
4559
4883
|
}
|
|
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
4884
|
case "/auto": {
|
|
4600
4885
|
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
4601
4886
|
if (!normalizedArg) {
|
|
@@ -5004,7 +5289,7 @@ async function probeTerminalBackground(args = {}) {
|
|
|
5004
5289
|
if (typeof stdin.setRawMode !== "function") return null;
|
|
5005
5290
|
if (!isTerminal(stdin)) return null;
|
|
5006
5291
|
const wasRaw = Boolean(stdin.isRaw);
|
|
5007
|
-
return await new Promise((
|
|
5292
|
+
return await new Promise((resolve4) => {
|
|
5008
5293
|
let buffer = "";
|
|
5009
5294
|
let settled = false;
|
|
5010
5295
|
let timer;
|
|
@@ -5017,7 +5302,7 @@ async function probeTerminalBackground(args = {}) {
|
|
|
5017
5302
|
if (!wasRaw) stdin.setRawMode?.(false);
|
|
5018
5303
|
} catch {
|
|
5019
5304
|
}
|
|
5020
|
-
|
|
5305
|
+
resolve4(result);
|
|
5021
5306
|
};
|
|
5022
5307
|
const onData = (chunk) => {
|
|
5023
5308
|
buffer += chunk.toString("latin1");
|
|
@@ -5080,9 +5365,46 @@ function detectSystemBrightness(env = process.env, options = {}) {
|
|
|
5080
5365
|
return null;
|
|
5081
5366
|
}
|
|
5082
5367
|
|
|
5083
|
-
// packages/cli/tui/
|
|
5084
|
-
|
|
5085
|
-
|
|
5368
|
+
// packages/cli/tui/turnInjectionInbox.ts
|
|
5369
|
+
function appendStreamSafeNotice(history, text, deps) {
|
|
5370
|
+
const wasStreamingAssistant = history.currentRole === "assistant";
|
|
5371
|
+
if (wasStreamingAssistant && !history.currentContent) {
|
|
5372
|
+
history.currentRole = null;
|
|
5373
|
+
history.currentBlocks = [];
|
|
5374
|
+
}
|
|
5375
|
+
deps.appendLocalTurn(history, "", text);
|
|
5376
|
+
if (wasStreamingAssistant) deps.startTurn(history, "assistant");
|
|
5377
|
+
}
|
|
5378
|
+
function createTurnInjectionInbox() {
|
|
5379
|
+
let pending = [];
|
|
5380
|
+
let closed = false;
|
|
5381
|
+
return {
|
|
5382
|
+
push(entry) {
|
|
5383
|
+
if (closed) return false;
|
|
5384
|
+
if (!entry || typeof entry.text !== "string" || !entry.text.trim()) return false;
|
|
5385
|
+
pending.push(entry);
|
|
5386
|
+
return true;
|
|
5387
|
+
},
|
|
5388
|
+
drain() {
|
|
5389
|
+
if (pending.length === 0) return [];
|
|
5390
|
+
const taken = pending;
|
|
5391
|
+
pending = [];
|
|
5392
|
+
return taken.map((entry) => entry.text);
|
|
5393
|
+
},
|
|
5394
|
+
close() {
|
|
5395
|
+
closed = true;
|
|
5396
|
+
const remaining = pending;
|
|
5397
|
+
pending = [];
|
|
5398
|
+
return remaining;
|
|
5399
|
+
},
|
|
5400
|
+
get size() {
|
|
5401
|
+
return pending.length;
|
|
5402
|
+
},
|
|
5403
|
+
get closed() {
|
|
5404
|
+
return closed;
|
|
5405
|
+
}
|
|
5406
|
+
};
|
|
5407
|
+
}
|
|
5086
5408
|
|
|
5087
5409
|
// packages/ai/tools/askChoiceState.ts
|
|
5088
5410
|
function normalizeAskChoiceArgs(args) {
|
|
@@ -5861,24 +6183,6 @@ function emitTerminalBell(output) {
|
|
|
5861
6183
|
}
|
|
5862
6184
|
|
|
5863
6185
|
// packages/cli/tui/tuiTurnRunner.ts
|
|
5864
|
-
var AGENTS_MD_MAX_BYTES = 8192;
|
|
5865
|
-
function readAgentsMdLayer(cwd) {
|
|
5866
|
-
for (const name of ["AGENTS.md", "CLAUDE.md"]) {
|
|
5867
|
-
const filePath = join3(cwd, name);
|
|
5868
|
-
if (existsSync3(filePath)) {
|
|
5869
|
-
try {
|
|
5870
|
-
let content = readFileSync3(filePath, "utf8").trim();
|
|
5871
|
-
if (!content) continue;
|
|
5872
|
-
if (Buffer.byteLength(content, "utf8") > AGENTS_MD_MAX_BYTES) {
|
|
5873
|
-
content = Buffer.from(content, "utf8").subarray(0, AGENTS_MD_MAX_BYTES).toString("utf8") + "\n\n<!-- AGENTS.md truncated -->";
|
|
5874
|
-
}
|
|
5875
|
-
return buildAgentsMdLayer(content, name);
|
|
5876
|
-
} catch {
|
|
5877
|
-
}
|
|
5878
|
-
}
|
|
5879
|
-
}
|
|
5880
|
-
return null;
|
|
5881
|
-
}
|
|
5882
6186
|
async function runAgentChat(scriptDir, state, message, env, output, agentRunner = runAgentTurn, options = {}) {
|
|
5883
6187
|
const effectiveAgentKey = state.agentKey;
|
|
5884
6188
|
const effectiveAgentName = state.agentName;
|
|
@@ -5923,12 +6227,16 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5923
6227
|
}
|
|
5924
6228
|
}
|
|
5925
6229
|
const layers = [
|
|
5926
|
-
|
|
6230
|
+
readAgentsMdLayerFromDisk(state.cwd),
|
|
5927
6231
|
// Skill discovery: scan conventional skill dirs for SKILL.md and inject an
|
|
5928
6232
|
// index layer so the model knows what skills exist and can readFile them
|
|
5929
6233
|
// on-demand. Mirrors agentRunCommand.ts and desktopAgentRuntimeTurnService.
|
|
5930
6234
|
buildSkillDiscoveryContextLayer(state.cwd)
|
|
5931
6235
|
];
|
|
6236
|
+
const responseGuidelinesBlock = {
|
|
6237
|
+
content: buildResponseGuidelines(true),
|
|
6238
|
+
cacheScope: "session"
|
|
6239
|
+
};
|
|
5932
6240
|
let memoryPromptBlock = state.cachedMemoryOverlay;
|
|
5933
6241
|
if (memoryPromptBlock === void 0) {
|
|
5934
6242
|
memoryPromptBlock = await resolveCliMemory({
|
|
@@ -5941,15 +6249,19 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5941
6249
|
}
|
|
5942
6250
|
const memoryOverlayLayer = buildMemoryOverlayLayer({ promptBlock: memoryPromptBlock });
|
|
5943
6251
|
const memoryUseGuidanceLayer = buildMemoryUseGuidanceLayer({ promptBlock: memoryPromptBlock });
|
|
6252
|
+
const cwdNoticeBlocks = state.pendingCwdNotice ? [{ content: state.pendingCwdNotice, cacheScope: "turn" }] : [];
|
|
5944
6253
|
const contextBlockScopes = partitionScopedBlocks([
|
|
5945
6254
|
...renderTurnContextBlocksWithScope(layers),
|
|
6255
|
+
responseGuidelinesBlock,
|
|
5946
6256
|
...renderTurnContextBlocksWithScope([memoryUseGuidanceLayer]),
|
|
5947
6257
|
// Attached skill bodies are already self-contained sections built by
|
|
5948
6258
|
// buildSkillContextBlocks; they stay turn-scope because the user can
|
|
5949
6259
|
// attach/detach skills between turns.
|
|
5950
6260
|
...(skillContextBlocks ?? []).map((content) => content.trim()).filter((content) => content.length > 0).map((content) => ({ content, cacheScope: "turn" })),
|
|
5951
|
-
...renderTurnContextBlocksWithScope([memoryOverlayLayer])
|
|
6261
|
+
...renderTurnContextBlocksWithScope([memoryOverlayLayer]),
|
|
6262
|
+
...cwdNoticeBlocks
|
|
5952
6263
|
]);
|
|
6264
|
+
const spawnedRunsMissingParent = [];
|
|
5953
6265
|
const result = await agentRunner({
|
|
5954
6266
|
agentName: effectiveAgentName,
|
|
5955
6267
|
agentKey: effectiveAgentKey,
|
|
@@ -5967,10 +6279,12 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5967
6279
|
scriptDir,
|
|
5968
6280
|
env: {
|
|
5969
6281
|
...env,
|
|
5970
|
-
NOLO_LANG: state.userLanguage
|
|
5971
|
-
|
|
6282
|
+
NOLO_LANG: state.userLanguage
|
|
6283
|
+
},
|
|
6284
|
+
output: {
|
|
6285
|
+
...output,
|
|
6286
|
+
tuiTrees: output.tuiTrees === true && typeof output.writeToolBlock === "function"
|
|
5972
6287
|
},
|
|
5973
|
-
output,
|
|
5974
6288
|
showThinking: state.thinkingDisplay === "show",
|
|
5975
6289
|
...options.imageUrls && options.imageUrls.length > 0 ? { imageUrls: options.imageUrls } : {},
|
|
5976
6290
|
...options.actionGateHandler ? { actionGateHandler: options.actionGateHandler } : {},
|
|
@@ -5994,15 +6308,28 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5994
6308
|
// run-completion watcher can attribute terminal-state wakes to this
|
|
5995
6309
|
// conversation.
|
|
5996
6310
|
...state.dialogId ? { parentDialogId: state.dialogId } : {},
|
|
6311
|
+
// 首轮无 dialogId 时的兜底:收集失归属的 spawn,turn 结束回填。
|
|
6312
|
+
onBackgroundRunSpawned: (runId) => {
|
|
6313
|
+
spawnedRunsMissingParent.push(runId);
|
|
6314
|
+
},
|
|
5997
6315
|
...options.activityReporter ? { activityReporter: options.activityReporter } : {}
|
|
5998
6316
|
}),
|
|
5999
6317
|
...options.activityReporter ? { activityReporter: options.activityReporter } : {},
|
|
6000
6318
|
// 转发 dock 订阅:runAgentTurn 的输出层靠它判断「有面板」从而抑制
|
|
6001
6319
|
// transcript 的进展卡片;dock 本身也靠它接收模型轮询带回来的快照。
|
|
6002
6320
|
...options.onAgentRunStatus ? { onAgentRunStatus: options.onAgentRunStatus } : {},
|
|
6321
|
+
...options.drainInjections ? { drainInjections: options.drainInjections } : {},
|
|
6003
6322
|
...skillAllowedTools !== void 0 ? { allowedToolNames: skillAllowedTools } : {},
|
|
6004
6323
|
...contextBlockScopes.length > 0 ? { contextBlockScopes } : {}
|
|
6005
6324
|
});
|
|
6325
|
+
if (result.dialogId && spawnedRunsMissingParent.length > 0) {
|
|
6326
|
+
for (const runId of spawnedRunsMissingParent) {
|
|
6327
|
+
try {
|
|
6328
|
+
backfillRunRecordParentDialog(runId, result.dialogId, { env });
|
|
6329
|
+
} catch {
|
|
6330
|
+
}
|
|
6331
|
+
}
|
|
6332
|
+
}
|
|
6006
6333
|
return {
|
|
6007
6334
|
...result,
|
|
6008
6335
|
contextWindow: resolveAgentContextWindow({
|
|
@@ -6012,17 +6339,47 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
6012
6339
|
cachedMemoryOverlay: memoryPromptBlock
|
|
6013
6340
|
};
|
|
6014
6341
|
}
|
|
6342
|
+
var ESC = "\x1B";
|
|
6343
|
+
var CTRL_C = "";
|
|
6015
6344
|
function isApprovedConfirmationInput(answer) {
|
|
6016
6345
|
const normalized = answer.trim().toLowerCase();
|
|
6017
6346
|
return normalized === "" || normalized === "y" || normalized === "yes" || normalized === "\u786E\u8BA4";
|
|
6018
6347
|
}
|
|
6019
|
-
function
|
|
6348
|
+
function buildGateConfirmedResult(gate) {
|
|
6349
|
+
return {
|
|
6350
|
+
content: `action gate completed: ${gate.title}`,
|
|
6351
|
+
metadata: { actionGateResult: { gateId: gate.id, status: "completed", output: "confirmed" } }
|
|
6352
|
+
};
|
|
6353
|
+
}
|
|
6354
|
+
function buildGateCancelledResult(gate, reason) {
|
|
6355
|
+
return {
|
|
6356
|
+
content: `action gate cancelled: ${gate.title}`,
|
|
6357
|
+
metadata: {
|
|
6358
|
+
exitCode: 130,
|
|
6359
|
+
actionGateResult: { gateId: gate.id, status: "cancelled", output: reason }
|
|
6360
|
+
}
|
|
6361
|
+
};
|
|
6362
|
+
}
|
|
6363
|
+
function buildGateFailedResult(gate, message) {
|
|
6364
|
+
return {
|
|
6365
|
+
content: `action gate failed: ${gate.title}`,
|
|
6366
|
+
metadata: {
|
|
6367
|
+
exitCode: 1,
|
|
6368
|
+
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
6369
|
+
}
|
|
6370
|
+
};
|
|
6371
|
+
}
|
|
6372
|
+
function deriveGateMeta(gate) {
|
|
6020
6373
|
const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
|
|
6021
6374
|
const isConfirmation = gate.kind === "confirm";
|
|
6022
6375
|
const displayCommand = commandPayload?.displayCommand ?? commandPayload?.command.join(" ") ?? gate.title;
|
|
6023
6376
|
const isInteractiveHandoff = gate.kind === "handoff" && gate.title === "This command requires an interactive terminal.";
|
|
6024
6377
|
const title = isInteractiveHandoff ? t("actionGateInteractiveTitle") : gate.title;
|
|
6025
6378
|
const body = isInteractiveHandoff ? t("actionGateInteractiveBody") : gate.body;
|
|
6379
|
+
return { commandPayload, isConfirmation, displayCommand, isInteractiveHandoff, title, body };
|
|
6380
|
+
}
|
|
6381
|
+
function writeGatePrompt(output, meta) {
|
|
6382
|
+
const { title, body, displayCommand, isConfirmation } = meta;
|
|
6026
6383
|
output.write(`
|
|
6027
6384
|
[nolo] ${t("actionGateNeeded")}
|
|
6028
6385
|
`);
|
|
@@ -6034,29 +6391,22 @@ function waitForActionGate(rl, input, output, gate, spawnRunner) {
|
|
|
6034
6391
|
`);
|
|
6035
6392
|
output.write(`[nolo] ${isConfirmation ? t("actionGateConfirmHint") : t("actionGateEnterHint")}
|
|
6036
6393
|
`);
|
|
6037
|
-
|
|
6394
|
+
}
|
|
6395
|
+
function waitForActionGate(rl, input, output, gate, spawnRunner) {
|
|
6396
|
+
const meta = deriveGateMeta(gate);
|
|
6397
|
+
const { commandPayload, isConfirmation, displayCommand } = meta;
|
|
6398
|
+
writeGatePrompt(output, meta);
|
|
6399
|
+
return new Promise((resolve4) => {
|
|
6038
6400
|
let settled = false;
|
|
6039
6401
|
const finish = (result) => {
|
|
6040
6402
|
if (settled) return;
|
|
6041
6403
|
settled = true;
|
|
6042
6404
|
rl.off("close", onClose);
|
|
6043
6405
|
rl.off("SIGINT", onSigint);
|
|
6044
|
-
|
|
6406
|
+
resolve4(result);
|
|
6045
6407
|
};
|
|
6046
|
-
const cancelResult = (reason) => (
|
|
6047
|
-
|
|
6048
|
-
metadata: {
|
|
6049
|
-
exitCode: 130,
|
|
6050
|
-
actionGateResult: { gateId: gate.id, status: "cancelled", output: reason }
|
|
6051
|
-
}
|
|
6052
|
-
});
|
|
6053
|
-
const failResult = (message) => ({
|
|
6054
|
-
content: `action gate failed: ${gate.title}`,
|
|
6055
|
-
metadata: {
|
|
6056
|
-
exitCode: 1,
|
|
6057
|
-
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
6058
|
-
}
|
|
6059
|
-
});
|
|
6408
|
+
const cancelResult = (reason) => buildGateCancelledResult(gate, reason);
|
|
6409
|
+
const failResult = (message) => buildGateFailedResult(gate, message);
|
|
6060
6410
|
const onClose = () => finish(cancelResult("readline closed"));
|
|
6061
6411
|
const onSigint = () => finish(cancelResult("interrupted"));
|
|
6062
6412
|
rl.once("close", onClose);
|
|
@@ -6064,7 +6414,7 @@ function waitForActionGate(rl, input, output, gate, spawnRunner) {
|
|
|
6064
6414
|
rl.question("", async (answer) => {
|
|
6065
6415
|
if (settled) return;
|
|
6066
6416
|
if (isConfirmation) {
|
|
6067
|
-
finish(isApprovedConfirmationInput(answer) ?
|
|
6417
|
+
finish(isApprovedConfirmationInput(answer) ? buildGateConfirmedResult(gate) : cancelResult("confirmation declined"));
|
|
6068
6418
|
return;
|
|
6069
6419
|
}
|
|
6070
6420
|
if (!commandPayload) {
|
|
@@ -6112,24 +6462,10 @@ function isInteractiveInput(input) {
|
|
|
6112
6462
|
return Boolean(candidate.isTTY) && typeof candidate.setRawMode === "function";
|
|
6113
6463
|
}
|
|
6114
6464
|
function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
6115
|
-
const
|
|
6116
|
-
const isConfirmation
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
const title = isInteractiveHandoff ? t("actionGateInteractiveTitle") : gate.title;
|
|
6120
|
-
const body = isInteractiveHandoff ? t("actionGateInteractiveBody") : gate.body;
|
|
6121
|
-
output.write(`
|
|
6122
|
-
[nolo] ${t("actionGateNeeded")}
|
|
6123
|
-
`);
|
|
6124
|
-
output.write(`[nolo] ${title}
|
|
6125
|
-
`);
|
|
6126
|
-
if (body) output.write(`[nolo] ${body}
|
|
6127
|
-
`);
|
|
6128
|
-
output.write(` ${displayCommand}
|
|
6129
|
-
`);
|
|
6130
|
-
output.write(`[nolo] ${isConfirmation ? t("actionGateConfirmHint") : t("actionGateEnterHint")}
|
|
6131
|
-
`);
|
|
6132
|
-
return new Promise((resolve2) => {
|
|
6465
|
+
const meta = deriveGateMeta(gate);
|
|
6466
|
+
const { commandPayload, isConfirmation, displayCommand } = meta;
|
|
6467
|
+
writeGatePrompt(output, meta);
|
|
6468
|
+
return new Promise((resolve4) => {
|
|
6133
6469
|
const rawInput = input;
|
|
6134
6470
|
let settled = false;
|
|
6135
6471
|
let commandRunning = false;
|
|
@@ -6139,22 +6475,10 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
6139
6475
|
settled = true;
|
|
6140
6476
|
hooks?.registerToken?.(null);
|
|
6141
6477
|
input.off("data", onData);
|
|
6142
|
-
|
|
6478
|
+
resolve4(result);
|
|
6143
6479
|
};
|
|
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
|
-
});
|
|
6480
|
+
const cancel = (reason) => finish(buildGateCancelledResult(gate, reason));
|
|
6481
|
+
const fail = (message) => finish(buildGateFailedResult(gate, message));
|
|
6158
6482
|
const runCommand = async () => {
|
|
6159
6483
|
if (settled || commandRunning) return;
|
|
6160
6484
|
commandRunning = true;
|
|
@@ -6197,7 +6521,7 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
6197
6521
|
};
|
|
6198
6522
|
const handleToken = (text) => {
|
|
6199
6523
|
if (settled || commandRunning) return;
|
|
6200
|
-
if (text.includes(
|
|
6524
|
+
if (text.includes(CTRL_C) || isConfirmation && text === ESC) {
|
|
6201
6525
|
cancel("interrupted");
|
|
6202
6526
|
return;
|
|
6203
6527
|
}
|
|
@@ -6207,28 +6531,16 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
6207
6531
|
if (newline >= 0) {
|
|
6208
6532
|
const normalized = confirmationLine.trim().toLowerCase();
|
|
6209
6533
|
confirmationLine = "";
|
|
6210
|
-
if (!isApprovedConfirmationInput(
|
|
6534
|
+
if (!isApprovedConfirmationInput(normalized)) {
|
|
6211
6535
|
cancel("confirmation declined");
|
|
6212
6536
|
return;
|
|
6213
6537
|
}
|
|
6214
|
-
finish(
|
|
6215
|
-
content: `action gate completed: ${gate.title}`,
|
|
6216
|
-
metadata: { actionGateResult: { gateId: gate.id, status: "completed", output: "confirmed" } }
|
|
6217
|
-
});
|
|
6538
|
+
finish(buildGateConfirmedResult(gate));
|
|
6218
6539
|
}
|
|
6219
6540
|
return;
|
|
6220
6541
|
}
|
|
6221
6542
|
if (text.includes("\r") || text.includes("\n")) {
|
|
6222
|
-
|
|
6223
|
-
finish({
|
|
6224
|
-
content: `action gate completed: ${gate.title}`,
|
|
6225
|
-
metadata: {
|
|
6226
|
-
actionGateResult: { gateId: gate.id, status: "completed", output: "confirmed" }
|
|
6227
|
-
}
|
|
6228
|
-
});
|
|
6229
|
-
} else {
|
|
6230
|
-
void runCommand();
|
|
6231
|
-
}
|
|
6543
|
+
void runCommand();
|
|
6232
6544
|
}
|
|
6233
6545
|
};
|
|
6234
6546
|
const onData = (chunk) => {
|
|
@@ -6242,6 +6554,40 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
6242
6554
|
}
|
|
6243
6555
|
});
|
|
6244
6556
|
}
|
|
6557
|
+
function asConfirmPermissionRequest(gate) {
|
|
6558
|
+
return gate;
|
|
6559
|
+
}
|
|
6560
|
+
function isAutoConfirmableFileWriteGate(gate) {
|
|
6561
|
+
return gate.kind === "confirm" && asConfirmPermissionRequest(gate).action === "file_write";
|
|
6562
|
+
}
|
|
6563
|
+
async function resolveActionGate(gate, deps) {
|
|
6564
|
+
if (gate.kind === "confirm") {
|
|
6565
|
+
const approved = await deps.dialogHost.run(
|
|
6566
|
+
(anchor) => runConfirmDialog({
|
|
6567
|
+
request: asConfirmPermissionRequest(gate),
|
|
6568
|
+
input: deps.input,
|
|
6569
|
+
output: deps.output,
|
|
6570
|
+
...anchor
|
|
6571
|
+
})
|
|
6572
|
+
);
|
|
6573
|
+
return approved ? buildGateConfirmedResult(gate) : buildGateCancelledResult(gate, "confirmation declined");
|
|
6574
|
+
}
|
|
6575
|
+
return deps.dialogHost.withKeyboard(async () => {
|
|
6576
|
+
let subprocessRan = false;
|
|
6577
|
+
deps.pauseComposer();
|
|
6578
|
+
try {
|
|
6579
|
+
return await waitForRawActionGate(deps.input, deps.output, gate, deps.spawnRunner, {
|
|
6580
|
+
beforeSubprocess: () => {
|
|
6581
|
+
subprocessRan = true;
|
|
6582
|
+
},
|
|
6583
|
+
afterSubprocess: deps.resumeComposerFromSubprocess,
|
|
6584
|
+
registerToken: deps.registerToken
|
|
6585
|
+
});
|
|
6586
|
+
} finally {
|
|
6587
|
+
if (!subprocessRan) deps.resumeComposerFromDialog();
|
|
6588
|
+
}
|
|
6589
|
+
});
|
|
6590
|
+
}
|
|
6245
6591
|
async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, confirmDestructiveAction) {
|
|
6246
6592
|
const scheduleTitlePatchSync = (runResult) => {
|
|
6247
6593
|
if (!runResult.titlePatchPromise || !runResult.dialogId) return;
|
|
@@ -6313,7 +6659,6 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6313
6659
|
ctx.scheduleRender();
|
|
6314
6660
|
}) : ctx.output;
|
|
6315
6661
|
const requestUserChoice = isInteractiveInput(ctx.input) && ctx.dialogHost ? async (choiceReq) => {
|
|
6316
|
-
ctx.modalOwnsKeyboard = true;
|
|
6317
6662
|
try {
|
|
6318
6663
|
return await ctx.dialogHost.run(
|
|
6319
6664
|
(anchor) => runAskChoiceDialog({
|
|
@@ -6325,12 +6670,11 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6325
6670
|
);
|
|
6326
6671
|
} catch {
|
|
6327
6672
|
return { kind: "cancelled" };
|
|
6328
|
-
} finally {
|
|
6329
|
-
ctx.composerDecoderDrain?.();
|
|
6330
|
-
ctx.modalOwnsKeyboard = false;
|
|
6331
6673
|
}
|
|
6332
6674
|
} : void 0;
|
|
6333
6675
|
ctx.runRegistryPoller.beginHold();
|
|
6676
|
+
const injectionInbox = createTurnInjectionInbox();
|
|
6677
|
+
ctx.turnInjectionInbox = injectionInbox;
|
|
6334
6678
|
try {
|
|
6335
6679
|
ctx.activeTurnAbort = new AbortController();
|
|
6336
6680
|
ctx.activeTurnEpoch = myEpoch;
|
|
@@ -6347,6 +6691,7 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6347
6691
|
...confirmDestructiveAction ? { confirmDestructiveAction } : {},
|
|
6348
6692
|
...requestUserChoice ? { requestUserChoice } : {},
|
|
6349
6693
|
abortSignal: ctx.activeTurnAbort.signal,
|
|
6694
|
+
drainInjections: () => injectionInbox.drain(),
|
|
6350
6695
|
pastedTextStore: ctx.pasteStore,
|
|
6351
6696
|
activityReporter: ctx.activityReporter,
|
|
6352
6697
|
onAgentRunStatus: (snapshot) => {
|
|
@@ -6372,7 +6717,9 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6372
6717
|
...runResult.title ? { dialogTitle: runResult.title } : {}
|
|
6373
6718
|
} : {},
|
|
6374
6719
|
...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {},
|
|
6375
|
-
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {}
|
|
6720
|
+
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {},
|
|
6721
|
+
// 本轮已发起 agent 调用(消息已注入),消费切换通知。
|
|
6722
|
+
pendingCwdNotice: void 0
|
|
6376
6723
|
};
|
|
6377
6724
|
if (runResult.dialogId && nextDialogKey) {
|
|
6378
6725
|
ctx.refreshDialogTotalCredits(runResult.dialogId, nextDialogKey);
|
|
@@ -6420,7 +6767,11 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6420
6767
|
// estimatedContextTokens:下一轮若 provider 不返回 usage,context
|
|
6421
6768
|
// chip 仍显示真实累计占用而不是回退到启动时的静态估算。
|
|
6422
6769
|
...runResult.turnTokens && runResult.turnTokens.input > 0 ? { estimatedContextTokens: runResult.turnTokens.input } : {},
|
|
6423
|
-
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {}
|
|
6770
|
+
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {},
|
|
6771
|
+
// 切换消息本轮已注入 agent 上下文(runAgentChat 已读),消费掉,
|
|
6772
|
+
// 避免下轮重复注入。仅当确实发起了 agent 调用(本轮是真实 turn、
|
|
6773
|
+
// 而非纯 child-run-completed 事件短路)时才清除。
|
|
6774
|
+
pendingCwdNotice: void 0
|
|
6424
6775
|
};
|
|
6425
6776
|
if (runResult.dialogId && nextDialogKey) {
|
|
6426
6777
|
ctx.refreshDialogTotalCredits(runResult.dialogId, nextDialogKey);
|
|
@@ -6443,6 +6794,21 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6443
6794
|
ctx.runRegistryPoller.endHold();
|
|
6444
6795
|
ctx.activityIndicator.stop();
|
|
6445
6796
|
ctx.activeTurnAbort = null;
|
|
6797
|
+
if (ctx.turnInjectionInbox === injectionInbox) ctx.turnInjectionInbox = null;
|
|
6798
|
+
const leftover = injectionInbox.close();
|
|
6799
|
+
if (leftover.length > 0) {
|
|
6800
|
+
const binding = ensureChatQueueBinding(
|
|
6801
|
+
ctx,
|
|
6802
|
+
actionGateHandler,
|
|
6803
|
+
confirmDestructiveAction
|
|
6804
|
+
);
|
|
6805
|
+
for (const entry of leftover) {
|
|
6806
|
+
try {
|
|
6807
|
+
binding.enqueue(entry.fallback);
|
|
6808
|
+
} catch {
|
|
6809
|
+
}
|
|
6810
|
+
}
|
|
6811
|
+
}
|
|
6446
6812
|
}
|
|
6447
6813
|
}
|
|
6448
6814
|
function ensureChatQueueBinding(ctx, actionGateHandler, confirmDestructiveAction) {
|
|
@@ -7030,7 +7396,7 @@ function createFixedInput(output, config) {
|
|
|
7030
7396
|
const renderInputArea = (buffer, cursorPos) => {
|
|
7031
7397
|
const colorEnabled = resolveCliColorEnabled();
|
|
7032
7398
|
const cols = Math.max(1, getColumns());
|
|
7033
|
-
const completions = completeSlashCommand(buffer);
|
|
7399
|
+
const completions = completeSlashCommand(buffer, config.getCwd?.());
|
|
7034
7400
|
const sections = [];
|
|
7035
7401
|
if (completions.length > 0) {
|
|
7036
7402
|
sections.push(fitAnsiLine(dimCliText(completions.join(" "), colorEnabled), cols));
|
|
@@ -7051,6 +7417,10 @@ function createFixedInput(output, config) {
|
|
|
7051
7417
|
for (const line of queueLines) {
|
|
7052
7418
|
sections.push(fitAnsiLine(line.replace(/\r?\n/g, " "), cols));
|
|
7053
7419
|
}
|
|
7420
|
+
const attachmentLine = config.getAttachmentLine?.() ?? null;
|
|
7421
|
+
if (attachmentLine) {
|
|
7422
|
+
sections.push(fitAnsiLine(attachmentLine.replace(/\r?\n/g, " "), cols));
|
|
7423
|
+
}
|
|
7054
7424
|
const promptRaw = t("promptLabel");
|
|
7055
7425
|
const promptWidth = displayWidth(promptRaw);
|
|
7056
7426
|
const prompt = colorEnabled ? `${themeColorSequence("accent")}${promptRaw}\x1B[39m` : promptRaw;
|
|
@@ -7100,7 +7470,7 @@ function createFixedInput(output, config) {
|
|
|
7100
7470
|
}
|
|
7101
7471
|
const text = sections.join("\n");
|
|
7102
7472
|
const lines = sections.length;
|
|
7103
|
-
const headerRows = (completions.length > 0 ? 1 : 0) + 2 + (titleLine ? 1 : 0) + activityLines.length + queueLines.length;
|
|
7473
|
+
const headerRows = (completions.length > 0 ? 1 : 0) + 2 + (titleLine ? 1 : 0) + activityLines.length + queueLines.length + (attachmentLine ? 1 : 0);
|
|
7104
7474
|
return { text, lines, cursorCol, cursorRow: headerRows + cursorRow };
|
|
7105
7475
|
};
|
|
7106
7476
|
const repaintAt = (buffer, cursorPos, force = false) => {
|
|
@@ -7510,6 +7880,7 @@ async function runSubmittedSlashLine(line, host, actionGateHandler, confirmDestr
|
|
|
7510
7880
|
turnCtx,
|
|
7511
7881
|
emitCommandOutput,
|
|
7512
7882
|
renderHistoryToOutput,
|
|
7883
|
+
scheduleRender,
|
|
7513
7884
|
refreshDialogTotalCredits,
|
|
7514
7885
|
persistExplicitAgentSwitch,
|
|
7515
7886
|
persistAgentSelection: persistAgentSelection2,
|
|
@@ -7683,6 +8054,18 @@ async function runSubmittedSlashLine(line, host, actionGateHandler, confirmDestr
|
|
|
7683
8054
|
emitCommandOutput(t("themeRefreshFailed"));
|
|
7684
8055
|
}
|
|
7685
8056
|
}
|
|
8057
|
+
if (result.action?.type === "cwd-refresh") {
|
|
8058
|
+
if ((options.env?.NOLO_CLI_GIT_STATUS ?? process.env.NOLO_CLI_GIT_STATUS) !== "0") {
|
|
8059
|
+
const gitStatus = await detectGitStatusAsync(host.state.cwd);
|
|
8060
|
+
if (gitStatus !== void 0) {
|
|
8061
|
+
host.state = { ...host.state, gitStatus };
|
|
8062
|
+
}
|
|
8063
|
+
}
|
|
8064
|
+
if (result.action.switchMessage) {
|
|
8065
|
+
emitCommandOutput(result.action.switchMessage);
|
|
8066
|
+
}
|
|
8067
|
+
scheduleRender();
|
|
8068
|
+
}
|
|
7686
8069
|
if (result.action?.type === "pick-agent") {
|
|
7687
8070
|
try {
|
|
7688
8071
|
const pickResult = await dialogHost.run(
|
|
@@ -8114,7 +8497,6 @@ async function runTuiWorkspace(options) {
|
|
|
8114
8497
|
isTurnActive: () => activeTurnAbort !== null,
|
|
8115
8498
|
fallbackLabel: () => `${state.agentName} -> working`,
|
|
8116
8499
|
stoppingLabel: () => t("turnStopping"),
|
|
8117
|
-
displayMode: () => state.toolDisplay,
|
|
8118
8500
|
onRepaint: () => {
|
|
8119
8501
|
if (fixedInput.active && !fixedInput.isPaused()) {
|
|
8120
8502
|
output.write("\x1B[?2026h\x1B[?25l");
|
|
@@ -8158,7 +8540,14 @@ async function runTuiWorkspace(options) {
|
|
|
8158
8540
|
getInputLines: () => fixedInput.getInputLines(),
|
|
8159
8541
|
isPaused: () => fixedInput.isPaused()
|
|
8160
8542
|
},
|
|
8161
|
-
output
|
|
8543
|
+
output,
|
|
8544
|
+
// The decoder-drain hook is only bound once the interactive raw-mode
|
|
8545
|
+
// composer installs its decoder (inside the `isInteractiveInput` block
|
|
8546
|
+
// below); the non-raw readline path never binds it, so this stays a
|
|
8547
|
+
// no-op there — which is correct, that path has no raw decoder to drain.
|
|
8548
|
+
drainDecoder: () => {
|
|
8549
|
+
if (composerDecoderDrain) composerDecoderDrain();
|
|
8550
|
+
}
|
|
8162
8551
|
});
|
|
8163
8552
|
let sessionEnded = false;
|
|
8164
8553
|
const selectionState = createSelectionState();
|
|
@@ -8187,7 +8576,7 @@ async function runTuiWorkspace(options) {
|
|
|
8187
8576
|
const repaintBanner = () => {
|
|
8188
8577
|
if (!output.isTTY) return;
|
|
8189
8578
|
if (fixedInput.isPaused()) return;
|
|
8190
|
-
if (
|
|
8579
|
+
if (dialogHost.isKeyboardClaimed()) return;
|
|
8191
8580
|
const currentColumns = output.columns ?? 80;
|
|
8192
8581
|
const welcome = renderWelcome(state, 0, 0, currentColumns);
|
|
8193
8582
|
const lines = welcome.split("\n");
|
|
@@ -8236,7 +8625,6 @@ async function runTuiWorkspace(options) {
|
|
|
8236
8625
|
selectionState.anchor = null;
|
|
8237
8626
|
selectionState.head = null;
|
|
8238
8627
|
};
|
|
8239
|
-
let modalOwnsKeyboard = false;
|
|
8240
8628
|
let rawActionGateTokenHandler = null;
|
|
8241
8629
|
const refreshDialogTotalCredits = (dialogId, dialogKey) => {
|
|
8242
8630
|
const env = options.env ?? process.env;
|
|
@@ -8272,6 +8660,7 @@ async function runTuiWorkspace(options) {
|
|
|
8272
8660
|
if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
|
|
8273
8661
|
};
|
|
8274
8662
|
let chatQueueBinding = null;
|
|
8663
|
+
let turnInjectionInbox = null;
|
|
8275
8664
|
const turnCtx = {
|
|
8276
8665
|
get state() {
|
|
8277
8666
|
return state;
|
|
@@ -8309,24 +8698,18 @@ async function runTuiWorkspace(options) {
|
|
|
8309
8698
|
set activeTurnEpoch(v) {
|
|
8310
8699
|
activeTurnEpoch = v;
|
|
8311
8700
|
},
|
|
8312
|
-
get modalOwnsKeyboard() {
|
|
8313
|
-
return modalOwnsKeyboard;
|
|
8314
|
-
},
|
|
8315
|
-
set modalOwnsKeyboard(v) {
|
|
8316
|
-
modalOwnsKeyboard = v;
|
|
8317
|
-
},
|
|
8318
|
-
get composerDecoderDrain() {
|
|
8319
|
-
return composerDecoderDrain;
|
|
8320
|
-
},
|
|
8321
|
-
set composerDecoderDrain(v) {
|
|
8322
|
-
composerDecoderDrain = v;
|
|
8323
|
-
},
|
|
8324
8701
|
get chatQueueBinding() {
|
|
8325
8702
|
return chatQueueBinding;
|
|
8326
8703
|
},
|
|
8327
8704
|
set chatQueueBinding(v) {
|
|
8328
8705
|
chatQueueBinding = v;
|
|
8329
8706
|
},
|
|
8707
|
+
get turnInjectionInbox() {
|
|
8708
|
+
return turnInjectionInbox;
|
|
8709
|
+
},
|
|
8710
|
+
set turnInjectionInbox(v) {
|
|
8711
|
+
turnInjectionInbox = v;
|
|
8712
|
+
},
|
|
8330
8713
|
get sessionEnded() {
|
|
8331
8714
|
return sessionEnded;
|
|
8332
8715
|
},
|
|
@@ -8392,6 +8775,7 @@ async function runTuiWorkspace(options) {
|
|
|
8392
8775
|
turnCtx,
|
|
8393
8776
|
emitCommandOutput,
|
|
8394
8777
|
renderHistoryToOutput,
|
|
8778
|
+
scheduleRender,
|
|
8395
8779
|
refreshDialogTotalCredits,
|
|
8396
8780
|
persistExplicitAgentSwitch,
|
|
8397
8781
|
persistAgentSelection,
|
|
@@ -8424,9 +8808,16 @@ async function runTuiWorkspace(options) {
|
|
|
8424
8808
|
return dimCliText(` \u2937 ${i + 1}. ${oneLine}`, colorEnabled);
|
|
8425
8809
|
});
|
|
8426
8810
|
},
|
|
8811
|
+
getAttachmentLine: () => {
|
|
8812
|
+
const line = formatComposerAttachmentLine(state.attachedImages);
|
|
8813
|
+
return line ? dimCliText(line, resolveCliColorEnabled()) : null;
|
|
8814
|
+
},
|
|
8427
8815
|
onInputLinesChange: () => {
|
|
8428
8816
|
renderHistoryToOutput();
|
|
8429
|
-
}
|
|
8817
|
+
},
|
|
8818
|
+
// /cd 路径补全候选行渲染需要当前 cwd(读 state 而非入参,保证
|
|
8819
|
+
// /cd 切换后立即以新 cwd 渲染,composer 不必重建)。
|
|
8820
|
+
getCwd: () => state.cwd
|
|
8430
8821
|
});
|
|
8431
8822
|
fixedInput = {
|
|
8432
8823
|
...baseFixedInput,
|
|
@@ -8500,39 +8891,33 @@ async function runTuiWorkspace(options) {
|
|
|
8500
8891
|
input.setRawMode?.(false);
|
|
8501
8892
|
};
|
|
8502
8893
|
const buildInteractiveTurnHandlers = () => {
|
|
8503
|
-
const releaseKeyboardToComposer = () => {
|
|
8504
|
-
onData.destroy();
|
|
8505
|
-
modalOwnsKeyboard = false;
|
|
8506
|
-
};
|
|
8507
8894
|
const actionGateHandler = async (gate) => {
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
return await waitForRawActionGate(input, output, gate, spawnRunner, {
|
|
8511
|
-
beforeSubprocess: () => fixedInput.pause(),
|
|
8512
|
-
afterSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
8513
|
-
registerToken: (handler) => {
|
|
8514
|
-
rawActionGateTokenHandler = handler;
|
|
8515
|
-
}
|
|
8516
|
-
});
|
|
8517
|
-
} finally {
|
|
8518
|
-
releaseKeyboardToComposer();
|
|
8895
|
+
if (state.autoConfirm && isAutoConfirmableFileWriteGate(gate)) {
|
|
8896
|
+
return buildGateConfirmedResult(gate);
|
|
8519
8897
|
}
|
|
8898
|
+
return await resolveActionGate(gate, {
|
|
8899
|
+
dialogHost,
|
|
8900
|
+
input,
|
|
8901
|
+
output,
|
|
8902
|
+
spawnRunner,
|
|
8903
|
+
registerToken: (handler) => {
|
|
8904
|
+
rawActionGateTokenHandler = handler;
|
|
8905
|
+
},
|
|
8906
|
+
pauseComposer: () => fixedInput.pause(),
|
|
8907
|
+
resumeComposerFromSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
8908
|
+
resumeComposerFromDialog: () => fixedInput.resumeFromDialog()
|
|
8909
|
+
});
|
|
8520
8910
|
};
|
|
8521
8911
|
const confirmDestructiveAction = async (request) => {
|
|
8522
8912
|
if (state.autoConfirm) return true;
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
})
|
|
8532
|
-
);
|
|
8533
|
-
} finally {
|
|
8534
|
-
releaseKeyboardToComposer();
|
|
8535
|
-
}
|
|
8913
|
+
return await dialogHost.run(
|
|
8914
|
+
(anchor) => runConfirmDialog({
|
|
8915
|
+
request,
|
|
8916
|
+
input,
|
|
8917
|
+
output,
|
|
8918
|
+
...anchor
|
|
8919
|
+
})
|
|
8920
|
+
);
|
|
8536
8921
|
};
|
|
8537
8922
|
return { actionGateHandler, confirmDestructiveAction };
|
|
8538
8923
|
};
|
|
@@ -8568,8 +8953,26 @@ ${err.message}` : ""}`
|
|
|
8568
8953
|
runWakeHandler = (event) => {
|
|
8569
8954
|
if (done) return;
|
|
8570
8955
|
if (busy || fixedInput.isPaused()) {
|
|
8571
|
-
const
|
|
8572
|
-
|
|
8956
|
+
const text = typeof event === "string" ? event : event.text;
|
|
8957
|
+
const injected = !!turnInjectionInbox && turnInjectionInbox.push({ text, fallback: event });
|
|
8958
|
+
if (injected) {
|
|
8959
|
+
const displayText = typeof event !== "string" && event.kind === "child-run-completed" ? event.displayText ?? event.text : text;
|
|
8960
|
+
const noticeLine = dimCliText(displayText, resolveCliColorEnabled());
|
|
8961
|
+
if (!isInteractiveInput(input)) {
|
|
8962
|
+
output.write(`${noticeLine}
|
|
8963
|
+
`);
|
|
8964
|
+
} else {
|
|
8965
|
+
history.followBottom = true;
|
|
8966
|
+
appendStreamSafeNotice(history, noticeLine, {
|
|
8967
|
+
appendLocalTurn,
|
|
8968
|
+
startTurn
|
|
8969
|
+
});
|
|
8970
|
+
renderHistoryToOutput();
|
|
8971
|
+
}
|
|
8972
|
+
} else {
|
|
8973
|
+
const { actionGateHandler, confirmDestructiveAction } = buildInteractiveTurnHandlers();
|
|
8974
|
+
ensureChatQueueBinding(turnCtx, actionGateHandler, confirmDestructiveAction).enqueue(event);
|
|
8975
|
+
}
|
|
8573
8976
|
if (fixedInput.active && !fixedInput.isPaused()) {
|
|
8574
8977
|
fixedInput.repaint(buffer, cursorPos);
|
|
8575
8978
|
}
|
|
@@ -8710,6 +9113,19 @@ ${err.message}` : ""}`
|
|
|
8710
9113
|
output.write(`${refreshMsg}
|
|
8711
9114
|
`);
|
|
8712
9115
|
}
|
|
9116
|
+
} else if (res.action?.type === "cwd-refresh") {
|
|
9117
|
+
state = res.nextState;
|
|
9118
|
+
if (res.output) {
|
|
9119
|
+
output.write(`${res.output}
|
|
9120
|
+
`);
|
|
9121
|
+
}
|
|
9122
|
+
if ((options.env?.NOLO_CLI_GIT_STATUS ?? process.env.NOLO_CLI_GIT_STATUS) !== "0") {
|
|
9123
|
+
const gitStatus = await detectGitStatusAsync(state.cwd);
|
|
9124
|
+
if (gitStatus !== void 0) {
|
|
9125
|
+
state = { ...state, gitStatus };
|
|
9126
|
+
}
|
|
9127
|
+
}
|
|
9128
|
+
scheduleRender();
|
|
8713
9129
|
} else if (res.action) {
|
|
8714
9130
|
output.write(
|
|
8715
9131
|
"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"
|
|
@@ -8734,7 +9150,7 @@ ${hint}` : hint;
|
|
|
8734
9150
|
};
|
|
8735
9151
|
const handleInputToken = async (sequence) => {
|
|
8736
9152
|
if (done) return;
|
|
8737
|
-
if (
|
|
9153
|
+
if (dialogHost.isKeyboardClaimed()) {
|
|
8738
9154
|
rawActionGateTokenHandler?.(sequence);
|
|
8739
9155
|
return;
|
|
8740
9156
|
}
|
|
@@ -8918,8 +9334,20 @@ ${merged}` : merged;
|
|
|
8918
9334
|
if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
|
|
8919
9335
|
return;
|
|
8920
9336
|
}
|
|
9337
|
+
if (isBackspaceSequence(sequence, {}) && buffer === "" && state.attachedImages.length > 0) {
|
|
9338
|
+
const undo = popLastAttachedImage(state.attachedImages);
|
|
9339
|
+
if (undo.handled && undo.removed) {
|
|
9340
|
+
state = { ...state, attachedImages: undo.images };
|
|
9341
|
+
emitCommandOutput(
|
|
9342
|
+
`[nolo] ${t("attachmentRemovedHint", undo.removed.filename, String(undo.images.length))}`
|
|
9343
|
+
);
|
|
9344
|
+
if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
|
|
9345
|
+
return;
|
|
9346
|
+
}
|
|
9347
|
+
}
|
|
8921
9348
|
const result = applyTuiInputKey(buffer, sequence, {}, cursorPos, {
|
|
8922
|
-
pasteStore
|
|
9349
|
+
pasteStore,
|
|
9350
|
+
cwd: state.cwd
|
|
8923
9351
|
});
|
|
8924
9352
|
if (result.redraw) {
|
|
8925
9353
|
resetHistoryFrameDiffCache(output);
|
|
@@ -8942,7 +9370,7 @@ ${merged}` : merged;
|
|
|
8942
9370
|
if (busyLock) {
|
|
8943
9371
|
const trimmedText = submittedText.trim();
|
|
8944
9372
|
const busySlashCommand = trimmedText.split(/\s+/)[0]?.toLowerCase();
|
|
8945
|
-
const isBusyLocalSlash = busySlashCommand === "/context" || busySlashCommand === "/ctx" || busySlashCommand === "/
|
|
9373
|
+
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";
|
|
8946
9374
|
if (isBusyLocalSlash) {
|
|
8947
9375
|
await handleBusyLocalSlash(submittedText, busySlashCommand);
|
|
8948
9376
|
return;
|
|
@@ -9012,9 +9440,9 @@ ${merged}` : merged;
|
|
|
9012
9440
|
input.on("data", onData);
|
|
9013
9441
|
fixedInput.repaint(buffer, cursorPos);
|
|
9014
9442
|
refreshGitStatus();
|
|
9015
|
-
await new Promise((
|
|
9016
|
-
resolveDone =
|
|
9017
|
-
if (done)
|
|
9443
|
+
await new Promise((resolve4) => {
|
|
9444
|
+
resolveDone = resolve4;
|
|
9445
|
+
if (done) resolve4();
|
|
9018
9446
|
});
|
|
9019
9447
|
} finally {
|
|
9020
9448
|
finish();
|
|
@@ -9028,7 +9456,11 @@ ${merged}` : merged;
|
|
|
9028
9456
|
for await (const line of rl) {
|
|
9029
9457
|
const shouldExit = await runSubmittedLine(
|
|
9030
9458
|
line,
|
|
9031
|
-
(gate) =>
|
|
9459
|
+
(gate) => (
|
|
9460
|
+
// /auto on 同款短路,见上方交互路径的 actionGateHandler 注释:
|
|
9461
|
+
// 只放行 file_write 的 confirm gate,handoff/input 类仍要求真人操作。
|
|
9462
|
+
state.autoConfirm && isAutoConfirmableFileWriteGate(gate) ? Promise.resolve(buildGateConfirmedResult(gate)) : waitForActionGate(rl, input, output, gate, spawnRunner)
|
|
9463
|
+
),
|
|
9032
9464
|
async (request) => {
|
|
9033
9465
|
if (state.autoConfirm) return true;
|
|
9034
9466
|
rl.pause();
|
|
@@ -9067,12 +9499,16 @@ ${renderStatusLine(state)}
|
|
|
9067
9499
|
}
|
|
9068
9500
|
async function startTuiWorkspace(options) {
|
|
9069
9501
|
const themeOwner = ++latestWorkspaceThemeOwner;
|
|
9502
|
+
void sweepStaleClipboardFiles(getDefaultClipboardTempDir()).catch(() => {
|
|
9503
|
+
});
|
|
9070
9504
|
try {
|
|
9071
9505
|
return await runTuiWorkspace(options);
|
|
9072
9506
|
} finally {
|
|
9073
9507
|
if (themeOwner === latestWorkspaceThemeOwner) {
|
|
9074
9508
|
resetWorkspaceThemeState();
|
|
9075
9509
|
}
|
|
9510
|
+
void sweepStaleClipboardFiles(getDefaultClipboardTempDir()).catch(() => {
|
|
9511
|
+
});
|
|
9076
9512
|
}
|
|
9077
9513
|
}
|
|
9078
9514
|
export {
|