nolo-cli 0.50.0-alpha.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-4BPV4B2U.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-KZSETRE3.js → agentDeleteCommand-SVXKS5SC.js} +30 -28
- package/{agentEmailCommands-5TEW64UO.js → agentEmailCommands-WN7QBTP3.js} +57 -52
- package/{agentListCommands-KVLURCS7.js → agentListCommands-2BEBOQIG.js} +42 -33
- package/{agentMachineCommands-4LQF5YB5.js → agentMachineCommands-WALP3ONU.js} +30 -28
- package/{agentRecordCommands-OXC6JSH6.js → agentRecordCommands-E652SW57.js} +55 -50
- package/{agentRunCommand-4AXTA7MR.js → agentRunCommand-6VXWXKCS.js} +60 -53
- package/{agentRunControl-4GHHSXFZ.js → agentRunControl-LJVFDJGU.js} +3 -1
- package/{agentRuntimeLocal-SIQYQGSK.js → agentRuntimeLocal-SBG7BDFQ.js} +30 -26
- package/{agentSlice-VD3BAJAU.js → agentSlice-3WYXIGEO.js} +8 -8
- package/{agentSuperviseCommands-VB6BUS5H.js → agentSuperviseCommands-F3RFAL7K.js} +2 -2
- package/{appDeleteCommands-LSIIQFYN.js → appDeleteCommands-NTUNMEXY.js} +31 -29
- package/{appDeployCommands-VYGKN7HU.js → appDeployCommands-DISWXRTL.js} +31 -29
- package/{appDeployStatusCommands-ODFHFUR7.js → appDeployStatusCommands-IKRA6B6F.js} +31 -29
- package/{appGetCommands-DPQY67UZ.js → appGetCommands-UMOP2DFV.js} +31 -29
- package/{appListCommands-EFXENXWX.js → appListCommands-ZKFD2AKS.js} +31 -29
- package/{authCommand-WLWOEVYI.js → authCommand-BS3CQC6I.js} +11 -11
- package/{chatQueueReduxAdapter-N5432EP2.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-WWXZYFWM.js → chunk-2TLYVDTN.js} +464 -1135
- package/{chunk-6BYAXNH5.js → chunk-3QOCS5IF.js} +11 -2
- package/chunk-6IGD47IC.js +19 -0
- package/{chunk-QDNFRWAX.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-OZ4JNDIL.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-JBL24PK6.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-HMMOAG2I.js → chunk-DXOELY7S.js} +67 -69
- package/{chunk-OFZPJ3NT.js → chunk-E4MARS3Q.js} +1 -1
- package/{chunk-27MWS6HD.js → chunk-EAYBPWHX.js} +179 -86
- package/{chunk-DQLYEGP7.js → chunk-EGVY3GMT.js} +1 -1
- package/{chunk-2JYSSXLY.js → chunk-EJFW7TRP.js} +5 -26
- package/{chunk-4YAMAMNA.js → chunk-FGRCSLPV.js} +36 -46
- package/{chunk-VFN256RI.js → chunk-G4WSLTQF.js} +56 -97
- package/{chunk-HR5XDXYM.js → chunk-G5SQVIFZ.js} +3 -3
- package/{chunk-J3UALFHL.js → chunk-GHE5XMVR.js} +1 -1
- package/{chunk-7M72YPM2.js → chunk-GKB4AZKV.js} +440 -2981
- package/{chunk-S3HB4CQY.js → chunk-GKNGRBE6.js} +256 -40
- package/{chunk-Q24S4NDF.js → chunk-HQTK2SFT.js} +1 -1
- package/{chunk-XB7ACJFH.js → chunk-IPTZ5TVU.js} +7 -6
- package/{chunk-4RXXP6WD.js → chunk-J7KDNHUO.js} +5 -64
- package/{chunk-BO3YFOZR.js → chunk-KNQ5LYVZ.js} +57 -2
- package/{chunk-AV4Z57LV.js → chunk-KVVNC5V3.js} +2 -2
- package/{chunk-VKSBVRGP.js → chunk-LVCAWHI5.js} +4 -4
- package/{chunk-5JXRVJAC.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-72COHDZR.js → chunk-OSUZKICS.js} +1600 -190
- package/{chunk-HIDPTO4B.js → chunk-Q2QN2RHG.js} +7 -7
- package/{chunk-L3JWI7WX.js → chunk-QOKAKDPE.js} +15 -11
- package/{chunk-4ZL2KBI7.js → chunk-RFYXK6KI.js} +1 -1
- package/chunk-RQSN75DW.js +1766 -0
- package/{chunk-RPO6WAZV.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-FTSPVLKJ.js → chunk-TUBNQ3OF.js} +2 -2
- package/{chunk-BANYWEYY.js → chunk-TY3ADTX5.js} +1 -1
- package/chunk-UAD2WT54.js +64 -0
- package/{chunk-F22JQTSX.js → chunk-UEV5WVQV.js} +3 -3
- package/{chunk-MCX2LX27.js → chunk-UMCMW5R3.js} +51 -34
- package/{chunk-6L6UPZNH.js → chunk-VFDRZHPM.js} +16 -16
- package/{chunk-C2WF2OY7.js → chunk-W22UTILW.js} +3 -3
- package/{chunk-W3RZLXMA.js → chunk-WERPP2S7.js} +2 -2
- package/{chunk-AZ6DT2UD.js → chunk-WSUHBABG.js} +1 -1
- package/{chunk-3YVCM5PE.js → chunk-X3OGKR5Q.js} +4 -4
- package/{chunk-IERBSHMR.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-Y7TGWSUN.js → chunk-YWY25N4V.js} +1 -1
- package/{chunk-Z7A54NFZ.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-IHKV53QC.js → createAgentAutomationAction-HTMTGX6Q.js} +25 -21
- package/{createDialogAction-4ARDCKPP.js → createDialogAction-WYQBSN6A.js} +27 -23
- package/{createPageAction-GQOCPICU.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-YOTCP26N.js → dialogCommands-FRSIAPKY.js} +31 -29
- package/{dialogSlice-NX26W623.js → dialogSlice-5KPVIAWH.js} +24 -21
- package/{docCreateCommands-JVAMHES4.js → docCreateCommands-DBRJMPDX.js} +30 -28
- package/{docDeleteCommands-LW5DWICT.js → docDeleteCommands-BCYPLWXN.js} +31 -29
- package/{docReadCommands-AQOZS3I5.js → docReadCommands-L5JX4Q7G.js} +30 -28
- package/{docStore-YAE7GYHZ.js → docStore-34NXLCEO.js} +8 -33
- package/{docUpdateCommands-FFGGX5RG.js → docUpdateCommands-RELG7XJD.js} +30 -28
- package/fetchMessages-KZQVBXKY.js +1 -1
- package/{getPricing-JNOCWYDH.js → getPricing-FM7TJZFV.js} +4 -4
- package/{handleSendMessageAction-7YKH4UBI.js → handleSendMessageAction-MEYK7RPD.js} +25 -22
- package/index.js +64 -64
- package/{machineCommands-FMMFBMCQ.js → machineCommands-YSXTOWHQ.js} +59 -54
- package/{machineWsRunDispatch-UODRJY63.js → machineWsRunDispatch-DNAYOPQT.js} +54 -49
- package/memberThunks-KVPBG4V7.js +638 -0
- package/{models-N4NXQ44D.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-GVDEA7RH.js → readlineWorkspace-KZ3LPQG2.js} +866 -377
- package/{removeDialogAgentAction-RMPISD42.js → removeDialogAgentAction-JGSCPML3.js} +12 -11
- package/{runAgentClientLoop-6NCW5AS6.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-7MJVL4XR.js → spaceCommands-OI7RIB2T.js} +30 -28
- package/{streamAgentChatTurn-UAKCHWFN.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-ROUITGAR.js → tools-6ZPQ75XA.js} +37 -32
- package/{tuiSummaryLlmCaller-U4EGD2SX.js → tuiSummaryLlmCaller-YKYQB4ZL.js} +17 -15
- package/{updateDialogTitleAction-R4M6ZXCX.js → updateDialogTitleAction-LRJ7NSOS.js} +26 -22
- package/chunk-EUG45QJR.js +0 -6104
- package/spaceSlice-JVVDCGA3.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-QDNFRWAX.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-IERBSHMR.js";
|
|
155
|
-
import "./chunk-7M72YPM2.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-5JXRVJAC.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-XB7ACJFH.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-BO3YFOZR.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
|
|
|
@@ -1863,6 +2021,18 @@ function formatTerminalRunAge(snapshot, now) {
|
|
|
1863
2021
|
function formatUnassignedFact(snapshot) {
|
|
1864
2022
|
return snapshot.unassigned ? "parent: ?" : null;
|
|
1865
2023
|
}
|
|
2024
|
+
function sanitizeRunSnapshotForNormal(snapshot) {
|
|
2025
|
+
const clean = (value) => stripAnsi(value).replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
|
|
2026
|
+
return {
|
|
2027
|
+
...snapshot,
|
|
2028
|
+
agentName: snapshot.agentName ? clean(snapshot.agentName) : snapshot.agentName,
|
|
2029
|
+
taskPreview: snapshot.taskPreview ? clean(snapshot.taskPreview) : snapshot.taskPreview,
|
|
2030
|
+
lastAssistantText: snapshot.lastAssistantText ? clean(snapshot.lastAssistantText) : snapshot.lastAssistantText,
|
|
2031
|
+
lastToolNames: snapshot.lastToolNames?.map(clean).filter(Boolean),
|
|
2032
|
+
errorMessage: void 0,
|
|
2033
|
+
logLines: void 0
|
|
2034
|
+
};
|
|
2035
|
+
}
|
|
1866
2036
|
|
|
1867
2037
|
// packages/cli/tui/agentRunPanelLines.ts
|
|
1868
2038
|
function formatPanelProgress(snapshot, now) {
|
|
@@ -2037,11 +2207,12 @@ function createRunDock(deps) {
|
|
|
2037
2207
|
const ordered = orderedEntries();
|
|
2038
2208
|
if (ordered.length === 0) return [];
|
|
2039
2209
|
const at = now();
|
|
2040
|
-
|
|
2041
|
-
|
|
2210
|
+
const displaySnapshots = ordered.map((entry) => sanitizeRunSnapshotForNormal(entry.snapshot));
|
|
2211
|
+
if (displaySnapshots.length === 1) {
|
|
2212
|
+
return formatAgentRunPanelLines(displaySnapshots[0], colorEnabled, at);
|
|
2042
2213
|
}
|
|
2043
2214
|
return formatRunDockLines(
|
|
2044
|
-
|
|
2215
|
+
displaySnapshots,
|
|
2045
2216
|
colorEnabled,
|
|
2046
2217
|
at,
|
|
2047
2218
|
maxRows
|
|
@@ -3312,6 +3483,20 @@ function summarizeAttachment(img) {
|
|
|
3312
3483
|
].join("\n");
|
|
3313
3484
|
return themeText(text, "chrome", colorEnabled);
|
|
3314
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
|
+
}
|
|
3315
3500
|
function mergeAttachedImages(existing, incoming) {
|
|
3316
3501
|
if (incoming.length === 0) return existing;
|
|
3317
3502
|
if (existing.length === 0) return [...incoming];
|
|
@@ -3333,12 +3518,12 @@ function mergeAttachedImages(existing, incoming) {
|
|
|
3333
3518
|
return out;
|
|
3334
3519
|
}
|
|
3335
3520
|
async function readImagePaths(paths, options = {}) {
|
|
3336
|
-
const
|
|
3521
|
+
const resolve4 = options.resolve ?? ((p) => p);
|
|
3337
3522
|
const reportedFailures = /* @__PURE__ */ new Set();
|
|
3338
3523
|
const images = [];
|
|
3339
3524
|
const failures = [];
|
|
3340
3525
|
for (const raw of paths) {
|
|
3341
|
-
const absolute =
|
|
3526
|
+
const absolute = resolve4(raw);
|
|
3342
3527
|
try {
|
|
3343
3528
|
const img = await readImageAsDataUrl(absolute, {
|
|
3344
3529
|
...options.maxBytes !== void 0 ? { maxBytes: options.maxBytes } : {}
|
|
@@ -3378,7 +3563,7 @@ async function resolveAttachmentImageUrls({
|
|
|
3378
3563
|
// packages/cli/tui/clipboardImage.ts
|
|
3379
3564
|
import { createHash } from "node:crypto";
|
|
3380
3565
|
import { mkdirSync } from "node:fs";
|
|
3381
|
-
import { writeFile } from "node:fs/promises";
|
|
3566
|
+
import { readdir, stat as stat2, unlink, writeFile } from "node:fs/promises";
|
|
3382
3567
|
import { tmpdir } from "node:os";
|
|
3383
3568
|
import { join } from "node:path";
|
|
3384
3569
|
var ClipboardImageError = class extends Error {
|
|
@@ -3390,6 +3575,34 @@ var ClipboardImageError = class extends Error {
|
|
|
3390
3575
|
}
|
|
3391
3576
|
};
|
|
3392
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
|
+
}
|
|
3393
3606
|
function isRemoteSession(env = process.env) {
|
|
3394
3607
|
return Boolean(env.SSH_CONNECTION || env.SSH_TTY || env.SSH_CLIENT);
|
|
3395
3608
|
}
|
|
@@ -3405,13 +3618,20 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3405
3618
|
}
|
|
3406
3619
|
if (platform === "darwin") {
|
|
3407
3620
|
const pngpaste = which("pngpaste");
|
|
3408
|
-
if (
|
|
3621
|
+
if (pngpaste) {
|
|
3622
|
+
return { command: [pngpaste, "-"], outputFormat: "raw" };
|
|
3623
|
+
}
|
|
3624
|
+
const osascript = which("osascript");
|
|
3625
|
+
if (!osascript) {
|
|
3409
3626
|
throw new ClipboardImageError(
|
|
3410
3627
|
"binary-missing",
|
|
3411
|
-
"\u672A\u627E\u5230 pngpaste\uFF0C\u8BF7\u8FD0\u884C brew install pngpaste \u5B89\u88C5\uFF0C\u6216\u76F4\u63A5\u62D6\u5165\u56FE\u7247\u6587\u4EF6/\u8F93\u5165\u56FE\u7247\u8DEF\u5F84"
|
|
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"
|
|
3412
3629
|
);
|
|
3413
3630
|
}
|
|
3414
|
-
return {
|
|
3631
|
+
return {
|
|
3632
|
+
command: [osascript, "-e", "the clipboard as \xABclass PNGf\xBB"],
|
|
3633
|
+
outputFormat: "osascript-hex"
|
|
3634
|
+
};
|
|
3415
3635
|
}
|
|
3416
3636
|
if (platform === "win32") {
|
|
3417
3637
|
const ps = which("powershell.exe") || which("powershell") || which("pwsh.exe") || which("pwsh");
|
|
@@ -3428,7 +3648,8 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3428
3648
|
"-NonInteractive",
|
|
3429
3649
|
"-Command",
|
|
3430
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) }"
|
|
3431
|
-
]
|
|
3651
|
+
],
|
|
3652
|
+
outputFormat: "raw"
|
|
3432
3653
|
};
|
|
3433
3654
|
}
|
|
3434
3655
|
if (platform === "linux") {
|
|
@@ -3441,17 +3662,18 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3441
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"
|
|
3442
3663
|
);
|
|
3443
3664
|
}
|
|
3444
|
-
return { command: [wlPaste2, "--type", "image/png"] };
|
|
3665
|
+
return { command: [wlPaste2, "--type", "image/png"], outputFormat: "raw" };
|
|
3445
3666
|
}
|
|
3446
3667
|
const xclip = which("xclip");
|
|
3447
3668
|
if (xclip) {
|
|
3448
3669
|
return {
|
|
3449
|
-
command: [xclip, "-selection", "clipboard", "-t", "image/png", "-o"]
|
|
3670
|
+
command: [xclip, "-selection", "clipboard", "-t", "image/png", "-o"],
|
|
3671
|
+
outputFormat: "raw"
|
|
3450
3672
|
};
|
|
3451
3673
|
}
|
|
3452
3674
|
const wlPaste = which("wl-paste");
|
|
3453
3675
|
if (wlPaste) {
|
|
3454
|
-
return { command: [wlPaste, "--type", "image/png"] };
|
|
3676
|
+
return { command: [wlPaste, "--type", "image/png"], outputFormat: "raw" };
|
|
3455
3677
|
}
|
|
3456
3678
|
throw new ClipboardImageError(
|
|
3457
3679
|
"binary-missing",
|
|
@@ -3463,6 +3685,21 @@ function getClipboardImageCommand(deps = {}) {
|
|
|
3463
3685
|
`\u5F53\u524D\u64CD\u4F5C\u7CFB\u7EDF\u6682\u4E0D\u652F\u6301\u526A\u8D34\u677F\u56FE\u50CF\u8BFB\u53D6: ${platform}`
|
|
3464
3686
|
);
|
|
3465
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
|
+
}
|
|
3466
3703
|
async function readClipboardImage(deps = {}) {
|
|
3467
3704
|
const env = deps.env ?? process.env;
|
|
3468
3705
|
const platform = deps.platform ?? process.platform;
|
|
@@ -3470,8 +3707,8 @@ async function readClipboardImage(deps = {}) {
|
|
|
3470
3707
|
const spawn = deps.spawn ?? Bun.spawn;
|
|
3471
3708
|
const maxBytes = deps.maxBytes ?? DEFAULT_MAX_IMAGE_BYTES;
|
|
3472
3709
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_CLIPBOARD_TIMEOUT_MS;
|
|
3473
|
-
const tempDir = deps.tempDir ??
|
|
3474
|
-
const { command } = getClipboardImageCommand({
|
|
3710
|
+
const tempDir = deps.tempDir ?? getDefaultClipboardTempDir();
|
|
3711
|
+
const { command, outputFormat } = getClipboardImageCommand({
|
|
3475
3712
|
env,
|
|
3476
3713
|
platform,
|
|
3477
3714
|
which
|
|
@@ -3505,6 +3742,12 @@ async function readClipboardImage(deps = {}) {
|
|
|
3505
3742
|
timeoutPromise
|
|
3506
3743
|
]);
|
|
3507
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
|
+
}
|
|
3508
3751
|
throw new ClipboardImageError(
|
|
3509
3752
|
"empty-clipboard",
|
|
3510
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()}` : "")
|
|
@@ -3523,6 +3766,23 @@ async function readClipboardImage(deps = {}) {
|
|
|
3523
3766
|
`\u8BFB\u53D6\u526A\u8D34\u677F\u56FE\u50CF\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`
|
|
3524
3767
|
);
|
|
3525
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
|
+
}
|
|
3526
3786
|
const compressResult = await compressImage(stdoutBuf, "image/png");
|
|
3527
3787
|
const finalBuf = compressResult.buffer;
|
|
3528
3788
|
const finalMime = compressResult.mime;
|
|
@@ -3583,7 +3843,7 @@ function parseStatusOutput(branch, status) {
|
|
|
3583
3843
|
return { branch, modified, untracked };
|
|
3584
3844
|
}
|
|
3585
3845
|
function execFileUtf8(file, args, cwd) {
|
|
3586
|
-
return new Promise((
|
|
3846
|
+
return new Promise((resolve4, reject) => {
|
|
3587
3847
|
execFile(
|
|
3588
3848
|
file,
|
|
3589
3849
|
args,
|
|
@@ -3593,7 +3853,7 @@ function execFileUtf8(file, args, cwd) {
|
|
|
3593
3853
|
reject(err);
|
|
3594
3854
|
return;
|
|
3595
3855
|
}
|
|
3596
|
-
|
|
3856
|
+
resolve4(typeof stdout === "string" ? stdout : String(stdout ?? ""));
|
|
3597
3857
|
}
|
|
3598
3858
|
);
|
|
3599
3859
|
});
|
|
@@ -3694,7 +3954,7 @@ function renderStatusLine(state, maxWidth) {
|
|
|
3694
3954
|
if (state.autoConfirm === true) {
|
|
3695
3955
|
emergency.push(themeText("\u23F5", "warning", colorEnabled));
|
|
3696
3956
|
}
|
|
3697
|
-
const runningTotal = runningTaskCount
|
|
3957
|
+
const runningTotal = runningTaskCount;
|
|
3698
3958
|
if (runningTotal > 0) {
|
|
3699
3959
|
emergency.push(themeText(`\u2699${runningTotal}`, "info", colorEnabled));
|
|
3700
3960
|
}
|
|
@@ -3847,7 +4107,6 @@ function renderContextPanel(state, colorEnabled = resolveCliColorEnabled()) {
|
|
|
3847
4107
|
t("contextFieldSkills"),
|
|
3848
4108
|
t("contextFieldProfile"),
|
|
3849
4109
|
t("contextFieldRuntime"),
|
|
3850
|
-
t("contextFieldTools"),
|
|
3851
4110
|
t("contextFieldServer")
|
|
3852
4111
|
];
|
|
3853
4112
|
let maxW = 0;
|
|
@@ -3877,8 +4136,7 @@ function renderContextPanel(state, colorEnabled = resolveCliColorEnabled()) {
|
|
|
3877
4136
|
field(labels[4], skills),
|
|
3878
4137
|
field(labels[5], state.profileName),
|
|
3879
4138
|
field(labels[6], state.runtimeMode),
|
|
3880
|
-
field(labels[7], state.
|
|
3881
|
-
field(labels[8], state.serverUrl),
|
|
4139
|
+
field(labels[7], state.serverUrl),
|
|
3882
4140
|
"",
|
|
3883
4141
|
themeText(t("contextNext"), "chrome", colorEnabled),
|
|
3884
4142
|
next("/agents ", ` ${t("contextNextAgents")}`),
|
|
@@ -3908,6 +4166,9 @@ function renderKnownAgents(colorEnabled = resolveCliColorEnabled()) {
|
|
|
3908
4166
|
}
|
|
3909
4167
|
|
|
3910
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";
|
|
3911
4172
|
var PASTE_TOKEN_PREFIX = "\0PASTE\0";
|
|
3912
4173
|
function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
|
|
3913
4174
|
const seq = sequence ?? "";
|
|
@@ -4012,6 +4273,16 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
|
|
|
4012
4273
|
return { buffer, cursorPos: curPos };
|
|
4013
4274
|
}
|
|
4014
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
|
+
}
|
|
4015
4286
|
const completed = completeSlashPrefix(buffer) ?? buffer;
|
|
4016
4287
|
return { buffer: completed, cursorPos: completed.length };
|
|
4017
4288
|
}
|
|
@@ -4064,9 +4335,9 @@ function deleteBufferRange(buffer, start, end, pasteStore) {
|
|
|
4064
4335
|
function releasePastesInRange(buffer, start, end, pasteStore) {
|
|
4065
4336
|
if (!pasteStore || start >= end) return;
|
|
4066
4337
|
const slice = buffer.slice(start, end);
|
|
4067
|
-
|
|
4338
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
|
|
4068
4339
|
let match;
|
|
4069
|
-
while ((match =
|
|
4340
|
+
while ((match = COLLAPSED_PASTE_PLACEHOLDER_RE.exec(slice)) !== null) {
|
|
4070
4341
|
releaseCollapsedPaste(pasteStore, Number(match[1]));
|
|
4071
4342
|
}
|
|
4072
4343
|
}
|
|
@@ -4120,12 +4391,10 @@ var SLASH_COMMANDS = [
|
|
|
4120
4391
|
"/clear",
|
|
4121
4392
|
"/compact",
|
|
4122
4393
|
"/theme",
|
|
4123
|
-
"/density",
|
|
4124
4394
|
"/context",
|
|
4125
4395
|
"/ctx",
|
|
4396
|
+
"/cd",
|
|
4126
4397
|
"/runtime",
|
|
4127
|
-
"/tools",
|
|
4128
|
-
"/thinking",
|
|
4129
4398
|
"/auto",
|
|
4130
4399
|
"/switch",
|
|
4131
4400
|
"/agent",
|
|
@@ -4163,12 +4432,49 @@ function completeSlashPrefix(buffer) {
|
|
|
4163
4432
|
}
|
|
4164
4433
|
return prefix.length > buffer.length ? prefix : null;
|
|
4165
4434
|
}
|
|
4166
|
-
function completeSlashCommand(buffer) {
|
|
4435
|
+
function completeSlashCommand(buffer, cwd) {
|
|
4167
4436
|
if (!buffer.startsWith("/")) return [];
|
|
4168
4437
|
const trimmed = buffer.trim();
|
|
4438
|
+
if (cwd && buffer.startsWith("/cd ")) {
|
|
4439
|
+
const prefix = buffer.slice("/cd ".length);
|
|
4440
|
+
return completeCdPathCandidates(prefix, cwd);
|
|
4441
|
+
}
|
|
4169
4442
|
if (trimmed.includes(" ")) return [];
|
|
4170
4443
|
return SLASH_COMMANDS.filter((cmd) => cmd.startsWith(trimmed) && cmd !== trimmed);
|
|
4171
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
|
+
}
|
|
4172
4478
|
function isLikelySlashCommand(input) {
|
|
4173
4479
|
const trimmed = input.trim();
|
|
4174
4480
|
if (!trimmed.startsWith("/")) return false;
|
|
@@ -4187,6 +4493,11 @@ function stripImageTokens(input, hints) {
|
|
|
4187
4493
|
return compactWhitespace(out);
|
|
4188
4494
|
}
|
|
4189
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
|
+
|
|
4190
4501
|
// packages/cli/tui/agentPicker.ts
|
|
4191
4502
|
function toAgentPickerItems(entries) {
|
|
4192
4503
|
return entries.map((entry) => ({
|
|
@@ -4348,6 +4659,10 @@ function estimateDefaultCliContextTokens(opts = {}) {
|
|
|
4348
4659
|
|
|
4349
4660
|
// packages/cli/tui/sessionDispatch.ts
|
|
4350
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
|
+
}
|
|
4351
4666
|
function createInitialTuiState(env = process.env) {
|
|
4352
4667
|
const agentKey = asOptionalTrimmedString(env.NOLO_AGENT) ?? DEFAULT_TUI_AGENT_KEY;
|
|
4353
4668
|
const agentName = asOptionalTrimmedString(env.NOLO_AGENT_NAME) ?? "nolo";
|
|
@@ -4380,8 +4695,7 @@ function createInitialTuiState(env = process.env) {
|
|
|
4380
4695
|
modeLabel: asOptionalTrimmedString(env.NOLO_CLI_STATUS_MODE) ?? runtimeMode,
|
|
4381
4696
|
userLanguage: asOptionalTrimmedString(env.NOLO_LANG),
|
|
4382
4697
|
gitStatus: void 0,
|
|
4383
|
-
|
|
4384
|
-
thinkingDisplay: "show",
|
|
4698
|
+
thinkingDisplay: resolveThinkingDisplayMode(env),
|
|
4385
4699
|
contextWindow: resolveAgentContextWindow({ agentKey, agentName }),
|
|
4386
4700
|
estimatedContextTokens: estimateDefaultCliContextTokens({
|
|
4387
4701
|
cwd,
|
|
@@ -4505,28 +4819,53 @@ function handleTuiInput(input, state) {
|
|
|
4505
4819
|
};
|
|
4506
4820
|
}
|
|
4507
4821
|
}
|
|
4508
|
-
case "/
|
|
4509
|
-
|
|
4510
|
-
const sub = parts[0]?.trim();
|
|
4511
|
-
if (!sub) {
|
|
4822
|
+
case "/cd": {
|
|
4823
|
+
if (!argText) {
|
|
4512
4824
|
return {
|
|
4513
4825
|
nextState: state,
|
|
4514
|
-
output: t("
|
|
4826
|
+
output: `${t("cdCurrent", state.cwd)}
|
|
4827
|
+
${t("cdUsage")}`
|
|
4515
4828
|
};
|
|
4516
4829
|
}
|
|
4517
|
-
if (
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
} 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);
|
|
4524
4836
|
return {
|
|
4525
|
-
nextState: state,
|
|
4526
|
-
output: t("
|
|
4837
|
+
nextState: { ...state, cwd: previous, prevCwd: void 0, pendingCwdNotice: switchMessage2 },
|
|
4838
|
+
output: t("cdSwitched", previous),
|
|
4839
|
+
action: { type: "cwd-refresh", switchMessage: switchMessage2 }
|
|
4527
4840
|
};
|
|
4528
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
|
+
};
|
|
4529
4861
|
}
|
|
4862
|
+
case "/density":
|
|
4863
|
+
case "/tools":
|
|
4864
|
+
case "/thinking":
|
|
4865
|
+
return {
|
|
4866
|
+
nextState: state,
|
|
4867
|
+
output: t("displayFixedHint")
|
|
4868
|
+
};
|
|
4530
4869
|
case "/context":
|
|
4531
4870
|
case "/ctx":
|
|
4532
4871
|
return { nextState: state, output: renderContextPanel(state) };
|
|
@@ -4542,45 +4881,6 @@ function handleTuiInput(input, state) {
|
|
|
4542
4881
|
output: t("runtimeSet", argText)
|
|
4543
4882
|
};
|
|
4544
4883
|
}
|
|
4545
|
-
case "/tools": {
|
|
4546
|
-
if (!argText) {
|
|
4547
|
-
return {
|
|
4548
|
-
nextState: state,
|
|
4549
|
-
output: t("toolsCurrent", state.toolDisplay)
|
|
4550
|
-
};
|
|
4551
|
-
}
|
|
4552
|
-
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
4553
|
-
if (!["normal", "pro", "hide", "compact", "verbose", "on", "off"].includes(normalizedArg)) {
|
|
4554
|
-
return {
|
|
4555
|
-
nextState: state,
|
|
4556
|
-
output: t("toolsUsage")
|
|
4557
|
-
};
|
|
4558
|
-
}
|
|
4559
|
-
const nextMode = normalizeToolDisplayMode(normalizedArg, state.toolDisplay);
|
|
4560
|
-
return {
|
|
4561
|
-
nextState: { ...state, toolDisplay: nextMode },
|
|
4562
|
-
output: t("toolsSet", nextMode)
|
|
4563
|
-
};
|
|
4564
|
-
}
|
|
4565
|
-
case "/thinking": {
|
|
4566
|
-
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
4567
|
-
if (!normalizedArg) {
|
|
4568
|
-
return {
|
|
4569
|
-
nextState: state,
|
|
4570
|
-
output: t("thinkingCurrent", state.thinkingDisplay)
|
|
4571
|
-
};
|
|
4572
|
-
}
|
|
4573
|
-
if (normalizedArg !== "show" && normalizedArg !== "hide") {
|
|
4574
|
-
return {
|
|
4575
|
-
nextState: state,
|
|
4576
|
-
output: t("thinkingUsage")
|
|
4577
|
-
};
|
|
4578
|
-
}
|
|
4579
|
-
return {
|
|
4580
|
-
nextState: { ...state, thinkingDisplay: normalizedArg },
|
|
4581
|
-
output: t("thinkingSet", normalizedArg)
|
|
4582
|
-
};
|
|
4583
|
-
}
|
|
4584
4884
|
case "/auto": {
|
|
4585
4885
|
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
4586
4886
|
if (!normalizedArg) {
|
|
@@ -4989,7 +5289,7 @@ async function probeTerminalBackground(args = {}) {
|
|
|
4989
5289
|
if (typeof stdin.setRawMode !== "function") return null;
|
|
4990
5290
|
if (!isTerminal(stdin)) return null;
|
|
4991
5291
|
const wasRaw = Boolean(stdin.isRaw);
|
|
4992
|
-
return await new Promise((
|
|
5292
|
+
return await new Promise((resolve4) => {
|
|
4993
5293
|
let buffer = "";
|
|
4994
5294
|
let settled = false;
|
|
4995
5295
|
let timer;
|
|
@@ -5002,7 +5302,7 @@ async function probeTerminalBackground(args = {}) {
|
|
|
5002
5302
|
if (!wasRaw) stdin.setRawMode?.(false);
|
|
5003
5303
|
} catch {
|
|
5004
5304
|
}
|
|
5005
|
-
|
|
5305
|
+
resolve4(result);
|
|
5006
5306
|
};
|
|
5007
5307
|
const onData = (chunk) => {
|
|
5008
5308
|
buffer += chunk.toString("latin1");
|
|
@@ -5065,9 +5365,46 @@ function detectSystemBrightness(env = process.env, options = {}) {
|
|
|
5065
5365
|
return null;
|
|
5066
5366
|
}
|
|
5067
5367
|
|
|
5068
|
-
// packages/cli/tui/
|
|
5069
|
-
|
|
5070
|
-
|
|
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
|
+
}
|
|
5071
5408
|
|
|
5072
5409
|
// packages/ai/tools/askChoiceState.ts
|
|
5073
5410
|
function normalizeAskChoiceArgs(args) {
|
|
@@ -5846,24 +6183,6 @@ function emitTerminalBell(output) {
|
|
|
5846
6183
|
}
|
|
5847
6184
|
|
|
5848
6185
|
// packages/cli/tui/tuiTurnRunner.ts
|
|
5849
|
-
var AGENTS_MD_MAX_BYTES = 8192;
|
|
5850
|
-
function readAgentsMdLayer(cwd) {
|
|
5851
|
-
for (const name of ["AGENTS.md", "CLAUDE.md"]) {
|
|
5852
|
-
const filePath = join3(cwd, name);
|
|
5853
|
-
if (existsSync3(filePath)) {
|
|
5854
|
-
try {
|
|
5855
|
-
let content = readFileSync3(filePath, "utf8").trim();
|
|
5856
|
-
if (!content) continue;
|
|
5857
|
-
if (Buffer.byteLength(content, "utf8") > AGENTS_MD_MAX_BYTES) {
|
|
5858
|
-
content = Buffer.from(content, "utf8").subarray(0, AGENTS_MD_MAX_BYTES).toString("utf8") + "\n\n<!-- AGENTS.md truncated -->";
|
|
5859
|
-
}
|
|
5860
|
-
return buildAgentsMdLayer(content, name);
|
|
5861
|
-
} catch {
|
|
5862
|
-
}
|
|
5863
|
-
}
|
|
5864
|
-
}
|
|
5865
|
-
return null;
|
|
5866
|
-
}
|
|
5867
6186
|
async function runAgentChat(scriptDir, state, message, env, output, agentRunner = runAgentTurn, options = {}) {
|
|
5868
6187
|
const effectiveAgentKey = state.agentKey;
|
|
5869
6188
|
const effectiveAgentName = state.agentName;
|
|
@@ -5908,12 +6227,16 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5908
6227
|
}
|
|
5909
6228
|
}
|
|
5910
6229
|
const layers = [
|
|
5911
|
-
|
|
6230
|
+
readAgentsMdLayerFromDisk(state.cwd),
|
|
5912
6231
|
// Skill discovery: scan conventional skill dirs for SKILL.md and inject an
|
|
5913
6232
|
// index layer so the model knows what skills exist and can readFile them
|
|
5914
6233
|
// on-demand. Mirrors agentRunCommand.ts and desktopAgentRuntimeTurnService.
|
|
5915
6234
|
buildSkillDiscoveryContextLayer(state.cwd)
|
|
5916
6235
|
];
|
|
6236
|
+
const responseGuidelinesBlock = {
|
|
6237
|
+
content: buildResponseGuidelines(true),
|
|
6238
|
+
cacheScope: "session"
|
|
6239
|
+
};
|
|
5917
6240
|
let memoryPromptBlock = state.cachedMemoryOverlay;
|
|
5918
6241
|
if (memoryPromptBlock === void 0) {
|
|
5919
6242
|
memoryPromptBlock = await resolveCliMemory({
|
|
@@ -5926,15 +6249,19 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5926
6249
|
}
|
|
5927
6250
|
const memoryOverlayLayer = buildMemoryOverlayLayer({ promptBlock: memoryPromptBlock });
|
|
5928
6251
|
const memoryUseGuidanceLayer = buildMemoryUseGuidanceLayer({ promptBlock: memoryPromptBlock });
|
|
6252
|
+
const cwdNoticeBlocks = state.pendingCwdNotice ? [{ content: state.pendingCwdNotice, cacheScope: "turn" }] : [];
|
|
5929
6253
|
const contextBlockScopes = partitionScopedBlocks([
|
|
5930
6254
|
...renderTurnContextBlocksWithScope(layers),
|
|
6255
|
+
responseGuidelinesBlock,
|
|
5931
6256
|
...renderTurnContextBlocksWithScope([memoryUseGuidanceLayer]),
|
|
5932
6257
|
// Attached skill bodies are already self-contained sections built by
|
|
5933
6258
|
// buildSkillContextBlocks; they stay turn-scope because the user can
|
|
5934
6259
|
// attach/detach skills between turns.
|
|
5935
6260
|
...(skillContextBlocks ?? []).map((content) => content.trim()).filter((content) => content.length > 0).map((content) => ({ content, cacheScope: "turn" })),
|
|
5936
|
-
...renderTurnContextBlocksWithScope([memoryOverlayLayer])
|
|
6261
|
+
...renderTurnContextBlocksWithScope([memoryOverlayLayer]),
|
|
6262
|
+
...cwdNoticeBlocks
|
|
5937
6263
|
]);
|
|
6264
|
+
const spawnedRunsMissingParent = [];
|
|
5938
6265
|
const result = await agentRunner({
|
|
5939
6266
|
agentName: effectiveAgentName,
|
|
5940
6267
|
agentKey: effectiveAgentKey,
|
|
@@ -5952,10 +6279,12 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5952
6279
|
scriptDir,
|
|
5953
6280
|
env: {
|
|
5954
6281
|
...env,
|
|
5955
|
-
NOLO_LANG: state.userLanguage
|
|
5956
|
-
|
|
6282
|
+
NOLO_LANG: state.userLanguage
|
|
6283
|
+
},
|
|
6284
|
+
output: {
|
|
6285
|
+
...output,
|
|
6286
|
+
tuiTrees: output.tuiTrees === true && typeof output.writeToolBlock === "function"
|
|
5957
6287
|
},
|
|
5958
|
-
output,
|
|
5959
6288
|
showThinking: state.thinkingDisplay === "show",
|
|
5960
6289
|
...options.imageUrls && options.imageUrls.length > 0 ? { imageUrls: options.imageUrls } : {},
|
|
5961
6290
|
...options.actionGateHandler ? { actionGateHandler: options.actionGateHandler } : {},
|
|
@@ -5979,15 +6308,28 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5979
6308
|
// run-completion watcher can attribute terminal-state wakes to this
|
|
5980
6309
|
// conversation.
|
|
5981
6310
|
...state.dialogId ? { parentDialogId: state.dialogId } : {},
|
|
6311
|
+
// 首轮无 dialogId 时的兜底:收集失归属的 spawn,turn 结束回填。
|
|
6312
|
+
onBackgroundRunSpawned: (runId) => {
|
|
6313
|
+
spawnedRunsMissingParent.push(runId);
|
|
6314
|
+
},
|
|
5982
6315
|
...options.activityReporter ? { activityReporter: options.activityReporter } : {}
|
|
5983
6316
|
}),
|
|
5984
6317
|
...options.activityReporter ? { activityReporter: options.activityReporter } : {},
|
|
5985
6318
|
// 转发 dock 订阅:runAgentTurn 的输出层靠它判断「有面板」从而抑制
|
|
5986
6319
|
// transcript 的进展卡片;dock 本身也靠它接收模型轮询带回来的快照。
|
|
5987
6320
|
...options.onAgentRunStatus ? { onAgentRunStatus: options.onAgentRunStatus } : {},
|
|
6321
|
+
...options.drainInjections ? { drainInjections: options.drainInjections } : {},
|
|
5988
6322
|
...skillAllowedTools !== void 0 ? { allowedToolNames: skillAllowedTools } : {},
|
|
5989
6323
|
...contextBlockScopes.length > 0 ? { contextBlockScopes } : {}
|
|
5990
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
|
+
}
|
|
5991
6333
|
return {
|
|
5992
6334
|
...result,
|
|
5993
6335
|
contextWindow: resolveAgentContextWindow({
|
|
@@ -5997,12 +6339,47 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
5997
6339
|
cachedMemoryOverlay: memoryPromptBlock
|
|
5998
6340
|
};
|
|
5999
6341
|
}
|
|
6000
|
-
|
|
6342
|
+
var ESC = "\x1B";
|
|
6343
|
+
var CTRL_C = "";
|
|
6344
|
+
function isApprovedConfirmationInput(answer) {
|
|
6345
|
+
const normalized = answer.trim().toLowerCase();
|
|
6346
|
+
return normalized === "" || normalized === "y" || normalized === "yes" || normalized === "\u786E\u8BA4";
|
|
6347
|
+
}
|
|
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) {
|
|
6001
6373
|
const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
|
|
6374
|
+
const isConfirmation = gate.kind === "confirm";
|
|
6002
6375
|
const displayCommand = commandPayload?.displayCommand ?? commandPayload?.command.join(" ") ?? gate.title;
|
|
6003
6376
|
const isInteractiveHandoff = gate.kind === "handoff" && gate.title === "This command requires an interactive terminal.";
|
|
6004
6377
|
const title = isInteractiveHandoff ? t("actionGateInteractiveTitle") : gate.title;
|
|
6005
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;
|
|
6006
6383
|
output.write(`
|
|
6007
6384
|
[nolo] ${t("actionGateNeeded")}
|
|
6008
6385
|
`);
|
|
@@ -6012,37 +6389,34 @@ function waitForActionGate(rl, input, output, gate, spawnRunner) {
|
|
|
6012
6389
|
`);
|
|
6013
6390
|
output.write(` ${displayCommand}
|
|
6014
6391
|
`);
|
|
6015
|
-
output.write(`[nolo] ${t("actionGateEnterHint")}
|
|
6392
|
+
output.write(`[nolo] ${isConfirmation ? t("actionGateConfirmHint") : t("actionGateEnterHint")}
|
|
6016
6393
|
`);
|
|
6017
|
-
|
|
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) => {
|
|
6018
6400
|
let settled = false;
|
|
6019
6401
|
const finish = (result) => {
|
|
6020
6402
|
if (settled) return;
|
|
6021
6403
|
settled = true;
|
|
6022
6404
|
rl.off("close", onClose);
|
|
6023
6405
|
rl.off("SIGINT", onSigint);
|
|
6024
|
-
|
|
6406
|
+
resolve4(result);
|
|
6025
6407
|
};
|
|
6026
|
-
const cancelResult = (reason) => (
|
|
6027
|
-
|
|
6028
|
-
metadata: {
|
|
6029
|
-
exitCode: 130,
|
|
6030
|
-
actionGateResult: { gateId: gate.id, status: "cancelled", output: reason }
|
|
6031
|
-
}
|
|
6032
|
-
});
|
|
6033
|
-
const failResult = (message) => ({
|
|
6034
|
-
content: `action gate failed: ${gate.title}`,
|
|
6035
|
-
metadata: {
|
|
6036
|
-
exitCode: 1,
|
|
6037
|
-
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
6038
|
-
}
|
|
6039
|
-
});
|
|
6408
|
+
const cancelResult = (reason) => buildGateCancelledResult(gate, reason);
|
|
6409
|
+
const failResult = (message) => buildGateFailedResult(gate, message);
|
|
6040
6410
|
const onClose = () => finish(cancelResult("readline closed"));
|
|
6041
6411
|
const onSigint = () => finish(cancelResult("interrupted"));
|
|
6042
6412
|
rl.once("close", onClose);
|
|
6043
6413
|
rl.once("SIGINT", onSigint);
|
|
6044
|
-
rl.question("", async () => {
|
|
6414
|
+
rl.question("", async (answer) => {
|
|
6045
6415
|
if (settled) return;
|
|
6416
|
+
if (isConfirmation) {
|
|
6417
|
+
finish(isApprovedConfirmationInput(answer) ? buildGateConfirmedResult(gate) : cancelResult("confirmation declined"));
|
|
6418
|
+
return;
|
|
6419
|
+
}
|
|
6046
6420
|
if (!commandPayload) {
|
|
6047
6421
|
finish(failResult("unsupported gate payload"));
|
|
6048
6422
|
return;
|
|
@@ -6088,47 +6462,23 @@ function isInteractiveInput(input) {
|
|
|
6088
6462
|
return Boolean(candidate.isTTY) && typeof candidate.setRawMode === "function";
|
|
6089
6463
|
}
|
|
6090
6464
|
function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
6091
|
-
const
|
|
6092
|
-
const
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
const body = isInteractiveHandoff ? t("actionGateInteractiveBody") : gate.body;
|
|
6096
|
-
output.write(`
|
|
6097
|
-
[nolo] ${t("actionGateNeeded")}
|
|
6098
|
-
`);
|
|
6099
|
-
output.write(`[nolo] ${title}
|
|
6100
|
-
`);
|
|
6101
|
-
if (body) output.write(`[nolo] ${body}
|
|
6102
|
-
`);
|
|
6103
|
-
output.write(` ${displayCommand}
|
|
6104
|
-
`);
|
|
6105
|
-
output.write(`[nolo] ${t("actionGateEnterHint")}
|
|
6106
|
-
`);
|
|
6107
|
-
return new Promise((resolve2) => {
|
|
6465
|
+
const meta = deriveGateMeta(gate);
|
|
6466
|
+
const { commandPayload, isConfirmation, displayCommand } = meta;
|
|
6467
|
+
writeGatePrompt(output, meta);
|
|
6468
|
+
return new Promise((resolve4) => {
|
|
6108
6469
|
const rawInput = input;
|
|
6109
6470
|
let settled = false;
|
|
6110
6471
|
let commandRunning = false;
|
|
6472
|
+
let confirmationLine = "";
|
|
6111
6473
|
const finish = (result) => {
|
|
6112
6474
|
if (settled) return;
|
|
6113
6475
|
settled = true;
|
|
6114
6476
|
hooks?.registerToken?.(null);
|
|
6115
6477
|
input.off("data", onData);
|
|
6116
|
-
|
|
6478
|
+
resolve4(result);
|
|
6117
6479
|
};
|
|
6118
|
-
const cancel = (reason) => finish(
|
|
6119
|
-
|
|
6120
|
-
metadata: {
|
|
6121
|
-
exitCode: 130,
|
|
6122
|
-
actionGateResult: { gateId: gate.id, status: "cancelled", output: reason }
|
|
6123
|
-
}
|
|
6124
|
-
});
|
|
6125
|
-
const fail = (message) => finish({
|
|
6126
|
-
content: `action gate failed: ${gate.title}`,
|
|
6127
|
-
metadata: {
|
|
6128
|
-
exitCode: 1,
|
|
6129
|
-
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
6130
|
-
}
|
|
6131
|
-
});
|
|
6480
|
+
const cancel = (reason) => finish(buildGateCancelledResult(gate, reason));
|
|
6481
|
+
const fail = (message) => finish(buildGateFailedResult(gate, message));
|
|
6132
6482
|
const runCommand = async () => {
|
|
6133
6483
|
if (settled || commandRunning) return;
|
|
6134
6484
|
commandRunning = true;
|
|
@@ -6171,10 +6521,24 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
6171
6521
|
};
|
|
6172
6522
|
const handleToken = (text) => {
|
|
6173
6523
|
if (settled || commandRunning) return;
|
|
6174
|
-
if (text.includes(
|
|
6524
|
+
if (text.includes(CTRL_C) || isConfirmation && text === ESC) {
|
|
6175
6525
|
cancel("interrupted");
|
|
6176
6526
|
return;
|
|
6177
6527
|
}
|
|
6528
|
+
if (isConfirmation) {
|
|
6529
|
+
const newline = text.search(/[\r\n]/);
|
|
6530
|
+
confirmationLine += newline >= 0 ? text.slice(0, newline) : text;
|
|
6531
|
+
if (newline >= 0) {
|
|
6532
|
+
const normalized = confirmationLine.trim().toLowerCase();
|
|
6533
|
+
confirmationLine = "";
|
|
6534
|
+
if (!isApprovedConfirmationInput(normalized)) {
|
|
6535
|
+
cancel("confirmation declined");
|
|
6536
|
+
return;
|
|
6537
|
+
}
|
|
6538
|
+
finish(buildGateConfirmedResult(gate));
|
|
6539
|
+
}
|
|
6540
|
+
return;
|
|
6541
|
+
}
|
|
6178
6542
|
if (text.includes("\r") || text.includes("\n")) {
|
|
6179
6543
|
void runCommand();
|
|
6180
6544
|
}
|
|
@@ -6190,6 +6554,40 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
6190
6554
|
}
|
|
6191
6555
|
});
|
|
6192
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
|
+
}
|
|
6193
6591
|
async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, confirmDestructiveAction) {
|
|
6194
6592
|
const scheduleTitlePatchSync = (runResult) => {
|
|
6195
6593
|
if (!runResult.titlePatchPromise || !runResult.dialogId) return;
|
|
@@ -6261,7 +6659,6 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6261
6659
|
ctx.scheduleRender();
|
|
6262
6660
|
}) : ctx.output;
|
|
6263
6661
|
const requestUserChoice = isInteractiveInput(ctx.input) && ctx.dialogHost ? async (choiceReq) => {
|
|
6264
|
-
ctx.modalOwnsKeyboard = true;
|
|
6265
6662
|
try {
|
|
6266
6663
|
return await ctx.dialogHost.run(
|
|
6267
6664
|
(anchor) => runAskChoiceDialog({
|
|
@@ -6273,12 +6670,11 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6273
6670
|
);
|
|
6274
6671
|
} catch {
|
|
6275
6672
|
return { kind: "cancelled" };
|
|
6276
|
-
} finally {
|
|
6277
|
-
ctx.composerDecoderDrain?.();
|
|
6278
|
-
ctx.modalOwnsKeyboard = false;
|
|
6279
6673
|
}
|
|
6280
6674
|
} : void 0;
|
|
6281
6675
|
ctx.runRegistryPoller.beginHold();
|
|
6676
|
+
const injectionInbox = createTurnInjectionInbox();
|
|
6677
|
+
ctx.turnInjectionInbox = injectionInbox;
|
|
6282
6678
|
try {
|
|
6283
6679
|
ctx.activeTurnAbort = new AbortController();
|
|
6284
6680
|
ctx.activeTurnEpoch = myEpoch;
|
|
@@ -6295,6 +6691,7 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6295
6691
|
...confirmDestructiveAction ? { confirmDestructiveAction } : {},
|
|
6296
6692
|
...requestUserChoice ? { requestUserChoice } : {},
|
|
6297
6693
|
abortSignal: ctx.activeTurnAbort.signal,
|
|
6694
|
+
drainInjections: () => injectionInbox.drain(),
|
|
6298
6695
|
pastedTextStore: ctx.pasteStore,
|
|
6299
6696
|
activityReporter: ctx.activityReporter,
|
|
6300
6697
|
onAgentRunStatus: (snapshot) => {
|
|
@@ -6320,7 +6717,9 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6320
6717
|
...runResult.title ? { dialogTitle: runResult.title } : {}
|
|
6321
6718
|
} : {},
|
|
6322
6719
|
...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {},
|
|
6323
|
-
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {}
|
|
6720
|
+
...runResult.cachedMemoryOverlay !== void 0 ? { cachedMemoryOverlay: runResult.cachedMemoryOverlay } : {},
|
|
6721
|
+
// 本轮已发起 agent 调用(消息已注入),消费切换通知。
|
|
6722
|
+
pendingCwdNotice: void 0
|
|
6324
6723
|
};
|
|
6325
6724
|
if (runResult.dialogId && nextDialogKey) {
|
|
6326
6725
|
ctx.refreshDialogTotalCredits(runResult.dialogId, nextDialogKey);
|
|
@@ -6368,7 +6767,11 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6368
6767
|
// estimatedContextTokens:下一轮若 provider 不返回 usage,context
|
|
6369
6768
|
// chip 仍显示真实累计占用而不是回退到启动时的静态估算。
|
|
6370
6769
|
...runResult.turnTokens && runResult.turnTokens.input > 0 ? { estimatedContextTokens: runResult.turnTokens.input } : {},
|
|
6371
|
-
...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
|
|
6372
6775
|
};
|
|
6373
6776
|
if (runResult.dialogId && nextDialogKey) {
|
|
6374
6777
|
ctx.refreshDialogTotalCredits(runResult.dialogId, nextDialogKey);
|
|
@@ -6391,6 +6794,21 @@ async function runOneAgentTurn(ctx, inputMsg, imageUrls, actionGateHandler, conf
|
|
|
6391
6794
|
ctx.runRegistryPoller.endHold();
|
|
6392
6795
|
ctx.activityIndicator.stop();
|
|
6393
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
|
+
}
|
|
6394
6812
|
}
|
|
6395
6813
|
}
|
|
6396
6814
|
function ensureChatQueueBinding(ctx, actionGateHandler, confirmDestructiveAction) {
|
|
@@ -6978,7 +7396,7 @@ function createFixedInput(output, config) {
|
|
|
6978
7396
|
const renderInputArea = (buffer, cursorPos) => {
|
|
6979
7397
|
const colorEnabled = resolveCliColorEnabled();
|
|
6980
7398
|
const cols = Math.max(1, getColumns());
|
|
6981
|
-
const completions = completeSlashCommand(buffer);
|
|
7399
|
+
const completions = completeSlashCommand(buffer, config.getCwd?.());
|
|
6982
7400
|
const sections = [];
|
|
6983
7401
|
if (completions.length > 0) {
|
|
6984
7402
|
sections.push(fitAnsiLine(dimCliText(completions.join(" "), colorEnabled), cols));
|
|
@@ -6999,6 +7417,10 @@ function createFixedInput(output, config) {
|
|
|
6999
7417
|
for (const line of queueLines) {
|
|
7000
7418
|
sections.push(fitAnsiLine(line.replace(/\r?\n/g, " "), cols));
|
|
7001
7419
|
}
|
|
7420
|
+
const attachmentLine = config.getAttachmentLine?.() ?? null;
|
|
7421
|
+
if (attachmentLine) {
|
|
7422
|
+
sections.push(fitAnsiLine(attachmentLine.replace(/\r?\n/g, " "), cols));
|
|
7423
|
+
}
|
|
7002
7424
|
const promptRaw = t("promptLabel");
|
|
7003
7425
|
const promptWidth = displayWidth(promptRaw);
|
|
7004
7426
|
const prompt = colorEnabled ? `${themeColorSequence("accent")}${promptRaw}\x1B[39m` : promptRaw;
|
|
@@ -7048,7 +7470,7 @@ function createFixedInput(output, config) {
|
|
|
7048
7470
|
}
|
|
7049
7471
|
const text = sections.join("\n");
|
|
7050
7472
|
const lines = sections.length;
|
|
7051
|
-
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);
|
|
7052
7474
|
return { text, lines, cursorCol, cursorRow: headerRows + cursorRow };
|
|
7053
7475
|
};
|
|
7054
7476
|
const repaintAt = (buffer, cursorPos, force = false) => {
|
|
@@ -7458,6 +7880,7 @@ async function runSubmittedSlashLine(line, host, actionGateHandler, confirmDestr
|
|
|
7458
7880
|
turnCtx,
|
|
7459
7881
|
emitCommandOutput,
|
|
7460
7882
|
renderHistoryToOutput,
|
|
7883
|
+
scheduleRender,
|
|
7461
7884
|
refreshDialogTotalCredits,
|
|
7462
7885
|
persistExplicitAgentSwitch,
|
|
7463
7886
|
persistAgentSelection: persistAgentSelection2,
|
|
@@ -7631,6 +8054,18 @@ async function runSubmittedSlashLine(line, host, actionGateHandler, confirmDestr
|
|
|
7631
8054
|
emitCommandOutput(t("themeRefreshFailed"));
|
|
7632
8055
|
}
|
|
7633
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
|
+
}
|
|
7634
8069
|
if (result.action?.type === "pick-agent") {
|
|
7635
8070
|
try {
|
|
7636
8071
|
const pickResult = await dialogHost.run(
|
|
@@ -8105,7 +8540,14 @@ async function runTuiWorkspace(options) {
|
|
|
8105
8540
|
getInputLines: () => fixedInput.getInputLines(),
|
|
8106
8541
|
isPaused: () => fixedInput.isPaused()
|
|
8107
8542
|
},
|
|
8108
|
-
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
|
+
}
|
|
8109
8551
|
});
|
|
8110
8552
|
let sessionEnded = false;
|
|
8111
8553
|
const selectionState = createSelectionState();
|
|
@@ -8134,7 +8576,7 @@ async function runTuiWorkspace(options) {
|
|
|
8134
8576
|
const repaintBanner = () => {
|
|
8135
8577
|
if (!output.isTTY) return;
|
|
8136
8578
|
if (fixedInput.isPaused()) return;
|
|
8137
|
-
if (
|
|
8579
|
+
if (dialogHost.isKeyboardClaimed()) return;
|
|
8138
8580
|
const currentColumns = output.columns ?? 80;
|
|
8139
8581
|
const welcome = renderWelcome(state, 0, 0, currentColumns);
|
|
8140
8582
|
const lines = welcome.split("\n");
|
|
@@ -8183,7 +8625,6 @@ async function runTuiWorkspace(options) {
|
|
|
8183
8625
|
selectionState.anchor = null;
|
|
8184
8626
|
selectionState.head = null;
|
|
8185
8627
|
};
|
|
8186
|
-
let modalOwnsKeyboard = false;
|
|
8187
8628
|
let rawActionGateTokenHandler = null;
|
|
8188
8629
|
const refreshDialogTotalCredits = (dialogId, dialogKey) => {
|
|
8189
8630
|
const env = options.env ?? process.env;
|
|
@@ -8219,6 +8660,7 @@ async function runTuiWorkspace(options) {
|
|
|
8219
8660
|
if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
|
|
8220
8661
|
};
|
|
8221
8662
|
let chatQueueBinding = null;
|
|
8663
|
+
let turnInjectionInbox = null;
|
|
8222
8664
|
const turnCtx = {
|
|
8223
8665
|
get state() {
|
|
8224
8666
|
return state;
|
|
@@ -8256,24 +8698,18 @@ async function runTuiWorkspace(options) {
|
|
|
8256
8698
|
set activeTurnEpoch(v) {
|
|
8257
8699
|
activeTurnEpoch = v;
|
|
8258
8700
|
},
|
|
8259
|
-
get modalOwnsKeyboard() {
|
|
8260
|
-
return modalOwnsKeyboard;
|
|
8261
|
-
},
|
|
8262
|
-
set modalOwnsKeyboard(v) {
|
|
8263
|
-
modalOwnsKeyboard = v;
|
|
8264
|
-
},
|
|
8265
|
-
get composerDecoderDrain() {
|
|
8266
|
-
return composerDecoderDrain;
|
|
8267
|
-
},
|
|
8268
|
-
set composerDecoderDrain(v) {
|
|
8269
|
-
composerDecoderDrain = v;
|
|
8270
|
-
},
|
|
8271
8701
|
get chatQueueBinding() {
|
|
8272
8702
|
return chatQueueBinding;
|
|
8273
8703
|
},
|
|
8274
8704
|
set chatQueueBinding(v) {
|
|
8275
8705
|
chatQueueBinding = v;
|
|
8276
8706
|
},
|
|
8707
|
+
get turnInjectionInbox() {
|
|
8708
|
+
return turnInjectionInbox;
|
|
8709
|
+
},
|
|
8710
|
+
set turnInjectionInbox(v) {
|
|
8711
|
+
turnInjectionInbox = v;
|
|
8712
|
+
},
|
|
8277
8713
|
get sessionEnded() {
|
|
8278
8714
|
return sessionEnded;
|
|
8279
8715
|
},
|
|
@@ -8339,6 +8775,7 @@ async function runTuiWorkspace(options) {
|
|
|
8339
8775
|
turnCtx,
|
|
8340
8776
|
emitCommandOutput,
|
|
8341
8777
|
renderHistoryToOutput,
|
|
8778
|
+
scheduleRender,
|
|
8342
8779
|
refreshDialogTotalCredits,
|
|
8343
8780
|
persistExplicitAgentSwitch,
|
|
8344
8781
|
persistAgentSelection,
|
|
@@ -8371,9 +8808,16 @@ async function runTuiWorkspace(options) {
|
|
|
8371
8808
|
return dimCliText(` \u2937 ${i + 1}. ${oneLine}`, colorEnabled);
|
|
8372
8809
|
});
|
|
8373
8810
|
},
|
|
8811
|
+
getAttachmentLine: () => {
|
|
8812
|
+
const line = formatComposerAttachmentLine(state.attachedImages);
|
|
8813
|
+
return line ? dimCliText(line, resolveCliColorEnabled()) : null;
|
|
8814
|
+
},
|
|
8374
8815
|
onInputLinesChange: () => {
|
|
8375
8816
|
renderHistoryToOutput();
|
|
8376
|
-
}
|
|
8817
|
+
},
|
|
8818
|
+
// /cd 路径补全候选行渲染需要当前 cwd(读 state 而非入参,保证
|
|
8819
|
+
// /cd 切换后立即以新 cwd 渲染,composer 不必重建)。
|
|
8820
|
+
getCwd: () => state.cwd
|
|
8377
8821
|
});
|
|
8378
8822
|
fixedInput = {
|
|
8379
8823
|
...baseFixedInput,
|
|
@@ -8447,39 +8891,33 @@ async function runTuiWorkspace(options) {
|
|
|
8447
8891
|
input.setRawMode?.(false);
|
|
8448
8892
|
};
|
|
8449
8893
|
const buildInteractiveTurnHandlers = () => {
|
|
8450
|
-
const releaseKeyboardToComposer = () => {
|
|
8451
|
-
onData.destroy();
|
|
8452
|
-
modalOwnsKeyboard = false;
|
|
8453
|
-
};
|
|
8454
8894
|
const actionGateHandler = async (gate) => {
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
return await waitForRawActionGate(input, output, gate, spawnRunner, {
|
|
8458
|
-
beforeSubprocess: () => fixedInput.pause(),
|
|
8459
|
-
afterSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
8460
|
-
registerToken: (handler) => {
|
|
8461
|
-
rawActionGateTokenHandler = handler;
|
|
8462
|
-
}
|
|
8463
|
-
});
|
|
8464
|
-
} finally {
|
|
8465
|
-
releaseKeyboardToComposer();
|
|
8895
|
+
if (state.autoConfirm && isAutoConfirmableFileWriteGate(gate)) {
|
|
8896
|
+
return buildGateConfirmedResult(gate);
|
|
8466
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
|
+
});
|
|
8467
8910
|
};
|
|
8468
8911
|
const confirmDestructiveAction = async (request) => {
|
|
8469
8912
|
if (state.autoConfirm) return true;
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
})
|
|
8479
|
-
);
|
|
8480
|
-
} finally {
|
|
8481
|
-
releaseKeyboardToComposer();
|
|
8482
|
-
}
|
|
8913
|
+
return await dialogHost.run(
|
|
8914
|
+
(anchor) => runConfirmDialog({
|
|
8915
|
+
request,
|
|
8916
|
+
input,
|
|
8917
|
+
output,
|
|
8918
|
+
...anchor
|
|
8919
|
+
})
|
|
8920
|
+
);
|
|
8483
8921
|
};
|
|
8484
8922
|
return { actionGateHandler, confirmDestructiveAction };
|
|
8485
8923
|
};
|
|
@@ -8515,8 +8953,26 @@ ${err.message}` : ""}`
|
|
|
8515
8953
|
runWakeHandler = (event) => {
|
|
8516
8954
|
if (done) return;
|
|
8517
8955
|
if (busy || fixedInput.isPaused()) {
|
|
8518
|
-
const
|
|
8519
|
-
|
|
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
|
+
}
|
|
8520
8976
|
if (fixedInput.active && !fixedInput.isPaused()) {
|
|
8521
8977
|
fixedInput.repaint(buffer, cursorPos);
|
|
8522
8978
|
}
|
|
@@ -8657,6 +9113,19 @@ ${err.message}` : ""}`
|
|
|
8657
9113
|
output.write(`${refreshMsg}
|
|
8658
9114
|
`);
|
|
8659
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();
|
|
8660
9129
|
} else if (res.action) {
|
|
8661
9130
|
output.write(
|
|
8662
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"
|
|
@@ -8681,7 +9150,7 @@ ${hint}` : hint;
|
|
|
8681
9150
|
};
|
|
8682
9151
|
const handleInputToken = async (sequence) => {
|
|
8683
9152
|
if (done) return;
|
|
8684
|
-
if (
|
|
9153
|
+
if (dialogHost.isKeyboardClaimed()) {
|
|
8685
9154
|
rawActionGateTokenHandler?.(sequence);
|
|
8686
9155
|
return;
|
|
8687
9156
|
}
|
|
@@ -8865,8 +9334,20 @@ ${merged}` : merged;
|
|
|
8865
9334
|
if (fixedInput.active) fixedInput.repaint(buffer, cursorPos);
|
|
8866
9335
|
return;
|
|
8867
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
|
+
}
|
|
8868
9348
|
const result = applyTuiInputKey(buffer, sequence, {}, cursorPos, {
|
|
8869
|
-
pasteStore
|
|
9349
|
+
pasteStore,
|
|
9350
|
+
cwd: state.cwd
|
|
8870
9351
|
});
|
|
8871
9352
|
if (result.redraw) {
|
|
8872
9353
|
resetHistoryFrameDiffCache(output);
|
|
@@ -8889,7 +9370,7 @@ ${merged}` : merged;
|
|
|
8889
9370
|
if (busyLock) {
|
|
8890
9371
|
const trimmedText = submittedText.trim();
|
|
8891
9372
|
const busySlashCommand = trimmedText.split(/\s+/)[0]?.toLowerCase();
|
|
8892
|
-
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";
|
|
8893
9374
|
if (isBusyLocalSlash) {
|
|
8894
9375
|
await handleBusyLocalSlash(submittedText, busySlashCommand);
|
|
8895
9376
|
return;
|
|
@@ -8959,9 +9440,9 @@ ${merged}` : merged;
|
|
|
8959
9440
|
input.on("data", onData);
|
|
8960
9441
|
fixedInput.repaint(buffer, cursorPos);
|
|
8961
9442
|
refreshGitStatus();
|
|
8962
|
-
await new Promise((
|
|
8963
|
-
resolveDone =
|
|
8964
|
-
if (done)
|
|
9443
|
+
await new Promise((resolve4) => {
|
|
9444
|
+
resolveDone = resolve4;
|
|
9445
|
+
if (done) resolve4();
|
|
8965
9446
|
});
|
|
8966
9447
|
} finally {
|
|
8967
9448
|
finish();
|
|
@@ -8975,7 +9456,11 @@ ${merged}` : merged;
|
|
|
8975
9456
|
for await (const line of rl) {
|
|
8976
9457
|
const shouldExit = await runSubmittedLine(
|
|
8977
9458
|
line,
|
|
8978
|
-
(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
|
+
),
|
|
8979
9464
|
async (request) => {
|
|
8980
9465
|
if (state.autoConfirm) return true;
|
|
8981
9466
|
rl.pause();
|
|
@@ -9014,12 +9499,16 @@ ${renderStatusLine(state)}
|
|
|
9014
9499
|
}
|
|
9015
9500
|
async function startTuiWorkspace(options) {
|
|
9016
9501
|
const themeOwner = ++latestWorkspaceThemeOwner;
|
|
9502
|
+
void sweepStaleClipboardFiles(getDefaultClipboardTempDir()).catch(() => {
|
|
9503
|
+
});
|
|
9017
9504
|
try {
|
|
9018
9505
|
return await runTuiWorkspace(options);
|
|
9019
9506
|
} finally {
|
|
9020
9507
|
if (themeOwner === latestWorkspaceThemeOwner) {
|
|
9021
9508
|
resetWorkspaceThemeState();
|
|
9022
9509
|
}
|
|
9510
|
+
void sweepStaleClipboardFiles(getDefaultClipboardTempDir()).catch(() => {
|
|
9511
|
+
});
|
|
9023
9512
|
}
|
|
9024
9513
|
}
|
|
9025
9514
|
export {
|