nolo-cli 0.11.0 → 0.12.0-alpha.1
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-ZEDPX6OF.js → _executeModel-MWAY74HA.js} +51 -50
- package/{action-AA4IJ5K2.js → action-RAXNQQKC.js} +8 -9
- package/{addContentAction-QYVO4SYP.js → addContentAction-ZHI7TVV3.js} +7 -9
- package/{addDialogAgentAction-WVVKT5WQ.js → addDialogAgentAction-JWXPKXNC.js} +9 -10
- package/{agentDeleteCommand-RDPGYIWF.js → agentDeleteCommand-LXR5A5FV.js} +38 -28
- package/{agentEmailCommands-2HJJKS5F.js → agentEmailCommands-DXRAP7BB.js} +64 -62
- package/{agentListCommands-HFEVV3ZW.js → agentListCommands-ZFMS5ZLY.js} +127 -31
- package/{agentMachineCommands-25ZOENJU.js → agentMachineCommands-ZJLYVV52.js} +37 -26
- package/{agentPullCommand-GOL2S4W2.js → agentPullCommand-KRBRIFIY.js} +7 -7
- package/{agentRecordCommands-GTCOAM3L.js → agentRecordCommands-DFS626TB.js} +56 -54
- package/{agentRunCommand-YBS3JDLD.js → agentRunCommand-GWBIE2TS.js} +59 -59
- package/{agentRunControl-K4VKNEHF.js → agentRunControl-IX4F5W2C.js} +3 -3
- package/{agentRuntimeLocal-UQBMQI2M.js → agentRuntimeLocal-YNZSHMZC.js} +30 -15
- package/{agentSlice-6EKOBCCS.js → agentSlice-T2PXOEPQ.js} +8 -9
- package/{authCommand-O2OWACN4.js → authCommand-DMW336GT.js} +15 -15
- package/{authCommands-H7365TZP.js → authCommands-GH5T6RYV.js} +6 -6
- package/{chunk-7D3JY6C2.js → chunk-3HHTVM6G.js} +64 -5
- package/{chunk-AFON4QUU.js → chunk-3QKO4EHV.js} +3 -3
- package/{chunk-4SOKXIW4.js → chunk-43UD5ZP7.js} +8 -11
- package/{chunk-S3GS2PRL.js → chunk-4BTHUYMY.js} +597 -68
- package/{chunk-SV5MWASH.js → chunk-4EH7AR52.js} +12 -12
- package/{chunk-FXXSGWAJ.js → chunk-4GBNEA5B.js} +1 -1
- package/{chunk-PXZAAB4L.js → chunk-4LG74DRG.js} +4 -4
- package/{chunk-2FTTDCD4.js → chunk-4ON5AV72.js} +2 -1
- package/{chunk-IWX4UW2E.js → chunk-524BDL33.js} +89 -8
- package/{chunk-X2S7JTIG.js → chunk-5ITRDSHY.js} +1240 -136
- package/{chunk-ISNCLGUZ.js → chunk-5NBHQD4D.js} +4 -3
- package/{chunk-GBDSZATH.js → chunk-6LMFFG3K.js} +3 -3
- package/{chunk-OUI3ZHYD.js → chunk-6OVCRC72.js} +1 -1
- package/{chunk-CKOJQDKR.js → chunk-7JJCGV7N.js} +146 -3
- package/{chunk-MQI77IRB.js → chunk-7MYHLZ3F.js} +2 -2
- package/{chunk-5MOUAAMK.js → chunk-AM53Q2SD.js} +194 -2564
- package/chunk-BYXBJQAS.js +0 -0
- package/{chunk-LAX2JSTX.js → chunk-DE5BA4O6.js} +20 -2
- package/{chunk-BX6U3ETE.js → chunk-DRMGJFGQ.js} +293 -89
- package/{chunk-KJR5KAUQ.js → chunk-EBH7G34M.js} +20 -7
- package/{chunk-E4HNJSHC.js → chunk-G3B356GF.js} +16 -18
- package/{chunk-KQQVGRA3.js → chunk-GDBCUWQ3.js} +35 -29
- package/{chunk-Q3UKJVU4.js → chunk-GPZM7QH6.js} +10 -10
- package/chunk-IKXL2HZ3.js +70 -0
- package/{chunk-QNMFBBZK.js → chunk-IVAOVLM7.js} +1 -1
- package/{chunk-EVZKZF32.js → chunk-JUN3HFMN.js} +182 -75
- package/{chunk-NEM67FX7.js → chunk-JZDIW766.js} +1 -1
- package/{chunk-TACHTH5D.js → chunk-LHSJMY5V.js} +18 -18
- package/{chunk-XYZA7S7V.js → chunk-MEVCDATU.js} +6 -6
- package/{chunk-YOCHZD7D.js → chunk-NCGFB7NN.js} +5 -3
- package/{chunk-O26GI2JP.js → chunk-NITP2JDG.js} +39 -8
- package/{chunk-YPRZSPF3.js → chunk-OCDEWRE2.js} +1 -1
- package/{chunk-PNEW2Z3T.js → chunk-OHEKYYJF.js} +7 -7
- package/chunk-OOIN7HSO.js +146 -0
- package/{chunk-DWGAEFJL.js → chunk-OPKKB25T.js} +1 -1
- package/{chunk-AEZAORLG.js → chunk-QCA3EPYK.js} +5 -5
- package/{chunk-C4FTUXVF.js → chunk-QLUFR47U.js} +11 -1
- package/{chunk-C2MDQQ4O.js → chunk-RNQ5BLR2.js} +1 -1
- package/{chunk-L53FGHA4.js → chunk-RSEUHW6T.js} +1 -1
- package/{chunk-2W2VYVI5.js → chunk-RZ735TLX.js} +527 -176
- package/chunk-S3UTETIC.js +4885 -0
- package/chunk-S73OEOHH.js +2286 -0
- package/{chunk-YTBMA7NO.js → chunk-TSKWE74T.js} +58 -8
- package/{chunk-5OIFWVX7.js → chunk-UG3WOFU6.js} +1 -1
- package/{chunk-4ZDM73SD.js → chunk-V2J635L5.js} +1 -1
- package/{chunk-IPYUUY4E.js → chunk-WPHL6ALY.js} +1 -1
- package/{chunk-3NSIQZZ6.js → chunk-WTYKCU4W.js} +9 -9
- package/{chunk-LP65VRCI.js → chunk-WWU275LU.js} +6 -6
- package/{chunk-XFOLQLDN.js → chunk-XHQWJUW4.js} +2 -2
- package/{chunk-D6OQHXVG.js → chunk-YDCZVUFP.js} +7 -7
- package/{chunk-PXQN7IBQ.js → chunk-YTQLJYLB.js} +2 -2
- package/{chunk-ZEYDOXHF.js → chunk-ZPFRLGIZ.js} +1467 -869
- package/{chunk-ZPRK73XY.js → chunk-ZR4VHQ5D.js} +14 -13
- package/cliEnvHelpers-VYC2OPTB.js +30 -0
- package/{createAgentAutomationAction-LTI5QU35.js → createAgentAutomationAction-G32GKDGV.js} +25 -26
- package/{createDialogAction-OJJ7L3L3.js → createDialogAction-TISANRZK.js} +26 -27
- package/{createPageAction-5MXWVRGY.js → createPageAction-O7KOYNV4.js} +26 -27
- package/{dbSlice-RQFQQVHT.js → dbSlice-WDP2ZZHK.js} +6 -7
- package/{deleteFile-7XP5BGC7.js → deleteFile-M7UNIUOO.js} +4 -4
- package/{dialogCommands-JTJ3RPPW.js → dialogCommands-6JPB3YQY.js} +33 -23
- package/{dialogSlice-OWROKURJ.js → dialogSlice-PRHHYSP5.js} +26 -27
- package/{docCreateCommands-WJBEW2V7.js → docCreateCommands-75E6TZNN.js} +33 -23
- package/{docDeleteCommands-BVEHJOY5.js → docDeleteCommands-EJHLN7LW.js} +34 -25
- package/{docReadCommands-NEWOZIJV.js → docReadCommands-RJYBC4FS.js} +33 -23
- package/{docStore-3DXRYBMD.js → docStore-H5VWKT5D.js} +25 -26
- package/{docUpdateCommands-C7WHT7UU.js → docUpdateCommands-MG4CNISV.js} +33 -23
- package/fetchMessages-KTNM7QAR.js +1 -1
- package/{getPricing-3E6UNPKL.js → getPricing-6TOZXPAU.js} +7 -3
- package/{handleSendMessageAction-B5PRR7BE.js → handleSendMessageAction-QTUGICSZ.js} +29 -30
- package/index.js +77 -76
- package/{localDialogRead-YSKFFRTT.js → localDialogRead-2VRI24F4.js} +1 -1
- package/{machineCommands-IIIREAEK.js → machineCommands-MAV7M3TK.js} +63 -61
- package/{machineWsRunDispatch-3SIU6ILW.js → machineWsRunDispatch-ZOEGTKHC.js} +55 -53
- package/{memoryCommands-O4MIPIWQ.js → memoryCommands-AFMES3LN.js} +5 -5
- package/{models-4OPOOLFS.js → models-LSCRJJ6P.js} +2 -2
- package/package.json +1 -1
- package/{read-QJNKRROM.js → read-2MIMRBZ2.js} +4 -4
- package/{readDocTool-H6X6KO6X.js → readDocTool-QHVGQHUJ.js} +1 -1
- package/{readlineWorkspace-HGP3I3OC.js → readlineWorkspace-SWQKC7ZS.js} +1113 -678
- package/{removeDialogAgentAction-TCT35SOF.js → removeDialogAgentAction-GTX5AN54.js} +13 -13
- package/{runAgentClientLoop-EFM4PTVI.js → runAgentClientLoop-P25HACXX.js} +47 -47
- package/{runtimeDoctorCommands-ID43Z7VX.js → runtimeDoctorCommands-QNF3J3UV.js} +6 -6
- package/{setDialogExtraReferencesAction-CGYLZMFH.js → setDialogExtraReferencesAction-WFQ63KYO.js} +9 -10
- package/{setPrimaryDialogAgentAction-F6BFQDJU.js → setPrimaryDialogAgentAction-P57FXTSU.js} +13 -13
- package/{settingSlice-2I5HMG47.js → settingSlice-CK5YZGNI.js} +7 -8
- package/{skillDiscovery-UGSQGX2U.js → skillDiscovery-ZYHSX7VD.js} +3 -3
- package/{spaceCommands-MT7BWCIL.js → spaceCommands-6O5EFEM5.js} +37 -29
- package/{spaceSlice-BS5TSW3W.js → spaceSlice-4EXTYXS4.js} +28 -27
- package/{streamAgentChatTurn-I3VBFNR3.js → streamAgentChatTurn-Q3FJAHG2.js} +222 -128
- package/{toolApiClient-C7P7YSE4.js → toolApiClient-QI3YBNWB.js} +2 -2
- package/{tools-XSD2BOEN.js → tools-AHNQE4GP.js} +34 -34
- package/{tuiSummaryLlmCaller-32NRHTT2.js → tuiSummaryLlmCaller-TXLF4MEI.js} +8 -6
- package/{updateCommands-VOSPKXFF.js → updateCommands-XZDOOYFH.js} +13 -5
- package/{updateDialogTitleAction-7FYNJOGP.js → updateDialogTitleAction-XZDVLKVX.js} +29 -29
- package/chunk-5MMAK75Q.js +0 -15
- package/chunk-AZPCASRE.js +0 -36
- package/chunk-BBYVOSU2.js +0 -792
- package/chunk-DCOA4QSN.js +0 -105
- package/chunk-UAD2WT54.js +0 -64
- package/{chunk-JK7VW2FN.js → chunk-5MIDPSSK.js} +3 -3
- package/{chunk-5CS33IBL.js → chunk-PDL2AV3E.js} +3 -3
- package/{chunk-5MMZUWSG.js → chunk-TOILAPLH.js} +5 -5
- package/{chunk-OOM6SJNR.js → chunk-TSUJOM6N.js} +6 -6
- package/{db-6QED3ZVO.js → db-HCJ5PRB5.js} +3 -3
- package/{offlineMarxistsAgentCommand-BCPJITJL.js → offlineMarxistsAgentCommand-5OOWZLJI.js} +3 -3
- package/{tableCommands-M3DJUETS.js → tableCommands-E4SQWDOX.js} +6 -6
- package/{understanding-ZOESBLF3.js → understanding-3CUQQ6SV.js} +3 -3
|
@@ -3,55 +3,81 @@ import {
|
|
|
3
3
|
normalizeDialogRecord,
|
|
4
4
|
readDialogSnapshot,
|
|
5
5
|
sortDialogs
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-4EH7AR52.js";
|
|
7
7
|
import {
|
|
8
|
+
ANSI_ESCAPE_REGEX,
|
|
9
|
+
CLI_AUTO_TIER_AGENT_KEYS,
|
|
8
10
|
CLI_AUTO_TIER_AGENT_KEY_TABLE,
|
|
9
11
|
CLI_IMAGE_AGENT_KEY,
|
|
12
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE,
|
|
10
13
|
THEME_PALETTES,
|
|
14
|
+
allocateCollapsedPaste,
|
|
15
|
+
applyTerminalOutputToText,
|
|
11
16
|
buildSkillContextBlocks,
|
|
12
17
|
classifyCliAutoRoute,
|
|
18
|
+
clearCollapsedPasteStore,
|
|
19
|
+
countPhysicalLines,
|
|
20
|
+
createCollapsedPasteStore,
|
|
13
21
|
dimCliText,
|
|
22
|
+
displayWidth,
|
|
23
|
+
expandRangeToCollapsedPasteChips,
|
|
24
|
+
findCollapsedPasteSpanAt,
|
|
25
|
+
fitAnsiLine,
|
|
14
26
|
formatAssistantDisplay,
|
|
15
27
|
formatTokenCount,
|
|
16
28
|
getActiveBrightness,
|
|
17
29
|
getActiveDensity,
|
|
18
30
|
getActiveThemeName,
|
|
19
|
-
getCliLocale,
|
|
20
|
-
highlightMarkdown,
|
|
21
|
-
initCliLocale,
|
|
22
31
|
isBalanceExhaustedError,
|
|
23
32
|
isQuotaExhaustedError,
|
|
24
33
|
normalizeThinkingDisplayMode,
|
|
25
34
|
normalizeToolDisplayMode,
|
|
26
|
-
|
|
35
|
+
padOrTruncateToWidth,
|
|
36
|
+
releaseCollapsedPaste,
|
|
37
|
+
releaseCollapsedPasteReferences,
|
|
27
38
|
renderTokenStatus,
|
|
39
|
+
replaceCollapsedPastesWithReferences,
|
|
40
|
+
resolveAgentContextWindow,
|
|
41
|
+
resolveCliAutoFallbackTier,
|
|
28
42
|
resolveCliColorEnabled,
|
|
29
43
|
resolveSkillReference,
|
|
30
44
|
resolveTuiBrightness,
|
|
31
45
|
runAgentTurn,
|
|
32
46
|
setActiveBrightness,
|
|
33
47
|
setActiveDensity,
|
|
48
|
+
setActiveTerminalBaseHex,
|
|
34
49
|
setActiveThemeName,
|
|
35
|
-
|
|
50
|
+
shouldCollapsePaste,
|
|
51
|
+
stripAnsi,
|
|
36
52
|
surfaceBackgroundSequence,
|
|
37
|
-
|
|
53
|
+
takeDisplayWidth,
|
|
38
54
|
themeColorSequence,
|
|
39
|
-
themeText
|
|
40
|
-
|
|
55
|
+
themeText,
|
|
56
|
+
truncateAnsi,
|
|
57
|
+
visibleWidth,
|
|
58
|
+
wrapTextToLines,
|
|
59
|
+
wrapTranscriptLine
|
|
60
|
+
} from "./chunk-ZPFRLGIZ.js";
|
|
61
|
+
import "./chunk-3QAF2LTL.js";
|
|
41
62
|
import "./chunk-6HYVJV7B.js";
|
|
42
63
|
import {
|
|
43
64
|
listFavoriteAgentIdsAcrossServers,
|
|
44
65
|
listLocalCachedAgents,
|
|
45
66
|
listRemoteAgents,
|
|
46
67
|
listRemoteAgentsAcrossServers
|
|
47
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-DE5BA4O6.js";
|
|
48
69
|
import "./chunk-ID4G2MAR.js";
|
|
49
70
|
import {
|
|
50
71
|
listUserRecordsFromServers
|
|
51
|
-
} from "./chunk-
|
|
52
|
-
import
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
} from "./chunk-OPKKB25T.js";
|
|
73
|
+
import {
|
|
74
|
+
createCliLocalRuntimeAdapter,
|
|
75
|
+
initCliLocale,
|
|
76
|
+
parseCliLocale,
|
|
77
|
+
setCliLocale,
|
|
78
|
+
t
|
|
79
|
+
} from "./chunk-5ITRDSHY.js";
|
|
80
|
+
import "./chunk-TOILAPLH.js";
|
|
55
81
|
import "./chunk-CMKUBIGW.js";
|
|
56
82
|
import "./chunk-JBTJAPUF.js";
|
|
57
83
|
import {
|
|
@@ -60,135 +86,148 @@ import {
|
|
|
60
86
|
import {
|
|
61
87
|
queryUserRecords,
|
|
62
88
|
readDbRecord
|
|
63
|
-
} from "./chunk-
|
|
64
|
-
import "./chunk-
|
|
89
|
+
} from "./chunk-QCA3EPYK.js";
|
|
90
|
+
import "./chunk-RNQ5BLR2.js";
|
|
65
91
|
import {
|
|
66
92
|
resolveCliAgentKeyInput
|
|
67
93
|
} from "./chunk-VHBWHNVT.js";
|
|
68
94
|
import "./chunk-LTRXGFMS.js";
|
|
69
|
-
import "./chunk-
|
|
95
|
+
import "./chunk-UG3WOFU6.js";
|
|
70
96
|
import "./chunk-ATNTHIZI.js";
|
|
71
97
|
import "./chunk-JEXVIMYZ.js";
|
|
72
|
-
import
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
import "./chunk-
|
|
98
|
+
import {
|
|
99
|
+
prepareTools
|
|
100
|
+
} from "./chunk-YTQLJYLB.js";
|
|
101
|
+
import "./chunk-4GBNEA5B.js";
|
|
102
|
+
import {
|
|
103
|
+
expandEnabledPacks
|
|
104
|
+
} from "./chunk-RZ735TLX.js";
|
|
105
|
+
import "./chunk-YDCZVUFP.js";
|
|
106
|
+
import "./chunk-OOIN7HSO.js";
|
|
76
107
|
import "./chunk-KQHGZWSV.js";
|
|
77
|
-
import "./chunk-
|
|
108
|
+
import "./chunk-IVAOVLM7.js";
|
|
78
109
|
import "./chunk-3LY4F7SV.js";
|
|
79
110
|
import "./chunk-VP4WJWKW.js";
|
|
80
111
|
import "./chunk-63W5N6P3.js";
|
|
81
112
|
import "./chunk-VF4K2QE6.js";
|
|
82
|
-
import "./chunk-
|
|
83
|
-
import "./chunk-
|
|
113
|
+
import "./chunk-MEVCDATU.js";
|
|
114
|
+
import "./chunk-G3B356GF.js";
|
|
84
115
|
import "./chunk-VC6OZXO5.js";
|
|
85
116
|
import "./chunk-OWOHNGCN.js";
|
|
86
117
|
import {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
getModelContextWindow,
|
|
90
|
-
planCompression,
|
|
91
|
-
serializeMessageContent
|
|
92
|
-
} from "./chunk-5MOUAAMK.js";
|
|
118
|
+
extractReferenceKeysFromMessage
|
|
119
|
+
} from "./chunk-AM53Q2SD.js";
|
|
93
120
|
import {
|
|
94
121
|
buildBuiltinSummaryContent
|
|
95
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-V2J635L5.js";
|
|
96
123
|
import "./chunk-MRC4Q34M.js";
|
|
97
124
|
import "./chunk-MTU75CZ2.js";
|
|
98
125
|
import "./chunk-CWMSB67P.js";
|
|
99
|
-
import "./chunk-
|
|
100
|
-
import "./chunk-
|
|
126
|
+
import "./chunk-GPZM7QH6.js";
|
|
127
|
+
import "./chunk-6LMFFG3K.js";
|
|
101
128
|
import "./chunk-Z4NR32XR.js";
|
|
102
129
|
import "./chunk-M76ECQRD.js";
|
|
103
|
-
import "./chunk-MQI77IRB.js";
|
|
104
|
-
import "./chunk-3NSIQZZ6.js";
|
|
105
|
-
import "./chunk-Y5GCAMGP.js";
|
|
106
|
-
import "./chunk-SOTZ6RDN.js";
|
|
107
|
-
import "./chunk-7D3JY6C2.js";
|
|
108
|
-
import "./chunk-UAD2WT54.js";
|
|
109
|
-
import "./chunk-O26GI2JP.js";
|
|
110
|
-
import "./chunk-AZPCASRE.js";
|
|
111
|
-
import "./chunk-DCOA4QSN.js";
|
|
112
|
-
import "./chunk-HNW7IJSK.js";
|
|
113
|
-
import "./chunk-XENYHRUE.js";
|
|
114
|
-
import "./chunk-IPYUUY4E.js";
|
|
115
|
-
import {
|
|
116
|
-
runSelfUpdate
|
|
117
|
-
} from "./chunk-CKOJQDKR.js";
|
|
118
|
-
import {
|
|
119
|
-
saveProfileAgentSelection,
|
|
120
|
-
saveProfileLocale
|
|
121
|
-
} from "./chunk-ROWQEJRP.js";
|
|
122
|
-
import {
|
|
123
|
-
readPipeText,
|
|
124
|
-
spawnProcess
|
|
125
|
-
} from "./chunk-IDZTNRP2.js";
|
|
126
130
|
import {
|
|
127
131
|
buildSkillDiscoveryContextBlock
|
|
128
|
-
} from "./chunk-
|
|
129
|
-
import "./chunk-C4FTUXVF.js";
|
|
130
|
-
import "./chunk-KKY4B2Q2.js";
|
|
132
|
+
} from "./chunk-3QKO4EHV.js";
|
|
131
133
|
import "./chunk-WZSRQNQG.js";
|
|
132
134
|
import {
|
|
135
|
+
buildLocalWorkspaceOpenAiTools,
|
|
136
|
+
buildLocalWorkspaceToolset,
|
|
133
137
|
getProcessRegistry
|
|
134
|
-
} from "./chunk-
|
|
135
|
-
import "./chunk-ZPRK73XY.js";
|
|
138
|
+
} from "./chunk-DRMGJFGQ.js";
|
|
136
139
|
import "./chunk-ZNFJWEN4.js";
|
|
137
|
-
import "./chunk-
|
|
140
|
+
import "./chunk-ZR4VHQ5D.js";
|
|
141
|
+
import "./chunk-NCGFB7NN.js";
|
|
138
142
|
import {
|
|
139
143
|
readCommandActionGatePayload,
|
|
140
144
|
resolveAgentImageInputSupport
|
|
141
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-4BTHUYMY.js";
|
|
142
146
|
import "./chunk-OPZYGHUC.js";
|
|
143
|
-
import "./chunk-OUI3ZHYD.js";
|
|
144
|
-
import "./chunk-YTBMA7NO.js";
|
|
145
|
-
import "./chunk-4SOKXIW4.js";
|
|
146
147
|
import {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
buildCurrentTimeBlock,
|
|
149
|
+
buildIdentityBlock,
|
|
150
|
+
buildRuntimeGuidanceBlocks
|
|
151
|
+
} from "./chunk-6OVCRC72.js";
|
|
152
|
+
import "./chunk-TSKWE74T.js";
|
|
153
|
+
import {
|
|
154
|
+
canonicalizeToolNames
|
|
155
|
+
} from "./chunk-43UD5ZP7.js";
|
|
156
|
+
import {
|
|
157
|
+
DEFAULT_CONTEXT_WINDOW,
|
|
158
|
+
clipCompactText,
|
|
159
|
+
estimateTokenCount,
|
|
160
|
+
getModelContextWindow,
|
|
161
|
+
planCompression,
|
|
162
|
+
serializeMessageContent
|
|
163
|
+
} from "./chunk-S73OEOHH.js";
|
|
164
|
+
import "./chunk-S3UTETIC.js";
|
|
165
|
+
import "./chunk-PDL2AV3E.js";
|
|
151
166
|
import "./chunk-JZPBVBIY.js";
|
|
152
|
-
import "./chunk-
|
|
153
|
-
import "./chunk-
|
|
154
|
-
import "./chunk-
|
|
155
|
-
import "./chunk-
|
|
156
|
-
import "./chunk-WWC7I6TA.js";
|
|
157
|
-
import "./chunk-JK7VW2FN.js";
|
|
167
|
+
import "./chunk-BYXBJQAS.js";
|
|
168
|
+
import "./chunk-QLUFR47U.js";
|
|
169
|
+
import "./chunk-KKY4B2Q2.js";
|
|
170
|
+
import "./chunk-5MIDPSSK.js";
|
|
158
171
|
import {
|
|
159
172
|
extractCustomId
|
|
160
173
|
} from "./chunk-DFFIZ25G.js";
|
|
161
174
|
import "./chunk-3ASDTTEI.js";
|
|
175
|
+
import "./chunk-4ON5AV72.js";
|
|
162
176
|
import {
|
|
163
|
-
|
|
164
|
-
} from "./chunk-
|
|
177
|
+
toErrorMessage
|
|
178
|
+
} from "./chunk-HNMXYYJR.js";
|
|
179
|
+
import "./chunk-H33743XH.js";
|
|
180
|
+
import "./chunk-LM6IYQ3F.js";
|
|
181
|
+
import "./chunk-SOTZ6RDN.js";
|
|
182
|
+
import "./chunk-HNW7IJSK.js";
|
|
183
|
+
import "./chunk-XENYHRUE.js";
|
|
165
184
|
import {
|
|
166
185
|
compactWhitespace
|
|
167
186
|
} from "./chunk-DWLEOOGR.js";
|
|
168
|
-
import
|
|
187
|
+
import {
|
|
188
|
+
runSelfUpdate
|
|
189
|
+
} from "./chunk-7JJCGV7N.js";
|
|
190
|
+
import {
|
|
191
|
+
saveProfileAgentSelection,
|
|
192
|
+
saveProfileLocale
|
|
193
|
+
} from "./chunk-ROWQEJRP.js";
|
|
194
|
+
import {
|
|
195
|
+
readPipeText,
|
|
196
|
+
spawnProcess
|
|
197
|
+
} from "./chunk-IDZTNRP2.js";
|
|
198
|
+
import "./chunk-IKXL2HZ3.js";
|
|
199
|
+
import "./chunk-524BDL33.js";
|
|
200
|
+
import "./chunk-7MYHLZ3F.js";
|
|
201
|
+
import "./chunk-WTYKCU4W.js";
|
|
202
|
+
import "./chunk-Y5GCAMGP.js";
|
|
203
|
+
import "./chunk-KX6YBIHG.js";
|
|
204
|
+
import "./chunk-3HHTVM6G.js";
|
|
205
|
+
import "./chunk-NITP2JDG.js";
|
|
206
|
+
import "./chunk-WPHL6ALY.js";
|
|
207
|
+
import "./chunk-O4BU24WZ.js";
|
|
208
|
+
import "./chunk-I42VC5KR.js";
|
|
209
|
+
import "./chunk-WWC7I6TA.js";
|
|
210
|
+
import {
|
|
211
|
+
asTrimmedLowercaseString
|
|
212
|
+
} from "./chunk-QSJ3HFEF.js";
|
|
213
|
+
import "./chunk-XHQWJUW4.js";
|
|
214
|
+
import "./chunk-TSUJOM6N.js";
|
|
215
|
+
import "./chunk-OOSFSFMA.js";
|
|
216
|
+
import "./chunk-GBRG75BQ.js";
|
|
217
|
+
import "./chunk-KUG52IAP.js";
|
|
218
|
+
import "./chunk-3EUW3WEO.js";
|
|
219
|
+
import "./chunk-U6VC4MU4.js";
|
|
169
220
|
import {
|
|
170
221
|
parseUserIdFromAuthToken,
|
|
171
222
|
resolveAuthToken,
|
|
172
223
|
resolveServerCandidates,
|
|
173
224
|
resolveServerUrl
|
|
174
|
-
} from "./chunk-
|
|
225
|
+
} from "./chunk-5NBHQD4D.js";
|
|
175
226
|
import {
|
|
176
227
|
DEFAULT_NOLO_SERVER_URL
|
|
177
228
|
} from "./chunk-OLZBQWZU.js";
|
|
178
|
-
import {
|
|
179
|
-
toErrorMessage
|
|
180
|
-
} from "./chunk-HNMXYYJR.js";
|
|
181
|
-
import "./chunk-H33743XH.js";
|
|
182
|
-
import "./chunk-LM6IYQ3F.js";
|
|
183
|
-
import "./chunk-XFOLQLDN.js";
|
|
184
|
-
import "./chunk-OOM6SJNR.js";
|
|
185
|
-
import "./chunk-OOSFSFMA.js";
|
|
186
|
-
import "./chunk-GBRG75BQ.js";
|
|
187
|
-
import "./chunk-3EUW3WEO.js";
|
|
188
|
-
import "./chunk-U6VC4MU4.js";
|
|
189
|
-
import "./chunk-KUG52IAP.js";
|
|
190
|
-
import "./chunk-4SN6J65J.js";
|
|
191
229
|
import "./chunk-LCBAMY2M.js";
|
|
230
|
+
import "./chunk-4SN6J65J.js";
|
|
192
231
|
import "./chunk-CF7PE763.js";
|
|
193
232
|
import {
|
|
194
233
|
asOptionalTrimmedString
|
|
@@ -198,8 +237,81 @@ import "./chunk-4VNS5WPM.js";
|
|
|
198
237
|
// packages/cli/tui/readlineWorkspace.ts
|
|
199
238
|
import { createInterface } from "node:readline";
|
|
200
239
|
import { stdin as defaultInput, stdout as defaultOutput } from "node:process";
|
|
201
|
-
import { existsSync as
|
|
240
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
|
|
241
|
+
import { join as join2 } from "node:path";
|
|
242
|
+
|
|
243
|
+
// packages/cli/client/estimateCliContext.ts
|
|
244
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
202
245
|
import { join } from "node:path";
|
|
246
|
+
var DEFAULT_CLI_PACKS = ["code", "agent-orchestration", "skills"];
|
|
247
|
+
var DEFAULT_CLI_PLATFORM_TOOLS = [
|
|
248
|
+
"ui_ask_choice",
|
|
249
|
+
"exa_search",
|
|
250
|
+
"fetchWebpage"
|
|
251
|
+
];
|
|
252
|
+
var DEFAULT_FLASH_PROMPT = "\u4F60\u662F\u5171\u4EAB\u7A7A\u95F4\u91CC\u7684\u9AD8\u6027\u4EF7\u6BD4\u901A\u7528 AI \u52A9\u624B\u3002\u4F18\u5148\u5FEB\u901F\u3001\u76F4\u63A5\u3001\u7A33\u5B9A\u5730\u5B8C\u6210\u4EFB\u52A1\uFF1B\u9700\u8981\u63A8\u7406\u65F6\u4FDD\u6301\u6B65\u9AA4\u6E05\u6670\u3002";
|
|
253
|
+
function readAgentsMd(cwd) {
|
|
254
|
+
for (const name of ["AGENTS.md", "agents.md"]) {
|
|
255
|
+
const path = join(cwd, name);
|
|
256
|
+
if (!existsSync(path)) continue;
|
|
257
|
+
try {
|
|
258
|
+
return readFileSync(path, "utf8");
|
|
259
|
+
} catch {
|
|
260
|
+
return "";
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return "";
|
|
264
|
+
}
|
|
265
|
+
function estimateToolSchemas(toolNames) {
|
|
266
|
+
const toolset = buildLocalWorkspaceToolset({
|
|
267
|
+
declaredToolNames: toolNames,
|
|
268
|
+
exposeShellTools: true
|
|
269
|
+
});
|
|
270
|
+
const workspaceTools = buildLocalWorkspaceOpenAiTools({
|
|
271
|
+
toolNames: toolset.toolNames,
|
|
272
|
+
exposeShellTools: true
|
|
273
|
+
});
|
|
274
|
+
const platformNames = DEFAULT_CLI_PLATFORM_TOOLS.filter(
|
|
275
|
+
(name) => toolNames.includes(name)
|
|
276
|
+
);
|
|
277
|
+
const platformTools = platformNames.length > 0 ? prepareTools([...platformNames]) : [];
|
|
278
|
+
return estimateTokenCount(JSON.stringify([...workspaceTools, ...platformTools]));
|
|
279
|
+
}
|
|
280
|
+
function estimateDefaultCliContextTokens(opts = {}) {
|
|
281
|
+
const cwd = opts.cwd?.trim() || process.cwd();
|
|
282
|
+
const model = opts.model?.trim() || "deepseek-v4-flash";
|
|
283
|
+
const agentName = opts.agentName?.trim() || "DeepSeek V4 Flash";
|
|
284
|
+
const agentKey = opts.agentKey?.trim() || "agent-pub-deepseek-v4-flash";
|
|
285
|
+
const prompt = opts.agentPrompt?.trim() || DEFAULT_FLASH_PROMPT;
|
|
286
|
+
const packTools = canonicalizeToolNames(
|
|
287
|
+
expandEnabledPacks([...DEFAULT_CLI_PACKS], [])
|
|
288
|
+
);
|
|
289
|
+
const toolNames = canonicalizeToolNames([
|
|
290
|
+
...packTools,
|
|
291
|
+
...DEFAULT_CLI_PLATFORM_TOOLS
|
|
292
|
+
]);
|
|
293
|
+
const guidance = buildRuntimeGuidanceBlocks(toolNames);
|
|
294
|
+
const systemParts = [
|
|
295
|
+
prompt,
|
|
296
|
+
buildIdentityBlock({
|
|
297
|
+
agentName,
|
|
298
|
+
agentId: agentKey,
|
|
299
|
+
model
|
|
300
|
+
}),
|
|
301
|
+
guidance.startupProtocol,
|
|
302
|
+
guidance.contextLayerContract,
|
|
303
|
+
guidance.emailRegistrationWorkflow,
|
|
304
|
+
guidance.webResearchToolPolicy,
|
|
305
|
+
buildCurrentTimeBlock(/* @__PURE__ */ new Date()),
|
|
306
|
+
readAgentsMd(cwd),
|
|
307
|
+
buildSkillDiscoveryContextBlock(cwd) ?? ""
|
|
308
|
+
];
|
|
309
|
+
const systemTokens = estimateTokenCount(
|
|
310
|
+
systemParts.filter((part) => part?.trim()).join("\n\n")
|
|
311
|
+
);
|
|
312
|
+
const toolTokens = estimateToolSchemas(toolNames);
|
|
313
|
+
return Math.max(0, systemTokens + toolTokens);
|
|
314
|
+
}
|
|
203
315
|
|
|
204
316
|
// packages/cli/client/compactDialog.ts
|
|
205
317
|
import { ulid } from "ulid";
|
|
@@ -480,6 +592,12 @@ function renderDialogRow(args, colorEnabled = resolveCliColorEnabled()) {
|
|
|
480
592
|
function renderDialogOverflow(text, colorEnabled = resolveCliColorEnabled()) {
|
|
481
593
|
return themeText(` ${text}`, "chrome", colorEnabled);
|
|
482
594
|
}
|
|
595
|
+
function renderOverflowAbove(count, colorEnabled = resolveCliColorEnabled()) {
|
|
596
|
+
return renderDialogOverflow(t("dialogMoreAbove", String(count)), colorEnabled);
|
|
597
|
+
}
|
|
598
|
+
function renderOverflowBelow(count, colorEnabled = resolveCliColorEnabled()) {
|
|
599
|
+
return renderDialogOverflow(t("dialogMoreBelow", String(count)), colorEnabled);
|
|
600
|
+
}
|
|
483
601
|
function renderDialogCommand(text, colorEnabled = resolveCliColorEnabled()) {
|
|
484
602
|
return themeText(` ${text}`, "danger", colorEnabled);
|
|
485
603
|
}
|
|
@@ -578,7 +696,7 @@ function renderSelectDialog(args) {
|
|
|
578
696
|
];
|
|
579
697
|
const lines = [...titleLines, ""];
|
|
580
698
|
if (window.start > 0) {
|
|
581
|
-
lines.push(
|
|
699
|
+
lines.push(renderOverflowAbove(window.start));
|
|
582
700
|
}
|
|
583
701
|
for (let index = window.start; index < window.end; index += 1) {
|
|
584
702
|
const item = args.items[index];
|
|
@@ -591,7 +709,7 @@ function renderSelectDialog(args) {
|
|
|
591
709
|
);
|
|
592
710
|
}
|
|
593
711
|
if (window.end < total) {
|
|
594
|
-
lines.push("",
|
|
712
|
+
lines.push("", renderOverflowBelow(total - window.end));
|
|
595
713
|
}
|
|
596
714
|
return lines.join("\n");
|
|
597
715
|
}
|
|
@@ -820,7 +938,7 @@ async function runSelectDialog(args) {
|
|
|
820
938
|
// packages/cli/tui/confirmDialog.ts
|
|
821
939
|
var FALLBACK_TERMINAL_WIDTH = 80;
|
|
822
940
|
var WIDE_CHAR = /[ᄀ-ᅟ⺀-〾ぁ-㏿㐀-䶿一-鿿ꀀ-가-힣豈-︰--⦆¢-₩]/;
|
|
823
|
-
function
|
|
941
|
+
function displayWidth2(text) {
|
|
824
942
|
let width = 0;
|
|
825
943
|
for (const char of text) width += WIDE_CHAR.test(char) ? 2 : 1;
|
|
826
944
|
return width;
|
|
@@ -828,9 +946,9 @@ function displayWidth(text) {
|
|
|
828
946
|
function truncateCommand(command, maxWidth) {
|
|
829
947
|
const indent = 2;
|
|
830
948
|
const budget = Math.max(10, maxWidth - indent);
|
|
831
|
-
if (
|
|
949
|
+
if (displayWidth2(command) <= budget) return command;
|
|
832
950
|
const marker = ` ${t("dialogConfirmCommandTruncated")}`;
|
|
833
|
-
const keep = Math.max(1, budget -
|
|
951
|
+
const keep = Math.max(1, budget - displayWidth2(marker));
|
|
834
952
|
let kept = "";
|
|
835
953
|
let width = 0;
|
|
836
954
|
for (const char of command) {
|
|
@@ -860,9 +978,15 @@ async function runConfirmDialog(args) {
|
|
|
860
978
|
value: false
|
|
861
979
|
}
|
|
862
980
|
];
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
981
|
+
let titleText = args.request.title;
|
|
982
|
+
let bodyText = args.request.body;
|
|
983
|
+
if (args.request.action === "destructive_shell_command") {
|
|
984
|
+
titleText = t("dialogConfirmTitle");
|
|
985
|
+
bodyText = t("dialogConfirmBody");
|
|
986
|
+
} else if (args.request.action === "external_file_access") {
|
|
987
|
+
titleText = t("dialogConfirmExternalFileTitle");
|
|
988
|
+
bodyText = t("dialogConfirmExternalFileBody");
|
|
989
|
+
}
|
|
866
990
|
const terminalWidth = typeof output.columns === "number" && output.columns > 0 ? output.columns : FALLBACK_TERMINAL_WIDTH;
|
|
867
991
|
const titleLines = [
|
|
868
992
|
renderDialogTitle(`${titleText} ${t("dialogConfirmHint")}`)
|
|
@@ -1112,19 +1236,23 @@ function renderTabBar(questions, activeIndex, colorEnabled) {
|
|
|
1112
1236
|
}
|
|
1113
1237
|
return colorEnabled ? themeText(` ${label} `, "muted", colorEnabled) : ` ${label} `;
|
|
1114
1238
|
});
|
|
1115
|
-
const submitLabel = "
|
|
1239
|
+
const submitLabel = t("askChoiceSubmit");
|
|
1116
1240
|
return tabs.join(" ") + " " + (colorEnabled ? themeText(submitLabel, "chrome", colorEnabled) : submitLabel);
|
|
1117
1241
|
}
|
|
1118
|
-
function renderFooter(colorEnabled) {
|
|
1119
|
-
const hints =
|
|
1242
|
+
function renderFooter(multiSelect, colorEnabled) {
|
|
1243
|
+
const hints = multiSelect ? t("askChoiceFooterMulti") : t("askChoiceFooterSingle");
|
|
1120
1244
|
return colorEnabled ? themeText(` ${hints}`, "chrome", colorEnabled) : ` ${hints}`;
|
|
1121
1245
|
}
|
|
1246
|
+
function otherRowPrefix(index) {
|
|
1247
|
+
return ` [${index + 1}] ${t("askChoiceOtherLabel")}: `;
|
|
1248
|
+
}
|
|
1122
1249
|
function renderAskChoiceFrame(state) {
|
|
1123
1250
|
const colorEnabled = resolveCliColorEnabled();
|
|
1124
1251
|
const q = state.questions[state.activeIndex];
|
|
1125
1252
|
const qs = state.questionStates[state.activeIndex];
|
|
1126
1253
|
const lines = [];
|
|
1127
|
-
|
|
1254
|
+
let otherCursor = null;
|
|
1255
|
+
lines.push(renderDialogTitle(t("askChoiceTitle")));
|
|
1128
1256
|
lines.push("");
|
|
1129
1257
|
if (state.questions.length > 1) {
|
|
1130
1258
|
lines.push(renderTabBar(state.questions, state.activeIndex, colorEnabled));
|
|
@@ -1135,11 +1263,11 @@ function renderAskChoiceFrame(state) {
|
|
|
1135
1263
|
);
|
|
1136
1264
|
if (q.multiSelect) {
|
|
1137
1265
|
lines.push(
|
|
1138
|
-
colorEnabled ? themeText(
|
|
1266
|
+
colorEnabled ? themeText(` ${t("askChoiceHintMulti")}`, "muted", colorEnabled) : ` ${t("askChoiceHintMulti")}`
|
|
1139
1267
|
);
|
|
1140
1268
|
} else {
|
|
1141
1269
|
lines.push(
|
|
1142
|
-
colorEnabled ? themeText(
|
|
1270
|
+
colorEnabled ? themeText(` ${t("askChoiceHintSingle")}`, "muted", colorEnabled) : ` ${t("askChoiceHintSingle")}`
|
|
1143
1271
|
);
|
|
1144
1272
|
}
|
|
1145
1273
|
lines.push("");
|
|
@@ -1149,9 +1277,7 @@ function renderAskChoiceFrame(state) {
|
|
|
1149
1277
|
total: totalRows
|
|
1150
1278
|
});
|
|
1151
1279
|
if (window.start > 0) {
|
|
1152
|
-
lines.push(
|
|
1153
|
-
colorEnabled ? themeText(` \u2191 ${window.start} more`, "chrome", colorEnabled) : ` \u2191 ${window.start} more`
|
|
1154
|
-
);
|
|
1280
|
+
lines.push(renderOverflowAbove(window.start));
|
|
1155
1281
|
}
|
|
1156
1282
|
for (let i = window.start; i < window.end; i++) {
|
|
1157
1283
|
if (i < q.choices.length) {
|
|
@@ -1169,25 +1295,29 @@ function renderAskChoiceFrame(state) {
|
|
|
1169
1295
|
} else {
|
|
1170
1296
|
const focused = qs.cursorIndex === i;
|
|
1171
1297
|
const marker = focused ? DIALOG_CURSOR : " ";
|
|
1172
|
-
const
|
|
1173
|
-
const
|
|
1298
|
+
const plainPrefix = `${marker}${otherRowPrefix(i)}`;
|
|
1299
|
+
const plainRow = `${plainPrefix}${qs.otherText}`;
|
|
1174
1300
|
if (focused && colorEnabled) {
|
|
1175
1301
|
lines.push(
|
|
1176
|
-
`\x1B[1m${themeColorSequence("accent")}${
|
|
1302
|
+
`\x1B[1m${themeColorSequence("accent")}${plainRow}\x1B[0m`
|
|
1177
1303
|
);
|
|
1178
1304
|
} else {
|
|
1179
|
-
lines.push(
|
|
1305
|
+
lines.push(plainRow);
|
|
1306
|
+
}
|
|
1307
|
+
if (qs.otherFocused) {
|
|
1308
|
+
otherCursor = {
|
|
1309
|
+
lineIndex: lines.length - 1,
|
|
1310
|
+
col: displayWidth(plainPrefix + qs.otherText)
|
|
1311
|
+
};
|
|
1180
1312
|
}
|
|
1181
1313
|
}
|
|
1182
1314
|
}
|
|
1183
1315
|
if (window.end < totalRows) {
|
|
1184
|
-
lines.push(
|
|
1185
|
-
colorEnabled ? themeText(` \u2193 ${totalRows - window.end} more`, "chrome", colorEnabled) : ` \u2193 ${totalRows - window.end} more`
|
|
1186
|
-
);
|
|
1316
|
+
lines.push(renderOverflowBelow(totalRows - window.end));
|
|
1187
1317
|
}
|
|
1188
1318
|
lines.push("");
|
|
1189
|
-
lines.push(renderFooter(colorEnabled));
|
|
1190
|
-
return lines.join("\n");
|
|
1319
|
+
lines.push(renderFooter(q.multiSelect, colorEnabled));
|
|
1320
|
+
return { text: lines.join("\n"), otherCursor };
|
|
1191
1321
|
}
|
|
1192
1322
|
async function runAskChoiceDialog(args) {
|
|
1193
1323
|
const { request } = args;
|
|
@@ -1200,9 +1330,6 @@ async function runAskChoiceDialog(args) {
|
|
|
1200
1330
|
if (normalized.questions.length === 0) {
|
|
1201
1331
|
return { kind: "cancelled" };
|
|
1202
1332
|
}
|
|
1203
|
-
const q0 = normalized.questions[0];
|
|
1204
|
-
if (normalized.questions.length === 1 && !q0.multiSelect && !q0.allowOther) {
|
|
1205
|
-
}
|
|
1206
1333
|
let state = createInitialAskChoiceState(normalized.questions);
|
|
1207
1334
|
const output = args.output ?? process.stdout;
|
|
1208
1335
|
const input = args.input ?? process.stdin;
|
|
@@ -1216,9 +1343,15 @@ async function runAskChoiceDialog(args) {
|
|
|
1216
1343
|
typeof args.bottomRow === "function" ? args.bottomRow() : args.bottomRow ?? 0
|
|
1217
1344
|
);
|
|
1218
1345
|
let lastBottomRow = 0;
|
|
1346
|
+
let unanchoredCursorLift = 0;
|
|
1347
|
+
const restoreUnanchoredCursor = () => {
|
|
1348
|
+
if (unanchoredCursorLift <= 0) return;
|
|
1349
|
+
output.write(`\x1B[${unanchoredCursorLift}B`);
|
|
1350
|
+
unanchoredCursorLift = 0;
|
|
1351
|
+
};
|
|
1219
1352
|
const paint = () => {
|
|
1220
1353
|
const frame = renderAskChoiceFrame(state);
|
|
1221
|
-
const lines = frame.split("\n");
|
|
1354
|
+
const lines = frame.text.split("\n");
|
|
1222
1355
|
const lineCount = lines.length;
|
|
1223
1356
|
const canPosition = outputIsTty(output) && typeof output.write === "function";
|
|
1224
1357
|
if (bottomAnchored && canPosition) {
|
|
@@ -1235,22 +1368,37 @@ async function runAskChoiceDialog(args) {
|
|
|
1235
1368
|
}
|
|
1236
1369
|
lastBottomRow = anchorRow;
|
|
1237
1370
|
renderedLineCount = lineCount;
|
|
1371
|
+
unanchoredCursorLift = 0;
|
|
1372
|
+
if (frame.otherCursor) {
|
|
1373
|
+
const cursorRow = anchorRow - (lineCount - 1 - frame.otherCursor.lineIndex);
|
|
1374
|
+
if (cursorRow >= 1) {
|
|
1375
|
+
output.write(`\x1B[${cursorRow};${frame.otherCursor.col + 1}H`);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1238
1378
|
return;
|
|
1239
1379
|
}
|
|
1240
1380
|
if (canPosition) {
|
|
1381
|
+
restoreUnanchoredCursor();
|
|
1241
1382
|
for (let i = 0; i < renderedLineCount; i++) {
|
|
1242
1383
|
output.write("\x1B[1A\x1B[2K");
|
|
1243
1384
|
}
|
|
1244
|
-
output.write(`${frame}
|
|
1385
|
+
output.write(`${frame.text}
|
|
1245
1386
|
`);
|
|
1246
1387
|
renderedLineCount = lineCount;
|
|
1388
|
+
if (frame.otherCursor) {
|
|
1389
|
+
const linesFromBottom = lineCount - frame.otherCursor.lineIndex;
|
|
1390
|
+
output.write(`\x1B[${linesFromBottom}A`);
|
|
1391
|
+
output.write(`\x1B[${frame.otherCursor.col + 1}G`);
|
|
1392
|
+
unanchoredCursorLift = linesFromBottom;
|
|
1393
|
+
}
|
|
1247
1394
|
return;
|
|
1248
1395
|
}
|
|
1249
1396
|
if (typeof output.write === "function") {
|
|
1250
|
-
output.write(`${frame}
|
|
1397
|
+
output.write(`${frame.text}
|
|
1251
1398
|
`);
|
|
1252
1399
|
}
|
|
1253
1400
|
renderedLineCount = lineCount;
|
|
1401
|
+
unanchoredCursorLift = 0;
|
|
1254
1402
|
};
|
|
1255
1403
|
const resizeTarget = output;
|
|
1256
1404
|
const onOutputResize = () => paint();
|
|
@@ -1278,6 +1426,9 @@ async function runAskChoiceDialog(args) {
|
|
|
1278
1426
|
continue;
|
|
1279
1427
|
}
|
|
1280
1428
|
let action = null;
|
|
1429
|
+
const qs = state.questionStates[state.activeIndex];
|
|
1430
|
+
const q = state.questions[state.activeIndex];
|
|
1431
|
+
const isOtherRow = qs.cursorIndex >= q.choices.length;
|
|
1281
1432
|
if (isCancel(sequence)) {
|
|
1282
1433
|
action = { type: "CANCEL" };
|
|
1283
1434
|
} else if (sequence === CSI_TAB) {
|
|
@@ -1289,11 +1440,17 @@ async function runAskChoiceDialog(args) {
|
|
|
1289
1440
|
} else if (isArrowDown(sequence)) {
|
|
1290
1441
|
action = { type: "MOVE_CURSOR", delta: 1 };
|
|
1291
1442
|
} else if (sequence === CSI_SPACE) {
|
|
1292
|
-
|
|
1443
|
+
if (qs.otherFocused) {
|
|
1444
|
+
action = {
|
|
1445
|
+
type: "SET_OTHER_TEXT",
|
|
1446
|
+
text: qs.otherText + " "
|
|
1447
|
+
};
|
|
1448
|
+
} else if (q.multiSelect) {
|
|
1449
|
+
action = { type: "TOGGLE_AT_CURSOR" };
|
|
1450
|
+
} else if (isOtherRow) {
|
|
1451
|
+
action = { type: "FOCUS_OTHER" };
|
|
1452
|
+
}
|
|
1293
1453
|
} else if (isSubmit(sequence)) {
|
|
1294
|
-
const qs = state.questionStates[state.activeIndex];
|
|
1295
|
-
const q = state.questions[state.activeIndex];
|
|
1296
|
-
const isOtherRow = qs.cursorIndex >= q.choices.length;
|
|
1297
1454
|
if (qs.otherFocused) {
|
|
1298
1455
|
action = { type: "BLUR_OTHER" };
|
|
1299
1456
|
} else if (isOtherRow && !qs.otherFocused) {
|
|
@@ -1304,24 +1461,29 @@ async function runAskChoiceDialog(args) {
|
|
|
1304
1461
|
action = { type: "SELECT_AT_CURSOR" };
|
|
1305
1462
|
}
|
|
1306
1463
|
} else if (sequence === CSI_BACKSPACE || sequence === CSI_BACKSPACE_ALT) {
|
|
1307
|
-
const qs = state.questionStates[state.activeIndex];
|
|
1308
1464
|
if (qs.otherFocused && qs.otherText.length > 0) {
|
|
1465
|
+
const chars = Array.from(qs.otherText);
|
|
1309
1466
|
action = {
|
|
1310
1467
|
type: "SET_OTHER_TEXT",
|
|
1311
|
-
text:
|
|
1468
|
+
text: chars.slice(0, -1).join("")
|
|
1312
1469
|
};
|
|
1313
1470
|
}
|
|
1314
|
-
} else if (sequence.length
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1471
|
+
} else if (sequence.length >= 1 && sequence.charCodeAt(0) >= 32 && !sequence.startsWith("\x1B")) {
|
|
1472
|
+
if (qs.otherFocused || isOtherRow && q.allowOther) {
|
|
1473
|
+
const cleaned = sequence.replace(/[\x00-\x1f\x7f]/g, "");
|
|
1474
|
+
if (cleaned) {
|
|
1475
|
+
if (!qs.otherFocused) {
|
|
1476
|
+
state = askChoiceReducer(state, { type: "FOCUS_OTHER" });
|
|
1477
|
+
}
|
|
1478
|
+
const currentText = state.questionStates[state.activeIndex].otherText;
|
|
1479
|
+
action = {
|
|
1480
|
+
type: "SET_OTHER_TEXT",
|
|
1481
|
+
text: currentText + cleaned
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1321
1484
|
}
|
|
1322
1485
|
}
|
|
1323
1486
|
if (action) {
|
|
1324
|
-
const prev = state;
|
|
1325
1487
|
state = askChoiceReducer(state, action);
|
|
1326
1488
|
if (state.phase !== "active") break;
|
|
1327
1489
|
if (action.type === "BLUR_OTHER" && state.activeIndex >= state.questions.length - 1 && canSubmit(state)) {
|
|
@@ -1345,6 +1507,7 @@ async function runAskChoiceDialog(args) {
|
|
|
1345
1507
|
renderedLineCount
|
|
1346
1508
|
);
|
|
1347
1509
|
} else {
|
|
1510
|
+
restoreUnanchoredCursor();
|
|
1348
1511
|
for (let i = 0; i < renderedLineCount; i++) {
|
|
1349
1512
|
output.write("\x1B[1A\x1B[2K");
|
|
1350
1513
|
}
|
|
@@ -1358,13 +1521,13 @@ async function runAskChoiceDialog(args) {
|
|
|
1358
1521
|
}
|
|
1359
1522
|
if (result.answers.length === 1) {
|
|
1360
1523
|
const a = result.answers[0];
|
|
1524
|
+
const q = normalized.questions[0];
|
|
1525
|
+
const labels = a.selectedIds.map((id) => q.choices.find((c) => c.id === id)?.label ?? "").filter(Boolean);
|
|
1526
|
+
if (a.otherText) labels.push(a.otherText);
|
|
1361
1527
|
return {
|
|
1362
1528
|
kind: "selected",
|
|
1363
1529
|
userMessage: a.userMessage,
|
|
1364
|
-
label:
|
|
1365
|
-
const q = normalized.questions[0];
|
|
1366
|
-
return q.choices.find((c) => c.id === id)?.label ?? "";
|
|
1367
|
-
}).join(", ") || a.otherText || ""
|
|
1530
|
+
label: labels.join(", ") || a.otherText || ""
|
|
1368
1531
|
};
|
|
1369
1532
|
}
|
|
1370
1533
|
return {
|
|
@@ -1422,8 +1585,13 @@ function createActivityIndicator(deps) {
|
|
|
1422
1585
|
let lastActivityAt = 0;
|
|
1423
1586
|
let frameIndex = 0;
|
|
1424
1587
|
let timer = null;
|
|
1588
|
+
let stopping = false;
|
|
1425
1589
|
const elapsedSecFrom = (startedAt) => startedAt > 0 ? Math.max(0, Math.floor((now() - startedAt) / 1e3)) : 0;
|
|
1426
1590
|
const tick = () => {
|
|
1591
|
+
if (stopping) {
|
|
1592
|
+
deps.onRepaint();
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1427
1595
|
frameIndex += 1;
|
|
1428
1596
|
if (explicitLabel === null && !fallbackActive && deps.isTurnActive() && lastActivityAt > 0 && now() - lastActivityAt >= fallbackDelayMs) {
|
|
1429
1597
|
fallbackActive = true;
|
|
@@ -1452,9 +1620,21 @@ function createActivityIndicator(deps) {
|
|
|
1452
1620
|
ensureTimer();
|
|
1453
1621
|
deps.onRepaint();
|
|
1454
1622
|
};
|
|
1623
|
+
const markStopping = () => {
|
|
1624
|
+
stopping = true;
|
|
1625
|
+
deps.onRepaint();
|
|
1626
|
+
};
|
|
1627
|
+
const isStopping = () => stopping;
|
|
1455
1628
|
const getView = () => {
|
|
1456
1629
|
if (!deps.isTurnActive()) return null;
|
|
1457
1630
|
const frame = ACTIVITY_FRAMES[frameIndex % ACTIVITY_FRAMES.length];
|
|
1631
|
+
if (stopping) {
|
|
1632
|
+
return {
|
|
1633
|
+
frame,
|
|
1634
|
+
label: deps.stoppingLabel(),
|
|
1635
|
+
elapsedSec: 0
|
|
1636
|
+
};
|
|
1637
|
+
}
|
|
1458
1638
|
if (explicitLabel !== null) {
|
|
1459
1639
|
return {
|
|
1460
1640
|
frame,
|
|
@@ -1481,8 +1661,9 @@ function createActivityIndicator(deps) {
|
|
|
1481
1661
|
fallbackActive = false;
|
|
1482
1662
|
fallbackStartedAt = 0;
|
|
1483
1663
|
lastActivityAt = 0;
|
|
1664
|
+
stopping = false;
|
|
1484
1665
|
};
|
|
1485
|
-
return { report, getView, stop };
|
|
1666
|
+
return { report, getView, markStopping, isStopping, stop };
|
|
1486
1667
|
}
|
|
1487
1668
|
|
|
1488
1669
|
// packages/ai/agent/utils/sortUtils.ts
|
|
@@ -1533,12 +1714,12 @@ function sortAgentsFavoriteOwnedPublic(items) {
|
|
|
1533
1714
|
// packages/cli/tui/agentCatalog.ts
|
|
1534
1715
|
var DEFAULT_TUI_AGENT_KEY = "agent-pub-01NOLOAPPBLD000000019KCKT0";
|
|
1535
1716
|
function formatAgentSourceLabel(entry) {
|
|
1536
|
-
if (entry.kind === "platform" || entry.apiSource === "platform") return "
|
|
1717
|
+
if (entry.kind === "platform" || entry.apiSource === "platform") return t("agentSourcePlatform");
|
|
1537
1718
|
if (entry.apiSource === "cli") {
|
|
1538
|
-
return entry.cliProvider ?
|
|
1719
|
+
return entry.cliProvider ? `${t("agentSourceSubscription")}(${entry.cliProvider})` : t("agentSourceSubscription");
|
|
1539
1720
|
}
|
|
1540
|
-
if (entry.apiSource === "custom") return "
|
|
1541
|
-
return "
|
|
1721
|
+
if (entry.apiSource === "custom") return t("agentSourceApi");
|
|
1722
|
+
return t("agentSourcePlatform");
|
|
1542
1723
|
}
|
|
1543
1724
|
var PLATFORM_AGENTS = [
|
|
1544
1725
|
{
|
|
@@ -1722,13 +1903,25 @@ function findAgentCatalogEntry(entries, rawTarget) {
|
|
|
1722
1903
|
if (!target) return null;
|
|
1723
1904
|
if (/^\d+$/.test(target)) {
|
|
1724
1905
|
const entry = entries[Number(target) - 1];
|
|
1725
|
-
return entry ? {
|
|
1906
|
+
return entry ? {
|
|
1907
|
+
name: entry.name,
|
|
1908
|
+
key: entry.key,
|
|
1909
|
+
model: entry.model,
|
|
1910
|
+
...entry.apiSource ? { apiSource: entry.apiSource } : entry.kind === "platform" ? { apiSource: "platform" } : {}
|
|
1911
|
+
} : null;
|
|
1726
1912
|
}
|
|
1727
1913
|
const lower = target.toLowerCase();
|
|
1728
1914
|
const byName = entries.find(
|
|
1729
1915
|
(entry) => entry.name.toLowerCase() === lower || entry.key.toLowerCase() === lower || entry.key.toLowerCase().endsWith(`-${lower}`)
|
|
1730
1916
|
);
|
|
1731
|
-
if (byName)
|
|
1917
|
+
if (byName) {
|
|
1918
|
+
return {
|
|
1919
|
+
name: byName.name,
|
|
1920
|
+
key: byName.key,
|
|
1921
|
+
model: byName.model,
|
|
1922
|
+
...byName.apiSource ? { apiSource: byName.apiSource } : byName.kind === "platform" ? { apiSource: "platform" } : {}
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1732
1925
|
if (target.startsWith("agent-") || target.startsWith("agent-pub-")) {
|
|
1733
1926
|
return { name: target, key: target };
|
|
1734
1927
|
}
|
|
@@ -1787,6 +1980,8 @@ async function runAgentPicker(args) {
|
|
|
1787
1980
|
kind: "selected",
|
|
1788
1981
|
name: selected.name,
|
|
1789
1982
|
key: selected.key,
|
|
1983
|
+
model: selected.model,
|
|
1984
|
+
apiSource: selected.apiSource ?? (selected.kind === "platform" ? "platform" : void 0),
|
|
1790
1985
|
entries
|
|
1791
1986
|
};
|
|
1792
1987
|
}
|
|
@@ -1796,7 +1991,11 @@ function resolveAgentSwitchTarget(rawTarget, catalogEntries = []) {
|
|
|
1796
1991
|
const aliasEntry = catalogEntries.find((entry) => entry.key === resolvedKey);
|
|
1797
1992
|
return {
|
|
1798
1993
|
name: aliasEntry?.name ?? asTrimmedLowercaseString(rawTarget),
|
|
1799
|
-
key: resolvedKey
|
|
1994
|
+
key: resolvedKey,
|
|
1995
|
+
...aliasEntry?.model ? { model: aliasEntry.model } : {},
|
|
1996
|
+
...aliasEntry ? {
|
|
1997
|
+
...aliasEntry.apiSource ? { apiSource: aliasEntry.apiSource } : aliasEntry.kind === "platform" ? { apiSource: "platform" } : {}
|
|
1998
|
+
} : {}
|
|
1800
1999
|
};
|
|
1801
2000
|
}
|
|
1802
2001
|
return findAgentCatalogEntry(catalogEntries, rawTarget);
|
|
@@ -1809,10 +2008,10 @@ function formatDialogTimestamp(value, now = Date.now()) {
|
|
|
1809
2008
|
const time = typeof value === "number" ? value : Date.parse(value);
|
|
1810
2009
|
if (!Number.isFinite(time) || time <= 0) return "";
|
|
1811
2010
|
const deltaSeconds = Math.max(0, Math.floor((now - time) / 1e3));
|
|
1812
|
-
if (deltaSeconds < 60) return "
|
|
1813
|
-
if (deltaSeconds < 3600) return
|
|
1814
|
-
if (deltaSeconds < 86400) return
|
|
1815
|
-
if (deltaSeconds < 30 * 86400) return
|
|
2011
|
+
if (deltaSeconds < 60) return t("timeJustNow");
|
|
2012
|
+
if (deltaSeconds < 3600) return t("timeMinutesAgo", String(Math.floor(deltaSeconds / 60)));
|
|
2013
|
+
if (deltaSeconds < 86400) return t("timeHoursAgo", String(Math.floor(deltaSeconds / 3600)));
|
|
2014
|
+
if (deltaSeconds < 30 * 86400) return t("timeDaysAgo", String(Math.floor(deltaSeconds / 86400)));
|
|
1816
2015
|
const date = new Date(time);
|
|
1817
2016
|
const pad = (part) => String(part).padStart(2, "0");
|
|
1818
2017
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
@@ -1829,7 +2028,7 @@ function toDialogPickerItems(dialogs) {
|
|
|
1829
2028
|
}
|
|
1830
2029
|
function renderDialogList(dialogs) {
|
|
1831
2030
|
if (dialogs.length === 0) return t("noDialogsYet");
|
|
1832
|
-
const lines = ["
|
|
2031
|
+
const lines = [t("recentDialogs")];
|
|
1833
2032
|
for (const [index, dialog] of dialogs.entries()) {
|
|
1834
2033
|
const stamp = formatDialogTimestamp(dialog.updatedAt ?? dialog.createdAt);
|
|
1835
2034
|
lines.push(
|
|
@@ -1837,7 +2036,7 @@ function renderDialogList(dialogs) {
|
|
|
1837
2036
|
` id=${dialog.id}`
|
|
1838
2037
|
);
|
|
1839
2038
|
}
|
|
1840
|
-
lines.push("", "
|
|
2039
|
+
lines.push("", t("dialogListTip"));
|
|
1841
2040
|
return lines.join("\n");
|
|
1842
2041
|
}
|
|
1843
2042
|
async function fetchRecentDialogs(args) {
|
|
@@ -1918,7 +2117,7 @@ async function runDialogPicker(args) {
|
|
|
1918
2117
|
}
|
|
1919
2118
|
|
|
1920
2119
|
// packages/cli/tui/pasteImage.ts
|
|
1921
|
-
import { existsSync } from "node:fs";
|
|
2120
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
1922
2121
|
import { readFile, stat } from "node:fs/promises";
|
|
1923
2122
|
import { homedir } from "node:os";
|
|
1924
2123
|
import { isAbsolute, resolve } from "node:path";
|
|
@@ -1973,7 +2172,7 @@ function detectImagePaths(line, cwd) {
|
|
|
1973
2172
|
if (!token.raw) continue;
|
|
1974
2173
|
const resolved = resolveImageSource(token.decoded, cwd);
|
|
1975
2174
|
if (!isImagePath(resolved)) continue;
|
|
1976
|
-
if (!
|
|
2175
|
+
if (!existsSync2(resolved)) continue;
|
|
1977
2176
|
out.push({ raw: token.raw, resolvedPath: resolved });
|
|
1978
2177
|
}
|
|
1979
2178
|
return out;
|
|
@@ -2156,302 +2355,48 @@ async function readImagePaths(paths, options = {}) {
|
|
|
2156
2355
|
}
|
|
2157
2356
|
|
|
2158
2357
|
// packages/cli/tui/gitStatus.ts
|
|
2159
|
-
import { execSync } from "node:child_process";
|
|
2160
|
-
function
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
return { branch, modified, untracked };
|
|
2187
|
-
} catch {
|
|
2188
|
-
return void 0;
|
|
2189
|
-
}
|
|
2190
|
-
}
|
|
2191
|
-
|
|
2192
|
-
// packages/cli/tui/tuiAnsi.ts
|
|
2193
|
-
var ANSI_ESCAPE_REGEX = /\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/g;
|
|
2194
|
-
var OSC_HYPERLINK_REGEX = /\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)\x1b\]8;;(?:\x07|\x1b\\)|\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/g;
|
|
2195
|
-
function stripAnsi(text) {
|
|
2196
|
-
return text.replace(OSC_HYPERLINK_REGEX, "").replace(ANSI_ESCAPE_REGEX, "");
|
|
2197
|
-
}
|
|
2198
|
-
var SGR_SEQUENCE_REGEX = /^\x1b\[[0-9;]*m/;
|
|
2199
|
-
var TRAILING_SGR_REGEX = /(?:\x1b\[[0-9;]*m)+$/;
|
|
2200
|
-
function applyTerminalOutputToText(existing, chunk) {
|
|
2201
|
-
if (!chunk) return existing;
|
|
2202
|
-
let text = existing;
|
|
2203
|
-
let index = 0;
|
|
2204
|
-
while (index < chunk.length) {
|
|
2205
|
-
if (chunk[index] === "\x1B") {
|
|
2206
|
-
const sgr = SGR_SEQUENCE_REGEX.exec(chunk.slice(index));
|
|
2207
|
-
if (sgr) {
|
|
2208
|
-
text += sgr[0];
|
|
2209
|
-
index += sgr[0].length;
|
|
2210
|
-
continue;
|
|
2211
|
-
}
|
|
2212
|
-
const osc = chunk.slice(index).match(/^\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/);
|
|
2213
|
-
if (osc) {
|
|
2214
|
-
index += osc[0].length;
|
|
2215
|
-
continue;
|
|
2216
|
-
}
|
|
2217
|
-
const csi = chunk.slice(index).match(/^\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/);
|
|
2218
|
-
if (csi) {
|
|
2219
|
-
index += csi[0].length;
|
|
2220
|
-
continue;
|
|
2221
|
-
}
|
|
2222
|
-
index += 1;
|
|
2223
|
-
continue;
|
|
2224
|
-
}
|
|
2225
|
-
const ch = chunk[index];
|
|
2226
|
-
if (ch === "\r") {
|
|
2227
|
-
const lastNl = text.lastIndexOf("\n");
|
|
2228
|
-
text = lastNl === -1 ? "" : text.slice(0, lastNl + 1);
|
|
2229
|
-
index += 1;
|
|
2230
|
-
continue;
|
|
2231
|
-
}
|
|
2232
|
-
if (ch === "\n") {
|
|
2233
|
-
text += "\n";
|
|
2234
|
-
index += 1;
|
|
2235
|
-
continue;
|
|
2236
|
-
}
|
|
2237
|
-
if (ch === "\b") {
|
|
2238
|
-
const trailing = TRAILING_SGR_REGEX.exec(text);
|
|
2239
|
-
const sgrTail = trailing ? trailing[0] : "";
|
|
2240
|
-
const head = sgrTail ? text.slice(0, -sgrTail.length) : text;
|
|
2241
|
-
if (head.length > 0 && head[head.length - 1] !== "\n") {
|
|
2242
|
-
text = head.slice(0, -1) + sgrTail;
|
|
2243
|
-
}
|
|
2244
|
-
index += 1;
|
|
2245
|
-
continue;
|
|
2246
|
-
}
|
|
2247
|
-
const code = ch.charCodeAt(0);
|
|
2248
|
-
if (code < 32 && ch !== " " || code === 127) {
|
|
2249
|
-
index += 1;
|
|
2250
|
-
continue;
|
|
2251
|
-
}
|
|
2252
|
-
text += ch;
|
|
2253
|
-
index += 1;
|
|
2254
|
-
}
|
|
2255
|
-
return text;
|
|
2256
|
-
}
|
|
2257
|
-
function displayWidth2(str) {
|
|
2258
|
-
let width = 0;
|
|
2259
|
-
for (const char of str) {
|
|
2260
|
-
const code = char.codePointAt(0) ?? 0;
|
|
2261
|
-
if (code < 32 || code === 127) continue;
|
|
2262
|
-
if (code >= 4352 && code <= 4447 || // 0x2768-0x2775 (ornamental brackets, incl. the ❯ prompt at U+276F)
|
|
2263
|
-
// render narrow in terminals; counting them wide drifts the cursor.
|
|
2264
|
-
code >= 9728 && code <= 10175 && !(code >= 10088 && code <= 10101) || // 0x2B00-0x2BFF (Misc Symbols and Arrows, incl. ⬢ U+2B22 used as the
|
|
2265
|
-
// status-line agent icon) render double-wide in common monospace fonts;
|
|
2266
|
-
// counting ⬢ as width 1 drifts the whole status line right of the icon.
|
|
2267
|
-
code >= 11008 && code <= 11263 || code >= 11904 && code <= 12350 || code >= 12352 && code <= 13247 || code >= 13312 && code <= 19903 || code >= 19968 && code <= 42191 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65072 && code <= 65135 || code >= 65281 && code <= 65376 || code >= 65504 && code <= 65510 || code >= 127744 && code <= 129791 || code >= 131072 && code <= 196605 || code >= 196608 && code <= 262141 || // East Asian Ambiguous CJK quotation marks (U+201C/D “ ”, U+2018/9 ‘ ’).
|
|
2268
|
-
// In CJK locale + CJK fonts these render double-wide like 全角 punctuation;
|
|
2269
|
-
// in English fonts they stay width 1. Follow the active locale so Chinese
|
|
2270
|
-
// replies align correctly without breaking English terminal output.
|
|
2271
|
-
getCliLocale() === "zh" && (code === 8220 || code === 8221 || code === 8216 || code === 8217)) {
|
|
2272
|
-
width += 2;
|
|
2273
|
-
} else {
|
|
2274
|
-
width += 1;
|
|
2275
|
-
}
|
|
2276
|
-
}
|
|
2277
|
-
return width;
|
|
2278
|
-
}
|
|
2279
|
-
function visibleWidth(str) {
|
|
2280
|
-
return displayWidth2(stripAnsi(str));
|
|
2281
|
-
}
|
|
2282
|
-
function truncateAnsi(text, maxWidth) {
|
|
2283
|
-
if (maxWidth <= 0) return "";
|
|
2284
|
-
if (visibleWidth(text) <= maxWidth) return text;
|
|
2285
|
-
let width = 0;
|
|
2286
|
-
let out = "";
|
|
2287
|
-
let i = 0;
|
|
2288
|
-
let sawAnsi = false;
|
|
2289
|
-
while (i < text.length) {
|
|
2290
|
-
if (text[i] === "\x1B" && text[i + 1] === "[") {
|
|
2291
|
-
sawAnsi = true;
|
|
2292
|
-
let j = i + 2;
|
|
2293
|
-
while (j < text.length) {
|
|
2294
|
-
const code = text.charCodeAt(j);
|
|
2295
|
-
j += 1;
|
|
2296
|
-
if (code >= 64 && code <= 126) break;
|
|
2297
|
-
}
|
|
2298
|
-
out += text.slice(i, j);
|
|
2299
|
-
i = j;
|
|
2300
|
-
continue;
|
|
2301
|
-
}
|
|
2302
|
-
const codePoint = text.codePointAt(i) ?? 0;
|
|
2303
|
-
const char = String.fromCodePoint(codePoint);
|
|
2304
|
-
const charWidth = displayWidth2(char);
|
|
2305
|
-
if (width + charWidth > maxWidth) break;
|
|
2306
|
-
out += char;
|
|
2307
|
-
width += charWidth;
|
|
2308
|
-
i += char.length;
|
|
2309
|
-
}
|
|
2310
|
-
return sawAnsi ? `${out}\x1B[0m` : out;
|
|
2311
|
-
}
|
|
2312
|
-
function fitAnsiLine(text, width, ellipsis = "\u2026") {
|
|
2313
|
-
if (width <= 0) return "";
|
|
2314
|
-
if (visibleWidth(text) <= width) return text;
|
|
2315
|
-
const ellipsisWidth = displayWidth2(ellipsis);
|
|
2316
|
-
if (width < ellipsisWidth) return truncateAnsi(text, width);
|
|
2317
|
-
if (width === ellipsisWidth) return truncateAnsi(ellipsis, width) || truncateAnsi(text, width);
|
|
2318
|
-
return `${truncateAnsi(text, width - ellipsisWidth)}${ellipsis}`;
|
|
2319
|
-
}
|
|
2320
|
-
function countPhysicalLines(text, columns) {
|
|
2321
|
-
const lines = text.split("\n");
|
|
2322
|
-
let total = 0;
|
|
2323
|
-
for (const line of lines) {
|
|
2324
|
-
const width = displayWidth2(line);
|
|
2325
|
-
total += Math.max(1, Math.ceil(width / columns));
|
|
2326
|
-
}
|
|
2327
|
-
return Math.max(total, 1);
|
|
2328
|
-
}
|
|
2329
|
-
function takeDisplayWidth(text, width) {
|
|
2330
|
-
let used = 0;
|
|
2331
|
-
let index = 0;
|
|
2332
|
-
for (const char of text) {
|
|
2333
|
-
const charWidth = displayWidth2(char);
|
|
2334
|
-
if (used + charWidth > width && used > 0) break;
|
|
2335
|
-
used += charWidth;
|
|
2336
|
-
index += char.length;
|
|
2337
|
-
}
|
|
2338
|
-
return { prefix: text.slice(0, index), rest: text.slice(index) };
|
|
2339
|
-
}
|
|
2340
|
-
function padOrTruncateToWidth(text, width) {
|
|
2341
|
-
const textWidth = visibleWidth(text);
|
|
2342
|
-
if (textWidth > width) {
|
|
2343
|
-
return truncateAnsi(text, width);
|
|
2344
|
-
}
|
|
2345
|
-
return `${text}${" ".repeat(width - textWidth)}`;
|
|
2346
|
-
}
|
|
2347
|
-
var SGR_RESET_REGEX = /^\x1b\[0?m$/;
|
|
2348
|
-
function tokenizeAnsiLine(line) {
|
|
2349
|
-
const tokens = [];
|
|
2350
|
-
let index = 0;
|
|
2351
|
-
while (index < line.length) {
|
|
2352
|
-
if (line[index] === "\x1B") {
|
|
2353
|
-
const osc = line.slice(index).match(/^\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/);
|
|
2354
|
-
if (osc) {
|
|
2355
|
-
tokens.push({ kind: "sgr", value: osc[0], width: 0 });
|
|
2356
|
-
index += osc[0].length;
|
|
2357
|
-
continue;
|
|
2358
|
-
}
|
|
2359
|
-
const sgr = SGR_SEQUENCE_REGEX.exec(line.slice(index));
|
|
2360
|
-
if (sgr) {
|
|
2361
|
-
tokens.push({ kind: "sgr", value: sgr[0], width: 0 });
|
|
2362
|
-
index += sgr[0].length;
|
|
2363
|
-
continue;
|
|
2364
|
-
}
|
|
2365
|
-
}
|
|
2366
|
-
const codePoint = line.codePointAt(index) ?? 0;
|
|
2367
|
-
const value = String.fromCodePoint(codePoint);
|
|
2368
|
-
tokens.push({ kind: "char", value, width: displayWidth2(value) });
|
|
2369
|
-
index += value.length;
|
|
2370
|
-
}
|
|
2371
|
-
return tokens;
|
|
2372
|
-
}
|
|
2373
|
-
function wrapTranscriptLine(line, columns) {
|
|
2374
|
-
if (line === "") return [""];
|
|
2375
|
-
const tokens = tokenizeAnsiLine(line);
|
|
2376
|
-
const result = [];
|
|
2377
|
-
let activeStyles = [];
|
|
2378
|
-
const applyStyleToken = (value) => {
|
|
2379
|
-
if (SGR_RESET_REGEX.test(value)) {
|
|
2380
|
-
activeStyles = [];
|
|
2381
|
-
} else {
|
|
2382
|
-
activeStyles.push(value);
|
|
2383
|
-
}
|
|
2384
|
-
};
|
|
2385
|
-
let start = 0;
|
|
2386
|
-
while (start < tokens.length) {
|
|
2387
|
-
if (tokens.slice(start).every((token) => token.kind === "sgr")) {
|
|
2388
|
-
if (result.length > 0) break;
|
|
2389
|
-
}
|
|
2390
|
-
const openingStyles = [...activeStyles];
|
|
2391
|
-
let width = 0;
|
|
2392
|
-
let end = start;
|
|
2393
|
-
let lastBreak = -1;
|
|
2394
|
-
while (end < tokens.length) {
|
|
2395
|
-
const token = tokens[end];
|
|
2396
|
-
if (token.kind === "sgr") {
|
|
2397
|
-
end += 1;
|
|
2398
|
-
continue;
|
|
2399
|
-
}
|
|
2400
|
-
if (width + token.width > columns && width > 0) break;
|
|
2401
|
-
width += token.width;
|
|
2402
|
-
end += 1;
|
|
2403
|
-
if (token.value === " " || token.value === " ") {
|
|
2404
|
-
lastBreak = end;
|
|
2405
|
-
}
|
|
2406
|
-
}
|
|
2407
|
-
let segmentEnd = end;
|
|
2408
|
-
if (end < tokens.length && lastBreak > start) {
|
|
2409
|
-
const overflowToken = tokens[end];
|
|
2410
|
-
if (overflowToken.kind === "char" && overflowToken.value !== " " && overflowToken.width === 1) {
|
|
2411
|
-
segmentEnd = lastBreak;
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
if (segmentEnd === start) segmentEnd = start + 1;
|
|
2415
|
-
let segment = "";
|
|
2416
|
-
let sawStyle = openingStyles.length > 0;
|
|
2417
|
-
for (let i = start; i < segmentEnd; i += 1) {
|
|
2418
|
-
const token = tokens[i];
|
|
2419
|
-
segment += token.value;
|
|
2420
|
-
if (token.kind === "sgr") {
|
|
2421
|
-
sawStyle = true;
|
|
2422
|
-
applyStyleToken(token.value);
|
|
2423
|
-
}
|
|
2424
|
-
}
|
|
2425
|
-
const prefix = openingStyles.join("");
|
|
2426
|
-
const needsReset = (sawStyle || activeStyles.length > 0) && !segment.endsWith("\x1B[0m");
|
|
2427
|
-
result.push(`${prefix}${segment}${needsReset ? "\x1B[0m" : ""}`);
|
|
2428
|
-
start = segmentEnd;
|
|
2429
|
-
while (start < tokens.length) {
|
|
2430
|
-
const token = tokens[start];
|
|
2431
|
-
if (token.kind === "char" && token.value === " ") {
|
|
2432
|
-
start += 1;
|
|
2433
|
-
continue;
|
|
2358
|
+
import { execFile, execSync } from "node:child_process";
|
|
2359
|
+
function parseStatusOutput(branch, status) {
|
|
2360
|
+
if (!status) {
|
|
2361
|
+
return { branch, modified: 0, untracked: 0 };
|
|
2362
|
+
}
|
|
2363
|
+
let modified = 0;
|
|
2364
|
+
let untracked = 0;
|
|
2365
|
+
for (const line of status.split("\n")) {
|
|
2366
|
+
if (!line) continue;
|
|
2367
|
+
const flag = line[0];
|
|
2368
|
+
if (flag === "?") untracked += 1;
|
|
2369
|
+
else modified += 1;
|
|
2370
|
+
}
|
|
2371
|
+
return { branch, modified, untracked };
|
|
2372
|
+
}
|
|
2373
|
+
function execFileUtf8(file, args, cwd) {
|
|
2374
|
+
return new Promise((resolve2, reject) => {
|
|
2375
|
+
execFile(
|
|
2376
|
+
file,
|
|
2377
|
+
args,
|
|
2378
|
+
{ cwd, encoding: "utf8", timeout: 2e3 },
|
|
2379
|
+
(err, stdout) => {
|
|
2380
|
+
if (err) {
|
|
2381
|
+
reject(err);
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
resolve2(typeof stdout === "string" ? stdout : String(stdout ?? ""));
|
|
2434
2385
|
}
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
}
|
|
2438
|
-
return result.length > 0 ? result : [""];
|
|
2386
|
+
);
|
|
2387
|
+
});
|
|
2439
2388
|
}
|
|
2440
|
-
function
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
const { prefix, rest } = takeDisplayWidth(remaining, columns);
|
|
2450
|
-
result.push(prefix);
|
|
2451
|
-
remaining = rest;
|
|
2389
|
+
function detectGitStatusAsync(cwd) {
|
|
2390
|
+
return (async () => {
|
|
2391
|
+
try {
|
|
2392
|
+
const branch = (await execFileUtf8("git", ["rev-parse", "--abbrev-ref", "HEAD"], cwd)).trim();
|
|
2393
|
+
if (!branch) return void 0;
|
|
2394
|
+
const status = (await execFileUtf8("git", ["status", "--porcelain"], cwd)).trim();
|
|
2395
|
+
return parseStatusOutput(branch, status);
|
|
2396
|
+
} catch {
|
|
2397
|
+
return void 0;
|
|
2452
2398
|
}
|
|
2453
|
-
}
|
|
2454
|
-
return result;
|
|
2399
|
+
})();
|
|
2455
2400
|
}
|
|
2456
2401
|
|
|
2457
2402
|
// packages/cli/tui/sessionRender.ts
|
|
@@ -2468,12 +2413,12 @@ function formatElapsedSeconds(totalSeconds) {
|
|
|
2468
2413
|
const mins = minutes % 60;
|
|
2469
2414
|
return `${hours}h ${mins}m`;
|
|
2470
2415
|
}
|
|
2471
|
-
function renderComposerTokenChip(tokens, fallbackContextWindow) {
|
|
2416
|
+
function renderComposerTokenChip(tokens, fallbackContextWindow, estimatedContextTokens) {
|
|
2472
2417
|
const cw = tokens?.contextWindow ?? fallbackContextWindow;
|
|
2473
2418
|
if (!cw) {
|
|
2474
2419
|
return "context: \u2014";
|
|
2475
2420
|
}
|
|
2476
|
-
const used = tokens ? tokens.input + tokens.output : 0;
|
|
2421
|
+
const used = tokens ? tokens.input + tokens.output : Math.max(0, estimatedContextTokens ?? 0);
|
|
2477
2422
|
const pct = Math.min(100, used / cw * 100);
|
|
2478
2423
|
const pctText = pct > 0 && pct < 10 ? pct.toFixed(1) : Math.round(pct).toString();
|
|
2479
2424
|
return `context: ${pctText}% (${formatTokenCount(used)}/${formatTokenCount(cw)})`;
|
|
@@ -2495,7 +2440,17 @@ function renderStatusLine(state) {
|
|
|
2495
2440
|
const untrackedText = untracked > 0 ? ` ${themeText(`?${untracked}`, "muted", colorEnabled)}` : "";
|
|
2496
2441
|
parts.push(`${branchText}${modifiedText}${untrackedText}`);
|
|
2497
2442
|
}
|
|
2498
|
-
const
|
|
2443
|
+
const credits = state.apiSource === "platform" ? state.turnTokens?.credits : void 0;
|
|
2444
|
+
const creditsSuffix = credits !== void 0 && credits > 0 ? ` \xB7 \u26A1 ${credits.toFixed(2)} \u79EF\u5206` : "";
|
|
2445
|
+
const tokenSegment = themeText(
|
|
2446
|
+
renderComposerTokenChip(
|
|
2447
|
+
state.turnTokens,
|
|
2448
|
+
state.contextWindow,
|
|
2449
|
+
state.estimatedContextTokens
|
|
2450
|
+
) + creditsSuffix,
|
|
2451
|
+
"muted",
|
|
2452
|
+
colorEnabled
|
|
2453
|
+
);
|
|
2499
2454
|
parts.push(tokenSegment);
|
|
2500
2455
|
const runningCount = getProcessRegistry().list().filter((p) => p.status === "running").length;
|
|
2501
2456
|
if (runningCount > 0) {
|
|
@@ -2577,7 +2532,7 @@ function renderWelcome(state, frame = 0, maxFrames = 0, columns) {
|
|
|
2577
2532
|
const isDark = brightness === "dark";
|
|
2578
2533
|
let sceneArt = colorEnabled ? buildColoredScene(isDark, frame, maxFrames) : buildPlainScene(isDark, frame, maxFrames);
|
|
2579
2534
|
if (typeof columns === "number" && columns > 0) {
|
|
2580
|
-
const widestSceneCol = sceneArt.split("\n").reduce((max, line) => Math.max(max,
|
|
2535
|
+
const widestSceneCol = sceneArt.split("\n").reduce((max, line) => Math.max(max, displayWidth(stripAnsi(line))), 0);
|
|
2581
2536
|
if (columns < widestSceneCol) sceneArt = "";
|
|
2582
2537
|
}
|
|
2583
2538
|
const versionLine = colorEnabled ? `\x1B[1m${themeColorSequence("accent")}nolo\x1B[0m ${state.cliVersion ?? ""} | server ${state.serverUrl}`.replace(" |", " |") : `nolo ${state.cliVersion ?? ""} | server ${state.serverUrl}`.replace(" |", " |");
|
|
@@ -2627,19 +2582,19 @@ function renderContextPanel(state, colorEnabled = resolveCliColorEnabled()) {
|
|
|
2627
2582
|
];
|
|
2628
2583
|
let maxW = 0;
|
|
2629
2584
|
for (const l of labels) {
|
|
2630
|
-
const w =
|
|
2585
|
+
const w = displayWidth(l);
|
|
2631
2586
|
if (w > maxW) maxW = w;
|
|
2632
2587
|
}
|
|
2633
2588
|
const targetWidth = maxW >= 9 ? maxW + 1 : 9;
|
|
2634
2589
|
const padLabel = (raw) => {
|
|
2635
|
-
const w =
|
|
2590
|
+
const w = displayWidth(raw);
|
|
2636
2591
|
const padding = " ".repeat(Math.max(0, targetWidth - w));
|
|
2637
2592
|
return raw + padding;
|
|
2638
2593
|
};
|
|
2639
2594
|
const field = (rawLabel, value) => `${themeText(padLabel(rawLabel), "muted", colorEnabled)}${value}`;
|
|
2640
2595
|
const next = (command, description) => ` ${themeText(command, "accent", colorEnabled)}${themeText(description, "muted", colorEnabled)}`;
|
|
2641
2596
|
const titleText = t("contextTitle");
|
|
2642
|
-
const heading = colorEnabled ? [renderDialogTitle(titleText, true)] : [titleText, "\u2500".repeat(
|
|
2597
|
+
const heading = colorEnabled ? [renderDialogTitle(titleText, true)] : [titleText, "\u2500".repeat(displayWidth(titleText))];
|
|
2643
2598
|
return [
|
|
2644
2599
|
...heading,
|
|
2645
2600
|
field(labels[0], `${state.agentName} (${state.agentKey})`),
|
|
@@ -2684,14 +2639,21 @@ function renderKnownAgents(colorEnabled = resolveCliColorEnabled()) {
|
|
|
2684
2639
|
|
|
2685
2640
|
// packages/cli/tui/sessionInput.ts
|
|
2686
2641
|
var PASTE_TOKEN_PREFIX = "\0PASTE\0";
|
|
2687
|
-
function applyTuiInputKey(buffer, sequence, key = {}, cursorPos) {
|
|
2642
|
+
function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
|
|
2688
2643
|
const seq = sequence ?? "";
|
|
2689
2644
|
const curPos = Math.max(0, Math.min(buffer.length, cursorPos ?? buffer.length));
|
|
2645
|
+
const pasteStore = options?.pasteStore;
|
|
2690
2646
|
if (seq.startsWith(PASTE_TOKEN_PREFIX)) {
|
|
2691
2647
|
const rawPayload = seq.slice(PASTE_TOKEN_PREFIX.length);
|
|
2692
2648
|
const normalized = rawPayload.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2693
|
-
const
|
|
2694
|
-
|
|
2649
|
+
const insertAt2 = snapCursorOutsidePasteChip(buffer, curPos);
|
|
2650
|
+
if (pasteStore && shouldCollapsePaste(normalized)) {
|
|
2651
|
+
const { placeholder } = allocateCollapsedPaste(pasteStore, normalized);
|
|
2652
|
+
const nextBuf3 = buffer.slice(0, insertAt2) + placeholder + buffer.slice(insertAt2);
|
|
2653
|
+
return { buffer: nextBuf3, cursorPos: insertAt2 + placeholder.length };
|
|
2654
|
+
}
|
|
2655
|
+
const nextBuf2 = buffer.slice(0, insertAt2) + normalized + buffer.slice(insertAt2);
|
|
2656
|
+
return { buffer: nextBuf2, cursorPos: insertAt2 + normalized.length };
|
|
2695
2657
|
}
|
|
2696
2658
|
if (seq === "" || key.ctrl && key.name === "c") {
|
|
2697
2659
|
return { buffer, cursorPos: curPos, abort: true };
|
|
@@ -2700,16 +2662,25 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos) {
|
|
|
2700
2662
|
return { buffer, cursorPos: curPos, copyView: true };
|
|
2701
2663
|
}
|
|
2702
2664
|
if (seq === "\x1B[13;2~" || seq === "\x1B[27;2;13~" || seq === "\x1B\r" || key.shift && (key.name === "enter" || key.name === "return") || seq === "\n" || key.ctrl && key.name === "j") {
|
|
2703
|
-
const
|
|
2704
|
-
|
|
2665
|
+
const insertAt2 = snapCursorOutsidePasteChip(buffer, curPos);
|
|
2666
|
+
const nextBuf2 = buffer.slice(0, insertAt2) + "\n" + buffer.slice(insertAt2);
|
|
2667
|
+
return { buffer: nextBuf2, cursorPos: insertAt2 + 1 };
|
|
2705
2668
|
}
|
|
2706
2669
|
if (key.name === "enter" || key.name === "return" || seq === "\r") {
|
|
2707
2670
|
return { buffer: "", cursorPos: 0, submit: buffer };
|
|
2708
2671
|
}
|
|
2709
2672
|
if (isLeftArrowSequence(seq, key)) {
|
|
2673
|
+
const span = findCollapsedPasteSpanAt(buffer, curPos, { preferLeft: true });
|
|
2674
|
+
if (span && curPos > span.start && curPos <= span.end) {
|
|
2675
|
+
return { buffer, cursorPos: span.start };
|
|
2676
|
+
}
|
|
2710
2677
|
return { buffer, cursorPos: Math.max(0, curPos - 1) };
|
|
2711
2678
|
}
|
|
2712
2679
|
if (isRightArrowSequence(seq, key)) {
|
|
2680
|
+
const span = findCollapsedPasteSpanAt(buffer, curPos);
|
|
2681
|
+
if (span && curPos >= span.start && curPos < span.end) {
|
|
2682
|
+
return { buffer, cursorPos: span.end };
|
|
2683
|
+
}
|
|
2713
2684
|
return { buffer, cursorPos: Math.min(buffer.length, curPos + 1) };
|
|
2714
2685
|
}
|
|
2715
2686
|
if (isHomeSequence(seq, key)) {
|
|
@@ -2720,24 +2691,33 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos) {
|
|
|
2720
2691
|
}
|
|
2721
2692
|
if (isDeleteWordSequence(seq, key)) {
|
|
2722
2693
|
if (curPos === 0) return { buffer, cursorPos: curPos };
|
|
2694
|
+
const pasteSpan = findCollapsedPasteSpanAt(buffer, curPos, {
|
|
2695
|
+
preferLeft: true
|
|
2696
|
+
});
|
|
2697
|
+
if (pasteSpan && (curPos === pasteSpan.end || curPos > pasteSpan.start && curPos < pasteSpan.end)) {
|
|
2698
|
+
return removePasteSpan(buffer, pasteSpan, pasteStore);
|
|
2699
|
+
}
|
|
2723
2700
|
const cutIdx = findWordStartLeft(buffer, curPos);
|
|
2724
|
-
|
|
2725
|
-
return { buffer: nextBuf2, cursorPos: cutIdx };
|
|
2701
|
+
return deleteBufferRange(buffer, cutIdx, curPos, pasteStore);
|
|
2726
2702
|
}
|
|
2727
2703
|
if (isKillToLineStartSequence(seq, key)) {
|
|
2728
2704
|
if (curPos === 0) return { buffer, cursorPos: curPos };
|
|
2729
2705
|
const lineStart = buffer.lastIndexOf("\n", curPos - 1) + 1;
|
|
2730
|
-
|
|
2731
|
-
return { buffer: nextBuf2, cursorPos: lineStart };
|
|
2706
|
+
return deleteBufferRange(buffer, lineStart, curPos, pasteStore);
|
|
2732
2707
|
}
|
|
2733
2708
|
if (isKillToLineEndSequence(seq, key)) {
|
|
2734
2709
|
const nlIdx = buffer.indexOf("\n", curPos);
|
|
2735
2710
|
const lineEnd = nlIdx === -1 ? buffer.length : nlIdx;
|
|
2736
|
-
|
|
2737
|
-
return { buffer: nextBuf2, cursorPos: curPos };
|
|
2711
|
+
return deleteBufferRange(buffer, curPos, lineEnd, pasteStore);
|
|
2738
2712
|
}
|
|
2739
2713
|
if (isBackspaceSequence(seq, key)) {
|
|
2740
2714
|
if (curPos > 0) {
|
|
2715
|
+
const pasteSpan = findCollapsedPasteSpanAt(buffer, curPos, {
|
|
2716
|
+
preferLeft: true
|
|
2717
|
+
});
|
|
2718
|
+
if (pasteSpan && (curPos === pasteSpan.end || curPos > pasteSpan.start && curPos < pasteSpan.end)) {
|
|
2719
|
+
return removePasteSpan(buffer, pasteSpan, pasteStore);
|
|
2720
|
+
}
|
|
2741
2721
|
const nextBuf2 = buffer.slice(0, curPos - 1) + buffer.slice(curPos);
|
|
2742
2722
|
return { buffer: nextBuf2, cursorPos: curPos - 1 };
|
|
2743
2723
|
}
|
|
@@ -2745,6 +2725,10 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos) {
|
|
|
2745
2725
|
}
|
|
2746
2726
|
if (isForwardDeleteSequence(seq, key)) {
|
|
2747
2727
|
if (curPos < buffer.length) {
|
|
2728
|
+
const pasteSpan = findCollapsedPasteSpanAt(buffer, curPos);
|
|
2729
|
+
if (pasteSpan && (curPos === pasteSpan.start || curPos > pasteSpan.start && curPos < pasteSpan.end)) {
|
|
2730
|
+
return removePasteSpan(buffer, pasteSpan, pasteStore);
|
|
2731
|
+
}
|
|
2748
2732
|
const nextBuf2 = buffer.slice(0, curPos) + buffer.slice(curPos + 1);
|
|
2749
2733
|
return { buffer: nextBuf2, cursorPos: curPos };
|
|
2750
2734
|
}
|
|
@@ -2761,8 +2745,14 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos) {
|
|
|
2761
2745
|
if (!seq || key.ctrl || key.meta || seq.startsWith("\x1B")) {
|
|
2762
2746
|
return { buffer, cursorPos: curPos };
|
|
2763
2747
|
}
|
|
2764
|
-
const
|
|
2765
|
-
|
|
2748
|
+
const insertAt = snapCursorOutsidePasteChip(buffer, curPos);
|
|
2749
|
+
const nextBuf = buffer.slice(0, insertAt) + seq + buffer.slice(insertAt);
|
|
2750
|
+
return { buffer: nextBuf, cursorPos: insertAt + seq.length };
|
|
2751
|
+
}
|
|
2752
|
+
function snapCursorOutsidePasteChip(buffer, pos) {
|
|
2753
|
+
const span = findCollapsedPasteSpanAt(buffer, pos);
|
|
2754
|
+
if (span && pos > span.start && pos < span.end) return span.end;
|
|
2755
|
+
return pos;
|
|
2766
2756
|
}
|
|
2767
2757
|
function isLeftArrowSequence(seq, key) {
|
|
2768
2758
|
if (key.name === "left") return true;
|
|
@@ -2786,13 +2776,44 @@ function isEndSequence(seq, key) {
|
|
|
2786
2776
|
if (seq === "" || seq === "\x1B[F" || seq === "\x1B[4~" || seq === "\x1B[8~" || seq === "\x1BOF") return true;
|
|
2787
2777
|
return false;
|
|
2788
2778
|
}
|
|
2779
|
+
function removePasteSpan(buffer, span, pasteStore) {
|
|
2780
|
+
if (pasteStore) releaseCollapsedPaste(pasteStore, span.id);
|
|
2781
|
+
const nextBuf = buffer.slice(0, span.start) + buffer.slice(span.end);
|
|
2782
|
+
return { buffer: nextBuf, cursorPos: span.start };
|
|
2783
|
+
}
|
|
2784
|
+
function deleteBufferRange(buffer, start, end, pasteStore) {
|
|
2785
|
+
if (start >= end) return { buffer, cursorPos: start };
|
|
2786
|
+
const range = expandRangeToCollapsedPasteChips(buffer, start, end);
|
|
2787
|
+
releasePastesInRange(buffer, range.start, range.end, pasteStore);
|
|
2788
|
+
const nextBuf = buffer.slice(0, range.start) + buffer.slice(range.end);
|
|
2789
|
+
return { buffer: nextBuf, cursorPos: range.start };
|
|
2790
|
+
}
|
|
2791
|
+
function releasePastesInRange(buffer, start, end, pasteStore) {
|
|
2792
|
+
if (!pasteStore || start >= end) return;
|
|
2793
|
+
const slice = buffer.slice(start, end);
|
|
2794
|
+
const re = /\[paste #(\d+) · (\d+) lines\]/g;
|
|
2795
|
+
let match;
|
|
2796
|
+
while ((match = re.exec(slice)) !== null) {
|
|
2797
|
+
releaseCollapsedPaste(pasteStore, Number(match[1]));
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2789
2800
|
var CJK_CHAR = /[\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]/;
|
|
2790
2801
|
function findWordStartLeft(buffer, curPos) {
|
|
2791
2802
|
let i = curPos;
|
|
2792
2803
|
while (i > 0 && /\s/.test(buffer[i - 1])) i--;
|
|
2793
2804
|
if (i === 0) return 0;
|
|
2805
|
+
const spanAtCursor = findCollapsedPasteSpanAt(buffer, i, {
|
|
2806
|
+
preferLeft: true
|
|
2807
|
+
});
|
|
2808
|
+
if (spanAtCursor && (i === spanAtCursor.end || i > spanAtCursor.start && i < spanAtCursor.end)) {
|
|
2809
|
+
return spanAtCursor.start;
|
|
2810
|
+
}
|
|
2794
2811
|
if (CJK_CHAR.test(buffer[i - 1])) return i - 1;
|
|
2795
|
-
while (i > 0 && !/\s/.test(buffer[i - 1]) && !CJK_CHAR.test(buffer[i - 1]))
|
|
2812
|
+
while (i > 0 && !/\s/.test(buffer[i - 1]) && !CJK_CHAR.test(buffer[i - 1])) {
|
|
2813
|
+
const span = findCollapsedPasteSpanAt(buffer, i, { preferLeft: true });
|
|
2814
|
+
if (span && i === span.end) break;
|
|
2815
|
+
i--;
|
|
2816
|
+
}
|
|
2796
2817
|
return i;
|
|
2797
2818
|
}
|
|
2798
2819
|
function isDeleteWordSequence(seq, key) {
|
|
@@ -2903,6 +2924,7 @@ function createInitialTuiState(env = process.env) {
|
|
|
2903
2924
|
) || void 0;
|
|
2904
2925
|
const dialogEnvValue = asOptionalTrimmedString(env.NOLO_DIALOG);
|
|
2905
2926
|
const explicitDialogKey = asOptionalTrimmedString(env.NOLO_DIALOG_KEY) ?? (dialogEnvValue?.startsWith("dialog-") ? dialogEnvValue : void 0);
|
|
2927
|
+
const autoRouteDefault = env.NOLO_AUTO_ROUTE !== "0";
|
|
2906
2928
|
return {
|
|
2907
2929
|
agentKey,
|
|
2908
2930
|
agentName,
|
|
@@ -2922,22 +2944,47 @@ function createInitialTuiState(env = process.env) {
|
|
|
2922
2944
|
attachedImages: [],
|
|
2923
2945
|
runtimeMode,
|
|
2924
2946
|
modeLabel: asOptionalTrimmedString(env.NOLO_CLI_STATUS_MODE) ?? runtimeMode,
|
|
2925
|
-
gitStatus:
|
|
2947
|
+
gitStatus: void 0,
|
|
2926
2948
|
thinkingDisplay: normalizeThinkingDisplayMode(
|
|
2927
2949
|
env.NOLO_CLI_THINKING ?? env.NOLO_THINKING,
|
|
2928
2950
|
"hide"
|
|
2929
2951
|
),
|
|
2930
2952
|
toolDisplay: normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "compact"),
|
|
2931
|
-
contextWindow:
|
|
2953
|
+
contextWindow: resolveAgentContextWindow({
|
|
2954
|
+
agentKey,
|
|
2955
|
+
agentName,
|
|
2956
|
+
autoRouteDefault
|
|
2957
|
+
}),
|
|
2958
|
+
estimatedContextTokens: estimateDefaultCliContextTokens({
|
|
2959
|
+
cwd,
|
|
2960
|
+
agentKey,
|
|
2961
|
+
agentName: autoRouteDefault ? "DeepSeek V4 Flash" : agentName,
|
|
2962
|
+
model: autoRouteDefault ? "deepseek-v4-flash" : void 0
|
|
2963
|
+
}),
|
|
2964
|
+
apiSource: PLATFORM_AGENTS.some((entry) => entry.key === agentKey) ? "platform" : void 0
|
|
2932
2965
|
};
|
|
2933
2966
|
}
|
|
2934
|
-
function applyAgentSwitch(state, target) {
|
|
2967
|
+
function applyAgentSwitch(state, target, opts) {
|
|
2968
|
+
const autoRouteDefault = opts?.autoRouteDefault ?? process.env.NOLO_AUTO_ROUTE !== "0";
|
|
2969
|
+
const contextWindow = resolveAgentContextWindow({
|
|
2970
|
+
agentKey: target.key,
|
|
2971
|
+
agentName: target.name,
|
|
2972
|
+
model: target.model,
|
|
2973
|
+
autoRouteDefault
|
|
2974
|
+
});
|
|
2935
2975
|
return {
|
|
2936
2976
|
nextState: {
|
|
2937
2977
|
...state,
|
|
2938
2978
|
agentName: target.name,
|
|
2939
2979
|
agentKey: target.key,
|
|
2940
|
-
contextWindow
|
|
2980
|
+
contextWindow,
|
|
2981
|
+
estimatedContextTokens: estimateDefaultCliContextTokens({
|
|
2982
|
+
cwd: state.cwd,
|
|
2983
|
+
agentKey: target.key,
|
|
2984
|
+
agentName: target.name,
|
|
2985
|
+
model: target.model
|
|
2986
|
+
}),
|
|
2987
|
+
apiSource: target.apiSource
|
|
2941
2988
|
},
|
|
2942
2989
|
output: `Switched to ${target.name}. ${state.dialogId ? `Dialog kept: ${state.dialogId}` : "Dialog kept: new"}`
|
|
2943
2990
|
};
|
|
@@ -2999,32 +3046,32 @@ function handleTuiInput(input, state) {
|
|
|
2999
3046
|
return {
|
|
3000
3047
|
nextState: state,
|
|
3001
3048
|
output: [
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3049
|
+
t("themeCurrent", getActiveThemeName(), brightness),
|
|
3050
|
+
t("themeUsage"),
|
|
3051
|
+
t("themeAvailable", available)
|
|
3005
3052
|
].join("\n")
|
|
3006
3053
|
};
|
|
3007
3054
|
}
|
|
3008
3055
|
if (sub === "light" || sub === "dark") {
|
|
3009
3056
|
setActiveBrightness(sub);
|
|
3010
|
-
return { nextState: state, output:
|
|
3057
|
+
return { nextState: state, output: t("themeBrightnessSwitched", sub) };
|
|
3011
3058
|
}
|
|
3012
3059
|
if (sub === "auto") {
|
|
3013
3060
|
setActiveBrightness(null);
|
|
3014
3061
|
return {
|
|
3015
3062
|
nextState: state,
|
|
3016
|
-
output:
|
|
3063
|
+
output: t("themeBrightnessAuto", resolveTuiBrightness())
|
|
3017
3064
|
};
|
|
3018
3065
|
}
|
|
3019
3066
|
if (setActiveThemeName(sub)) {
|
|
3020
3067
|
return {
|
|
3021
3068
|
nextState: state,
|
|
3022
|
-
output:
|
|
3069
|
+
output: t("themeSwitched", sub)
|
|
3023
3070
|
};
|
|
3024
3071
|
} else {
|
|
3025
3072
|
return {
|
|
3026
3073
|
nextState: state,
|
|
3027
|
-
output:
|
|
3074
|
+
output: t("themeUnknown", sub, available)
|
|
3028
3075
|
};
|
|
3029
3076
|
}
|
|
3030
3077
|
}
|
|
@@ -3034,20 +3081,19 @@ function handleTuiInput(input, state) {
|
|
|
3034
3081
|
if (!sub) {
|
|
3035
3082
|
return {
|
|
3036
3083
|
nextState: state,
|
|
3037
|
-
output:
|
|
3038
|
-
Usage: /density <cozy|spacious>`
|
|
3084
|
+
output: t("densityCurrent", getActiveDensity())
|
|
3039
3085
|
};
|
|
3040
3086
|
}
|
|
3041
3087
|
if (sub === "cozy" || sub === "spacious") {
|
|
3042
3088
|
setActiveDensity(sub);
|
|
3043
3089
|
return {
|
|
3044
3090
|
nextState: state,
|
|
3045
|
-
output:
|
|
3091
|
+
output: t("densitySwitched", sub)
|
|
3046
3092
|
};
|
|
3047
3093
|
} else {
|
|
3048
3094
|
return {
|
|
3049
3095
|
nextState: state,
|
|
3050
|
-
output:
|
|
3096
|
+
output: t("densityUnknown", sub)
|
|
3051
3097
|
};
|
|
3052
3098
|
}
|
|
3053
3099
|
}
|
|
@@ -3058,52 +3104,52 @@ Usage: /density <cozy|spacious>`
|
|
|
3058
3104
|
if (argText !== "auto" && argText !== "local" && argText !== "server") {
|
|
3059
3105
|
return {
|
|
3060
3106
|
nextState: state,
|
|
3061
|
-
output: "
|
|
3107
|
+
output: t("runtimeUsage")
|
|
3062
3108
|
};
|
|
3063
3109
|
}
|
|
3064
3110
|
return {
|
|
3065
3111
|
nextState: { ...state, runtimeMode: argText },
|
|
3066
|
-
output:
|
|
3112
|
+
output: t("runtimeSet", argText)
|
|
3067
3113
|
};
|
|
3068
3114
|
}
|
|
3069
3115
|
case "/tools": {
|
|
3070
3116
|
if (!argText) {
|
|
3071
3117
|
return {
|
|
3072
3118
|
nextState: state,
|
|
3073
|
-
output:
|
|
3119
|
+
output: t("toolsCurrent", state.toolDisplay)
|
|
3074
3120
|
};
|
|
3075
3121
|
}
|
|
3076
3122
|
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
3077
3123
|
if (!["hide", "compact", "verbose", "on", "off"].includes(normalizedArg)) {
|
|
3078
3124
|
return {
|
|
3079
3125
|
nextState: state,
|
|
3080
|
-
output: "
|
|
3126
|
+
output: t("toolsUsage")
|
|
3081
3127
|
};
|
|
3082
3128
|
}
|
|
3083
3129
|
const nextMode = normalizeToolDisplayMode(normalizedArg, state.toolDisplay);
|
|
3084
3130
|
return {
|
|
3085
3131
|
nextState: { ...state, toolDisplay: nextMode },
|
|
3086
|
-
output:
|
|
3132
|
+
output: t("toolsSet", nextMode)
|
|
3087
3133
|
};
|
|
3088
3134
|
}
|
|
3089
3135
|
case "/thinking": {
|
|
3090
3136
|
if (!argText) {
|
|
3091
3137
|
return {
|
|
3092
3138
|
nextState: state,
|
|
3093
|
-
output:
|
|
3139
|
+
output: t("thinkingCurrent", state.thinkingDisplay)
|
|
3094
3140
|
};
|
|
3095
3141
|
}
|
|
3096
3142
|
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
3097
3143
|
if (!["hide", "marker", "show", "on", "off"].includes(normalizedArg)) {
|
|
3098
3144
|
return {
|
|
3099
3145
|
nextState: state,
|
|
3100
|
-
output: "
|
|
3146
|
+
output: t("thinkingUsage")
|
|
3101
3147
|
};
|
|
3102
3148
|
}
|
|
3103
3149
|
const nextMode = normalizeThinkingDisplayMode(normalizedArg, state.thinkingDisplay);
|
|
3104
3150
|
return {
|
|
3105
3151
|
nextState: { ...state, thinkingDisplay: nextMode },
|
|
3106
|
-
output:
|
|
3152
|
+
output: t("thinkingSet", nextMode)
|
|
3107
3153
|
};
|
|
3108
3154
|
}
|
|
3109
3155
|
case "/tasks":
|
|
@@ -3115,14 +3161,14 @@ Usage: /density <cozy|spacious>`
|
|
|
3115
3161
|
const stopped = all.filter((p) => p.status !== "running");
|
|
3116
3162
|
const lines = [];
|
|
3117
3163
|
if (running.length > 0) {
|
|
3118
|
-
lines.push(
|
|
3164
|
+
lines.push(t("tasksRunning", String(running.length)));
|
|
3119
3165
|
for (const p of running) {
|
|
3120
3166
|
const elapsed = formatElapsedSeconds(Math.floor((Date.now() - p.startedAt) / 1e3));
|
|
3121
3167
|
lines.push(` pid ${p.pid} ${p.label} running ${elapsed}`);
|
|
3122
3168
|
}
|
|
3123
3169
|
}
|
|
3124
3170
|
if (stopped.length > 0) {
|
|
3125
|
-
lines.push(
|
|
3171
|
+
lines.push(t("tasksStopped", String(stopped.length)));
|
|
3126
3172
|
for (const p of stopped) {
|
|
3127
3173
|
const elapsed = formatElapsedSeconds(Math.floor((Date.now() - p.startedAt) / 1e3));
|
|
3128
3174
|
const exitInfo = p.exitCode !== void 0 ? ` exit ${p.exitCode}` : "";
|
|
@@ -3130,38 +3176,38 @@ Usage: /density <cozy|spacious>`
|
|
|
3130
3176
|
}
|
|
3131
3177
|
}
|
|
3132
3178
|
if (all.length === 0) {
|
|
3133
|
-
lines.push("
|
|
3179
|
+
lines.push(t("tasksNone"));
|
|
3134
3180
|
}
|
|
3135
3181
|
return { nextState: state, output: lines.join("\n") };
|
|
3136
3182
|
}
|
|
3137
3183
|
case "/stop": {
|
|
3138
3184
|
const registry = getProcessRegistry();
|
|
3139
3185
|
if (!argText) {
|
|
3140
|
-
return { nextState: state, output: "
|
|
3186
|
+
return { nextState: state, output: t("stopUsage") };
|
|
3141
3187
|
}
|
|
3142
3188
|
if (argText === "all") {
|
|
3143
3189
|
const before = registry.list().filter((p) => p.status === "running").length;
|
|
3144
3190
|
registry.stopAll();
|
|
3145
|
-
return { nextState: state, output:
|
|
3191
|
+
return { nextState: state, output: t("stopAllDone", String(before)) };
|
|
3146
3192
|
}
|
|
3147
3193
|
if (/^\d+$/.test(argText)) {
|
|
3148
3194
|
const pid = parseInt(argText, 10);
|
|
3149
3195
|
const proc = registry.get(pid);
|
|
3150
3196
|
if (!proc || proc.status !== "running") {
|
|
3151
|
-
return { nextState: state, output:
|
|
3197
|
+
return { nextState: state, output: t("stopNoPid", String(pid)) };
|
|
3152
3198
|
}
|
|
3153
3199
|
registry.kill(pid);
|
|
3154
|
-
return { nextState: state, output:
|
|
3200
|
+
return { nextState: state, output: t("stopPidDone", String(pid), proc.label) };
|
|
3155
3201
|
}
|
|
3156
3202
|
const matches = registry.list().filter((p) => p.status === "running" && p.label === argText);
|
|
3157
3203
|
if (matches.length === 0) {
|
|
3158
|
-
return { nextState: state, output:
|
|
3204
|
+
return { nextState: state, output: t("stopNoLabel", argText) };
|
|
3159
3205
|
}
|
|
3160
3206
|
for (const p of matches) {
|
|
3161
3207
|
registry.kill(p.pid);
|
|
3162
3208
|
}
|
|
3163
3209
|
const stoppedNames = matches.map((p) => `pid ${p.pid} (${p.label})`).join(", ");
|
|
3164
|
-
return { nextState: state, output:
|
|
3210
|
+
return { nextState: state, output: t("stopLabelsDone", stoppedNames) };
|
|
3165
3211
|
}
|
|
3166
3212
|
case "/exit":
|
|
3167
3213
|
case "/quit":
|
|
@@ -3185,15 +3231,13 @@ Usage: /density <cozy|spacious>`
|
|
|
3185
3231
|
if (argText) {
|
|
3186
3232
|
return {
|
|
3187
3233
|
nextState: state,
|
|
3188
|
-
output:
|
|
3189
|
-
|
|
3190
|
-
${renderTuiHelp()}`
|
|
3234
|
+
output: t("unknownCommand", trimmed) + renderTuiHelp()
|
|
3191
3235
|
};
|
|
3192
3236
|
}
|
|
3193
3237
|
if (!state.dialogId) {
|
|
3194
3238
|
return {
|
|
3195
3239
|
nextState: state,
|
|
3196
|
-
output: "
|
|
3240
|
+
output: t("compactNothing")
|
|
3197
3241
|
};
|
|
3198
3242
|
}
|
|
3199
3243
|
return {
|
|
@@ -3220,15 +3264,14 @@ ${renderTuiHelp()}`
|
|
|
3220
3264
|
if (argText === "current" || argText === "show") {
|
|
3221
3265
|
return {
|
|
3222
3266
|
nextState: state,
|
|
3223
|
-
output:
|
|
3267
|
+
output: t("agentCurrent", state.agentName, state.agentKey)
|
|
3224
3268
|
};
|
|
3225
3269
|
}
|
|
3226
3270
|
const resolvedTarget = resolveAgentSwitchTarget(argText, resolveCatalogPlatformAgents());
|
|
3227
3271
|
if (!resolvedTarget) {
|
|
3228
3272
|
return {
|
|
3229
3273
|
nextState: state,
|
|
3230
|
-
output:
|
|
3231
|
-
Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
3274
|
+
output: t("agentUnknown", argText)
|
|
3232
3275
|
};
|
|
3233
3276
|
}
|
|
3234
3277
|
return applyAgentSwitch(state, resolvedTarget);
|
|
@@ -3282,6 +3325,16 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
|
3282
3325
|
action: { type: "set-mouse", enabled: argText === "on" }
|
|
3283
3326
|
};
|
|
3284
3327
|
}
|
|
3328
|
+
case "/altscreen": {
|
|
3329
|
+
if (argText !== "on" && argText !== "off") {
|
|
3330
|
+
return { nextState: state, output: t("altscreenUsage") };
|
|
3331
|
+
}
|
|
3332
|
+
return {
|
|
3333
|
+
nextState: state,
|
|
3334
|
+
output: argText === "on" ? t("altscreenOn") : t("altscreenOff"),
|
|
3335
|
+
action: { type: "set-altscreen", enabled: argText === "on" }
|
|
3336
|
+
};
|
|
3337
|
+
}
|
|
3285
3338
|
case "/resume": {
|
|
3286
3339
|
if (!argText) {
|
|
3287
3340
|
return {
|
|
@@ -3311,7 +3364,7 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
|
3311
3364
|
if (rest[0] === "attach") {
|
|
3312
3365
|
const docName = rest.slice(1).join(" ").trim();
|
|
3313
3366
|
if (!docName) {
|
|
3314
|
-
return { nextState: state, output: "
|
|
3367
|
+
return { nextState: state, output: t("docAttachUsage") };
|
|
3315
3368
|
}
|
|
3316
3369
|
const attachedDocs = state.attachedDocs.includes(docName) ? state.attachedDocs : [...state.attachedDocs, docName];
|
|
3317
3370
|
return {
|
|
@@ -3321,7 +3374,7 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
|
3321
3374
|
}
|
|
3322
3375
|
return {
|
|
3323
3376
|
nextState: state,
|
|
3324
|
-
output: state.attachedDocs.length > 0 ?
|
|
3377
|
+
output: state.attachedDocs.length > 0 ? t("docList", state.attachedDocs.join(", ")) : t("docNone")
|
|
3325
3378
|
};
|
|
3326
3379
|
}
|
|
3327
3380
|
case "/skill": {
|
|
@@ -3329,7 +3382,7 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
|
3329
3382
|
if (sub === "attach") {
|
|
3330
3383
|
const skillRef = rest.slice(1).join(" ").trim();
|
|
3331
3384
|
if (!skillRef) {
|
|
3332
|
-
return { nextState: state, output: "
|
|
3385
|
+
return { nextState: state, output: t("skillAttachUsage") };
|
|
3333
3386
|
}
|
|
3334
3387
|
const attachedSkills = state.attachedSkills.includes(skillRef) ? state.attachedSkills : [...state.attachedSkills, skillRef];
|
|
3335
3388
|
return {
|
|
@@ -3340,38 +3393,37 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
|
3340
3393
|
if (sub === "detach") {
|
|
3341
3394
|
const skillRef = rest.slice(1).join(" ").trim();
|
|
3342
3395
|
if (!skillRef) {
|
|
3343
|
-
return { nextState: state, output: "
|
|
3396
|
+
return { nextState: state, output: t("skillDetachUsage") };
|
|
3344
3397
|
}
|
|
3345
3398
|
const attachedSkills = state.attachedSkills.filter((s) => s !== skillRef);
|
|
3346
3399
|
return {
|
|
3347
3400
|
nextState: { ...state, attachedSkills },
|
|
3348
|
-
output: state.attachedSkills.includes(skillRef) ?
|
|
3401
|
+
output: state.attachedSkills.includes(skillRef) ? t("skillDetached", skillRef) : t("skillNotAttached", skillRef)
|
|
3349
3402
|
};
|
|
3350
3403
|
}
|
|
3351
3404
|
if (sub === "clear") {
|
|
3352
3405
|
if (state.attachedSkills.length === 0) {
|
|
3353
|
-
return { nextState: state, output: "
|
|
3406
|
+
return { nextState: state, output: t("skillNone") };
|
|
3354
3407
|
}
|
|
3355
3408
|
return {
|
|
3356
3409
|
nextState: { ...state, attachedSkills: [] },
|
|
3357
|
-
output:
|
|
3410
|
+
output: t("skillCleared", String(state.attachedSkills.length))
|
|
3358
3411
|
};
|
|
3359
3412
|
}
|
|
3360
3413
|
return {
|
|
3361
3414
|
nextState: state,
|
|
3362
|
-
output: state.attachedSkills.length > 0 ?
|
|
3363
|
-
Usage: /skill attach <ref> | /skill detach <ref> | /skill clear` : "No skills attached. Use /skill attach <skill-ref> to attach a skill.\nSkill refs can be a dbKey (page-xxx), a skill name (searched in .agents/skills/ then docs/skills/), or a direct path."
|
|
3415
|
+
output: state.attachedSkills.length > 0 ? t("skillList", state.attachedSkills.join(", ")) : t("skillNoneHint")
|
|
3364
3416
|
};
|
|
3365
3417
|
}
|
|
3366
3418
|
case "/customize":
|
|
3367
3419
|
return {
|
|
3368
3420
|
nextState: state,
|
|
3369
|
-
output: "
|
|
3421
|
+
output: t("customizeHint")
|
|
3370
3422
|
};
|
|
3371
3423
|
case "/login":
|
|
3372
3424
|
return {
|
|
3373
3425
|
nextState: state,
|
|
3374
|
-
output: "
|
|
3426
|
+
output: t("loginHint")
|
|
3375
3427
|
};
|
|
3376
3428
|
case "/profile":
|
|
3377
3429
|
return {
|
|
@@ -3387,16 +3439,12 @@ Usage: /skill attach <ref> | /skill detach <ref> | /skill clear` : "No skills at
|
|
|
3387
3439
|
case "/version":
|
|
3388
3440
|
return {
|
|
3389
3441
|
nextState: state,
|
|
3390
|
-
output:
|
|
3391
|
-
Update this install with: nolo update
|
|
3392
|
-
If repo-local output differs, publish/install the latest npm package first.`
|
|
3442
|
+
output: t("versionInfo", state.cliVersion || t("versionUnknown"))
|
|
3393
3443
|
};
|
|
3394
3444
|
default:
|
|
3395
3445
|
return {
|
|
3396
3446
|
nextState: state,
|
|
3397
|
-
output:
|
|
3398
|
-
|
|
3399
|
-
${renderTuiHelp()}`
|
|
3447
|
+
output: t("unknownCommand", command) + renderTuiHelp()
|
|
3400
3448
|
};
|
|
3401
3449
|
}
|
|
3402
3450
|
}
|
|
@@ -3414,19 +3462,23 @@ function brightnessFromRgb(r, g, b) {
|
|
|
3414
3462
|
const luma = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
3415
3463
|
return luma >= 0.5 ? "light" : "dark";
|
|
3416
3464
|
}
|
|
3417
|
-
function
|
|
3465
|
+
function parseOsc11Background(reply) {
|
|
3418
3466
|
const match = reply.match(OSC11_REPLY_RE);
|
|
3419
3467
|
if (!match) return null;
|
|
3420
|
-
|
|
3468
|
+
const channels = [
|
|
3421
3469
|
componentToByte(match[1]),
|
|
3422
3470
|
componentToByte(match[2]),
|
|
3423
3471
|
componentToByte(match[3])
|
|
3424
|
-
|
|
3472
|
+
];
|
|
3473
|
+
return {
|
|
3474
|
+
brightness: brightnessFromRgb(channels[0], channels[1], channels[2]),
|
|
3475
|
+
hex: channels.map((v) => v.toString(16).padStart(2, "0").toUpperCase()).join("")
|
|
3476
|
+
};
|
|
3425
3477
|
}
|
|
3426
3478
|
function isTerminalDevice(stream) {
|
|
3427
3479
|
return stream instanceof ReadStream;
|
|
3428
3480
|
}
|
|
3429
|
-
async function
|
|
3481
|
+
async function detectTerminalBackground(args = {}) {
|
|
3430
3482
|
const stdin = args.stdin ?? process.stdin;
|
|
3431
3483
|
const stdout = args.stdout ?? process.stdout;
|
|
3432
3484
|
const timeoutMs = args.timeoutMs ?? 100;
|
|
@@ -3453,7 +3505,7 @@ async function detectTerminalBrightness(args = {}) {
|
|
|
3453
3505
|
};
|
|
3454
3506
|
const onData = (chunk) => {
|
|
3455
3507
|
buffer += chunk.toString("latin1");
|
|
3456
|
-
const parsed =
|
|
3508
|
+
const parsed = parseOsc11Background(buffer);
|
|
3457
3509
|
if (parsed) finish(parsed);
|
|
3458
3510
|
else if (buffer.length > 256) finish(null);
|
|
3459
3511
|
};
|
|
@@ -3747,6 +3799,7 @@ function createChatQueueTuiBinding(runTurn) {
|
|
|
3747
3799
|
|
|
3748
3800
|
// packages/cli/tui/tuiHistory.ts
|
|
3749
3801
|
var MAX_TUI_HISTORY_TURNS = 500;
|
|
3802
|
+
var turnLineCache = /* @__PURE__ */ new WeakMap();
|
|
3750
3803
|
function createTurnHistory() {
|
|
3751
3804
|
return {
|
|
3752
3805
|
turns: [],
|
|
@@ -3788,45 +3841,81 @@ function applyOutputChunkToCurrentTurn(history, chunk) {
|
|
|
3788
3841
|
history.currentContent = next;
|
|
3789
3842
|
return true;
|
|
3790
3843
|
}
|
|
3791
|
-
function
|
|
3792
|
-
const
|
|
3793
|
-
const
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
const
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
const anchorPrefix = colorEnabled ? `${themeColorSequence("chrome")}\u25C8\x1B[39m ` : "\u25C8 ";
|
|
3805
|
-
return `${anchorPrefix}${line}`;
|
|
3806
|
-
}
|
|
3807
|
-
return line.startsWith("[nolo]") && colorEnabled ? themeText(line, "chrome", true) : line;
|
|
3808
|
-
});
|
|
3809
|
-
return styledLines.join("\n");
|
|
3810
|
-
};
|
|
3844
|
+
function styleAssistantTurn(content, colorEnabled) {
|
|
3845
|
+
const highlighted = colorEnabled ? formatAssistantDisplay(content) : stripAnsi(formatAssistantDisplay(content));
|
|
3846
|
+
const rawLines = highlighted.split("\n");
|
|
3847
|
+
const styledLines = rawLines.map((line, idx) => {
|
|
3848
|
+
if (idx === 0 && !line.startsWith("[nolo]")) {
|
|
3849
|
+
const anchorPrefix = colorEnabled ? `${themeColorSequence("chrome")}\u25C8\x1B[39m ` : "\u25C8 ";
|
|
3850
|
+
return `${anchorPrefix}${line}`;
|
|
3851
|
+
}
|
|
3852
|
+
return line.startsWith("[nolo]") && colorEnabled ? themeText(line, "chrome", true) : line;
|
|
3853
|
+
});
|
|
3854
|
+
return styledLines.join("\n");
|
|
3855
|
+
}
|
|
3856
|
+
function renderTurnBlock(role, content, contentWidth, colorEnabled) {
|
|
3811
3857
|
const lines = [];
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3858
|
+
if (role === "user") {
|
|
3859
|
+
const logicalLines = content.split("\n");
|
|
3860
|
+
const accentSeq = colorEnabled ? themeColorSequence("accent") : "";
|
|
3861
|
+
const chromeSeq = colorEnabled ? themeColorSequence("chrome") : "";
|
|
3862
|
+
for (let i = 0; i < logicalLines.length; i++) {
|
|
3863
|
+
const line = logicalLines[i];
|
|
3864
|
+
let styledLine;
|
|
3865
|
+
if (colorEnabled) {
|
|
3866
|
+
const prefix = i === 0 ? `${accentSeq}\u276F\x1B[39m ` : `${chromeSeq}\u2502\x1B[39m `;
|
|
3867
|
+
styledLine = `${prefix}${line}`;
|
|
3868
|
+
} else {
|
|
3869
|
+
const prefix = i === 0 ? "\u276F " : " ";
|
|
3870
|
+
styledLine = `${prefix}${line}`;
|
|
3871
|
+
}
|
|
3872
|
+
lines.push(...wrapTranscriptLine(styledLine, contentWidth, " "));
|
|
3873
|
+
}
|
|
3874
|
+
} else {
|
|
3875
|
+
const styledEntry = styleAssistantTurn(content, colorEnabled);
|
|
3876
|
+
for (const logicalLine of styledEntry.split("\n")) {
|
|
3877
|
+
lines.push(...wrapTranscriptLine(logicalLine, contentWidth));
|
|
3815
3878
|
}
|
|
3816
|
-
lines.push(styleTurn(role, content));
|
|
3817
|
-
};
|
|
3818
|
-
for (const turn of history.turns) {
|
|
3819
|
-
pushTurn(turn.role, turn.content);
|
|
3820
|
-
}
|
|
3821
|
-
if (history.currentRole !== null && history.currentContent) {
|
|
3822
|
-
pushTurn(history.currentRole, history.currentContent);
|
|
3823
3879
|
}
|
|
3880
|
+
return lines;
|
|
3881
|
+
}
|
|
3882
|
+
function buildHistoryLines(history, contentWidth) {
|
|
3883
|
+
const colorEnabled = resolveCliColorEnabled();
|
|
3884
|
+
const density = getActiveDensity();
|
|
3824
3885
|
const wrapped = [];
|
|
3825
|
-
for (
|
|
3826
|
-
|
|
3827
|
-
|
|
3886
|
+
for (let i = 0; i < history.turns.length; i++) {
|
|
3887
|
+
const turn = history.turns[i];
|
|
3888
|
+
if (density === "spacious" && (i > 0 || turn.role === "user")) {
|
|
3889
|
+
wrapped.push("");
|
|
3890
|
+
}
|
|
3891
|
+
const cached = turnLineCache.get(turn);
|
|
3892
|
+
if (cached && cached.width === contentWidth && cached.color === colorEnabled && cached.density === density) {
|
|
3893
|
+
wrapped.push(...cached.lines);
|
|
3894
|
+
} else {
|
|
3895
|
+
const lines = renderTurnBlock(turn.role, turn.content, contentWidth, colorEnabled);
|
|
3896
|
+
turnLineCache.set(turn, {
|
|
3897
|
+
width: contentWidth,
|
|
3898
|
+
color: colorEnabled,
|
|
3899
|
+
density,
|
|
3900
|
+
lines
|
|
3901
|
+
});
|
|
3902
|
+
wrapped.push(...lines);
|
|
3828
3903
|
}
|
|
3829
3904
|
}
|
|
3905
|
+
if (history.currentRole !== null && history.currentContent) {
|
|
3906
|
+
const i = history.turns.length;
|
|
3907
|
+
if (density === "spacious" && (i > 0 || history.currentRole === "user")) {
|
|
3908
|
+
wrapped.push("");
|
|
3909
|
+
}
|
|
3910
|
+
wrapped.push(
|
|
3911
|
+
...renderTurnBlock(
|
|
3912
|
+
history.currentRole,
|
|
3913
|
+
history.currentContent,
|
|
3914
|
+
contentWidth,
|
|
3915
|
+
colorEnabled
|
|
3916
|
+
)
|
|
3917
|
+
);
|
|
3918
|
+
}
|
|
3830
3919
|
return wrapped;
|
|
3831
3920
|
}
|
|
3832
3921
|
function renderHistory(output, history, inputLines) {
|
|
@@ -3924,6 +4013,38 @@ function applyScrollAction(history, action, output, inputLines) {
|
|
|
3924
4013
|
}
|
|
3925
4014
|
|
|
3926
4015
|
// packages/cli/tui/tuiRawInput.ts
|
|
4016
|
+
function normalizePasteNewlines(text) {
|
|
4017
|
+
return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
4018
|
+
}
|
|
4019
|
+
var altScreenOn = /* @__PURE__ */ new WeakMap();
|
|
4020
|
+
function outputIsTty2(output) {
|
|
4021
|
+
return Boolean(output.isTTY);
|
|
4022
|
+
}
|
|
4023
|
+
function enterAltScreen(output) {
|
|
4024
|
+
if (!outputIsTty2(output)) return false;
|
|
4025
|
+
if (altScreenOn.get(output)) return false;
|
|
4026
|
+
altScreenOn.set(output, true);
|
|
4027
|
+
output.write("\x1B[?1049h");
|
|
4028
|
+
return true;
|
|
4029
|
+
}
|
|
4030
|
+
function leaveAltScreen(output) {
|
|
4031
|
+
if (!outputIsTty2(output)) return false;
|
|
4032
|
+
if (!altScreenOn.get(output)) return false;
|
|
4033
|
+
altScreenOn.set(output, false);
|
|
4034
|
+
output.write("\x1B[?1049l");
|
|
4035
|
+
return true;
|
|
4036
|
+
}
|
|
4037
|
+
function isAltScreenOn(output) {
|
|
4038
|
+
return Boolean(altScreenOn.get(output));
|
|
4039
|
+
}
|
|
4040
|
+
function styleCollapsedPastePlaceholders(text, colorEnabled) {
|
|
4041
|
+
if (!colorEnabled || !text.includes("[paste #")) return text;
|
|
4042
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
|
|
4043
|
+
return text.replace(
|
|
4044
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE,
|
|
4045
|
+
(match) => themeText(match, "accent", true)
|
|
4046
|
+
);
|
|
4047
|
+
}
|
|
3927
4048
|
function createNoopFixedInput() {
|
|
3928
4049
|
return {
|
|
3929
4050
|
active: false,
|
|
@@ -3946,6 +4067,8 @@ function createNoopFixedInput() {
|
|
|
3946
4067
|
getInputLines: () => 1,
|
|
3947
4068
|
isPaused: () => false,
|
|
3948
4069
|
setMouseEnabled() {
|
|
4070
|
+
},
|
|
4071
|
+
setAltScreenEnabled() {
|
|
3949
4072
|
}
|
|
3950
4073
|
};
|
|
3951
4074
|
}
|
|
@@ -3989,7 +4112,7 @@ function createFixedInput(output, config) {
|
|
|
3989
4112
|
sections.push(fitAnsiLine(line.replace(/\r?\n/g, " "), cols));
|
|
3990
4113
|
}
|
|
3991
4114
|
const promptRaw = t("promptLabel");
|
|
3992
|
-
const promptWidth =
|
|
4115
|
+
const promptWidth = displayWidth(promptRaw);
|
|
3993
4116
|
const prompt = colorEnabled ? `${themeColorSequence("accent")}${promptRaw}\x1B[39m` : promptRaw;
|
|
3994
4117
|
const contentWidth = Math.max(1, cols - promptWidth);
|
|
3995
4118
|
const logicalLines = buffer.length === 0 ? [""] : buffer.split("\n");
|
|
@@ -4017,13 +4140,15 @@ function createFixedInput(output, config) {
|
|
|
4017
4140
|
for (let j = 0; j < rows.length; j += 1) {
|
|
4018
4141
|
const rowPrefix = j === 0 ? prefix : " ".repeat(promptWidth);
|
|
4019
4142
|
const rowText = rows[j] ?? "";
|
|
4020
|
-
sections.push(
|
|
4143
|
+
sections.push(
|
|
4144
|
+
`${rowPrefix}${styleCollapsedPastePlaceholders(rowText, colorEnabled)}`
|
|
4145
|
+
);
|
|
4021
4146
|
const rowLen = rowText.length;
|
|
4022
4147
|
if (!cursorFound) {
|
|
4023
4148
|
if (targetPos <= charOffset + rowLen || j === rows.length - 1 && i === logicalLines.length - 1) {
|
|
4024
4149
|
const subOffset = Math.max(0, Math.min(rowLen, targetPos - charOffset));
|
|
4025
4150
|
const subStr = rowText.slice(0, subOffset);
|
|
4026
|
-
cursorCol = promptWidth +
|
|
4151
|
+
cursorCol = promptWidth + displayWidth(subStr);
|
|
4027
4152
|
cursorRow = inputRows;
|
|
4028
4153
|
cursorFound = true;
|
|
4029
4154
|
}
|
|
@@ -4040,10 +4165,15 @@ function createFixedInput(output, config) {
|
|
|
4040
4165
|
};
|
|
4041
4166
|
const repaintAt = (buffer, cursorPos) => {
|
|
4042
4167
|
const { text, lines, cursorCol, cursorRow } = renderInputArea(buffer, cursorPos);
|
|
4168
|
+
let linesChanged = false;
|
|
4043
4169
|
if (lines !== inputLines) {
|
|
4044
4170
|
inputLines = lines;
|
|
4171
|
+
linesChanged = true;
|
|
4045
4172
|
}
|
|
4046
4173
|
setScrollRegion(inputLines);
|
|
4174
|
+
if (linesChanged) {
|
|
4175
|
+
config.onInputLinesChange?.(inputLines);
|
|
4176
|
+
}
|
|
4047
4177
|
const startRow = getRows() - inputLines + 1;
|
|
4048
4178
|
write(`\x1B[${startRow};1H`);
|
|
4049
4179
|
write("\x1B[J");
|
|
@@ -4091,8 +4221,7 @@ function createFixedInput(output, config) {
|
|
|
4091
4221
|
disable() {
|
|
4092
4222
|
disableMouse();
|
|
4093
4223
|
resetScrollRegion();
|
|
4094
|
-
|
|
4095
|
-
write(`\x1B[${rows};1H\x1B[2K\x1B[${Math.max(1, rows - 1)};1H`);
|
|
4224
|
+
leaveAltScreen(output);
|
|
4096
4225
|
},
|
|
4097
4226
|
getInputLines: () => inputLines,
|
|
4098
4227
|
isPaused: () => paused,
|
|
@@ -4103,6 +4232,13 @@ function createFixedInput(output, config) {
|
|
|
4103
4232
|
} else {
|
|
4104
4233
|
write("\x1B[?1000l\x1B[?1006l");
|
|
4105
4234
|
}
|
|
4235
|
+
},
|
|
4236
|
+
setAltScreenEnabled(enabled) {
|
|
4237
|
+
if (enabled) {
|
|
4238
|
+
enterAltScreen(output);
|
|
4239
|
+
} else {
|
|
4240
|
+
leaveAltScreen(output);
|
|
4241
|
+
}
|
|
4106
4242
|
}
|
|
4107
4243
|
};
|
|
4108
4244
|
}
|
|
@@ -4152,9 +4288,27 @@ function isIncompleteTail(input, start) {
|
|
|
4152
4288
|
}
|
|
4153
4289
|
return false;
|
|
4154
4290
|
}
|
|
4155
|
-
var PASTE_START = "\x1B[
|
|
4156
|
-
var PASTE_END = "\x1B[
|
|
4157
|
-
function
|
|
4291
|
+
var PASTE_START = "\x1B[200~";
|
|
4292
|
+
var PASTE_END = "\x1B[201~";
|
|
4293
|
+
function findBracketedPasteEnd(input, contentStart) {
|
|
4294
|
+
return input.indexOf(PASTE_END, contentStart);
|
|
4295
|
+
}
|
|
4296
|
+
function emitPlainRunAsTokens(run) {
|
|
4297
|
+
if (run.length === 0) return [];
|
|
4298
|
+
if (shouldCollapsePaste(normalizePasteNewlines(run))) {
|
|
4299
|
+
return [`${PASTE_TOKEN_PREFIX}${run}`];
|
|
4300
|
+
}
|
|
4301
|
+
const tokens = [];
|
|
4302
|
+
for (let index = 0; index < run.length; ) {
|
|
4303
|
+
const codePoint = run.codePointAt(index);
|
|
4304
|
+
if (codePoint === void 0) break;
|
|
4305
|
+
const value = String.fromCodePoint(codePoint);
|
|
4306
|
+
tokens.push(value);
|
|
4307
|
+
index += value.length;
|
|
4308
|
+
}
|
|
4309
|
+
return tokens;
|
|
4310
|
+
}
|
|
4311
|
+
function splitRawInputWithTail(input, options) {
|
|
4158
4312
|
const tokens = [];
|
|
4159
4313
|
for (let index = 0; index < input.length; ) {
|
|
4160
4314
|
if (isIncompleteTail(input, index)) {
|
|
@@ -4162,15 +4316,17 @@ function splitRawInputWithTail(input) {
|
|
|
4162
4316
|
}
|
|
4163
4317
|
if (input.startsWith(PASTE_START, index)) {
|
|
4164
4318
|
const contentStart = index + PASTE_START.length;
|
|
4165
|
-
const endPos = input
|
|
4319
|
+
const endPos = findBracketedPasteEnd(input, contentStart);
|
|
4166
4320
|
if (endPos !== -1) {
|
|
4167
4321
|
const payload = input.slice(contentStart, endPos);
|
|
4168
4322
|
tokens.push(`${PASTE_TOKEN_PREFIX}${payload}`);
|
|
4169
4323
|
index = endPos + PASTE_END.length;
|
|
4170
|
-
} else {
|
|
4324
|
+
} else if (options?.forceCompleteOpenPaste) {
|
|
4171
4325
|
const payload = input.slice(contentStart);
|
|
4172
4326
|
tokens.push(`${PASTE_TOKEN_PREFIX}${payload}`);
|
|
4173
4327
|
index = input.length;
|
|
4328
|
+
} else {
|
|
4329
|
+
return { tokens, tail: input.slice(index) };
|
|
4174
4330
|
}
|
|
4175
4331
|
continue;
|
|
4176
4332
|
}
|
|
@@ -4195,63 +4351,121 @@ function splitRawInputWithTail(input) {
|
|
|
4195
4351
|
index += csi.length;
|
|
4196
4352
|
continue;
|
|
4197
4353
|
}
|
|
4198
|
-
const
|
|
4199
|
-
|
|
4200
|
-
const
|
|
4201
|
-
|
|
4202
|
-
|
|
4354
|
+
const nextEsc = input.indexOf("\x1B", index);
|
|
4355
|
+
const runEnd = nextEsc === -1 ? input.length : nextEsc;
|
|
4356
|
+
const run = input.slice(index, runEnd);
|
|
4357
|
+
if (run.length === 0) {
|
|
4358
|
+
const codePoint = input.codePointAt(index);
|
|
4359
|
+
if (codePoint === void 0) break;
|
|
4360
|
+
const value = String.fromCodePoint(codePoint);
|
|
4361
|
+
tokens.push(value);
|
|
4362
|
+
index += value.length;
|
|
4363
|
+
continue;
|
|
4364
|
+
}
|
|
4365
|
+
tokens.push(...emitPlainRunAsTokens(run));
|
|
4366
|
+
index = runEnd;
|
|
4203
4367
|
}
|
|
4204
4368
|
return { tokens, tail: "" };
|
|
4205
4369
|
}
|
|
4206
4370
|
function splitRawInput(input) {
|
|
4207
|
-
const { tokens, tail } = splitRawInputWithTail(input
|
|
4371
|
+
const { tokens, tail } = splitRawInputWithTail(input, {
|
|
4372
|
+
forceCompleteOpenPaste: true
|
|
4373
|
+
});
|
|
4208
4374
|
if (!tail) return tokens;
|
|
4209
|
-
|
|
4210
|
-
for (let index = 0; index < tail.length; ) {
|
|
4211
|
-
const codePoint = tail.codePointAt(index);
|
|
4212
|
-
if (codePoint === void 0) break;
|
|
4213
|
-
const value = String.fromCodePoint(codePoint);
|
|
4214
|
-
tailTokens.push(value);
|
|
4215
|
-
index += value.length;
|
|
4216
|
-
}
|
|
4217
|
-
return [...tokens, ...tailTokens];
|
|
4375
|
+
return [...tokens, ...emitPlainRunAsTokens(tail)];
|
|
4218
4376
|
}
|
|
4219
4377
|
function createRawInputDecoder(onToken, options) {
|
|
4220
4378
|
const decoder = new TextDecoder("utf-8", { fatal: false, ignoreBOM: true });
|
|
4221
4379
|
let pendingBuffer = "";
|
|
4222
4380
|
let timer = null;
|
|
4223
4381
|
const timeoutMs = options?.escTimeoutMs ?? 15;
|
|
4382
|
+
const unmarkedPasteDebounceMs = options?.unmarkedPasteDebounceMs ?? 40;
|
|
4224
4383
|
const clearTimer = () => {
|
|
4225
4384
|
if (timer !== null) {
|
|
4226
4385
|
clearTimeout(timer);
|
|
4227
4386
|
timer = null;
|
|
4228
4387
|
}
|
|
4229
4388
|
};
|
|
4230
|
-
const
|
|
4389
|
+
const emitCodePoints = (text) => {
|
|
4390
|
+
for (let index = 0; index < text.length; ) {
|
|
4391
|
+
const codePoint = text.codePointAt(index);
|
|
4392
|
+
if (codePoint === void 0) break;
|
|
4393
|
+
const value = String.fromCodePoint(codePoint);
|
|
4394
|
+
onToken(value);
|
|
4395
|
+
index += value.length;
|
|
4396
|
+
}
|
|
4397
|
+
};
|
|
4398
|
+
const flushPlainPending = () => {
|
|
4231
4399
|
clearTimer();
|
|
4232
|
-
if (pendingBuffer.length
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
}
|
|
4400
|
+
if (pendingBuffer.length === 0) return;
|
|
4401
|
+
const text = pendingBuffer;
|
|
4402
|
+
pendingBuffer = "";
|
|
4403
|
+
for (const token of emitPlainRunAsTokens(text)) {
|
|
4404
|
+
onToken(token);
|
|
4238
4405
|
}
|
|
4239
4406
|
};
|
|
4407
|
+
const flushEscPending = (forceCompleteOpenPaste) => {
|
|
4408
|
+
clearTimer();
|
|
4409
|
+
if (pendingBuffer.length === 0) return;
|
|
4410
|
+
const textToFlush = pendingBuffer;
|
|
4411
|
+
pendingBuffer = "";
|
|
4412
|
+
const { tokens, tail } = splitRawInputWithTail(textToFlush, {
|
|
4413
|
+
forceCompleteOpenPaste
|
|
4414
|
+
});
|
|
4415
|
+
for (const token of tokens) {
|
|
4416
|
+
onToken(token);
|
|
4417
|
+
}
|
|
4418
|
+
if (!tail) return;
|
|
4419
|
+
if (forceCompleteOpenPaste) {
|
|
4420
|
+
emitCodePoints(tail);
|
|
4421
|
+
return;
|
|
4422
|
+
}
|
|
4423
|
+
pendingBuffer = tail;
|
|
4424
|
+
};
|
|
4240
4425
|
const decodeFn = (chunk) => {
|
|
4241
4426
|
clearTimer();
|
|
4242
4427
|
const bytes = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
4243
4428
|
const text = decoder.decode(bytes, { stream: true });
|
|
4244
4429
|
pendingBuffer += text;
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4430
|
+
if (pendingBuffer.startsWith(PASTE_START)) {
|
|
4431
|
+
const endPos = findBracketedPasteEnd(
|
|
4432
|
+
pendingBuffer,
|
|
4433
|
+
PASTE_START.length
|
|
4434
|
+
);
|
|
4435
|
+
if (endPos === -1) return;
|
|
4436
|
+
const { tokens, tail } = splitRawInputWithTail(pendingBuffer);
|
|
4437
|
+
pendingBuffer = tail;
|
|
4438
|
+
for (const token of tokens) onToken(token);
|
|
4439
|
+
if (pendingBuffer.startsWith(PASTE_START)) return;
|
|
4440
|
+
}
|
|
4441
|
+
if (pendingBuffer.includes("\x1B")) {
|
|
4442
|
+
const { tokens, tail } = splitRawInputWithTail(pendingBuffer);
|
|
4443
|
+
pendingBuffer = tail;
|
|
4444
|
+
for (const token of tokens) onToken(token);
|
|
4445
|
+
if (pendingBuffer.startsWith(PASTE_START)) return;
|
|
4446
|
+
if (pendingBuffer.length > 0) {
|
|
4447
|
+
timer = setTimeout(() => flushEscPending(true), timeoutMs);
|
|
4448
|
+
}
|
|
4449
|
+
return;
|
|
4450
|
+
}
|
|
4451
|
+
if (shouldCollapsePaste(normalizePasteNewlines(pendingBuffer))) {
|
|
4452
|
+
timer = setTimeout(flushPlainPending, unmarkedPasteDebounceMs);
|
|
4453
|
+
return;
|
|
4454
|
+
}
|
|
4455
|
+
if (!pendingBuffer.includes("\n") && !pendingBuffer.includes("\r")) {
|
|
4456
|
+
emitCodePoints(pendingBuffer);
|
|
4457
|
+
pendingBuffer = "";
|
|
4458
|
+
return;
|
|
4249
4459
|
}
|
|
4250
|
-
|
|
4251
|
-
|
|
4460
|
+
timer = setTimeout(flushPlainPending, unmarkedPasteDebounceMs);
|
|
4461
|
+
};
|
|
4462
|
+
decodeFn.flush = () => {
|
|
4463
|
+
if (pendingBuffer.startsWith(PASTE_START) || pendingBuffer.includes("\x1B")) {
|
|
4464
|
+
flushEscPending(true);
|
|
4465
|
+
return;
|
|
4252
4466
|
}
|
|
4467
|
+
flushPlainPending();
|
|
4253
4468
|
};
|
|
4254
|
-
decodeFn.flush = flush;
|
|
4255
4469
|
decodeFn.destroy = () => {
|
|
4256
4470
|
clearTimer();
|
|
4257
4471
|
pendingBuffer = "";
|
|
@@ -4261,12 +4475,66 @@ function createRawInputDecoder(onToken, options) {
|
|
|
4261
4475
|
|
|
4262
4476
|
// packages/cli/tui/readlineWorkspace.ts
|
|
4263
4477
|
var AGENTS_MD_MAX_BYTES = 8192;
|
|
4478
|
+
var altScreenRestoreOutput = null;
|
|
4479
|
+
var altScreenHandlersInstalled = false;
|
|
4480
|
+
var preExistingSignalListeners = {};
|
|
4481
|
+
var SIGNAL_EXIT_CODE = {
|
|
4482
|
+
SIGINT: 130,
|
|
4483
|
+
SIGTERM: 143,
|
|
4484
|
+
SIGHUP: 129
|
|
4485
|
+
};
|
|
4486
|
+
var restoreAltScreen = () => {
|
|
4487
|
+
try {
|
|
4488
|
+
if (altScreenRestoreOutput) leaveAltScreen(altScreenRestoreOutput);
|
|
4489
|
+
} catch {
|
|
4490
|
+
}
|
|
4491
|
+
};
|
|
4492
|
+
function installAltScreenRestoreHandlers(output) {
|
|
4493
|
+
altScreenRestoreOutput = output;
|
|
4494
|
+
if (altScreenHandlersInstalled) return;
|
|
4495
|
+
altScreenHandlersInstalled = true;
|
|
4496
|
+
process.on("exit", restoreAltScreen);
|
|
4497
|
+
for (const sig of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
4498
|
+
const existing = process.listeners(sig);
|
|
4499
|
+
preExistingSignalListeners[sig] = [...existing];
|
|
4500
|
+
const handler = () => {
|
|
4501
|
+
restoreAltScreen();
|
|
4502
|
+
const others = process.listeners(sig).filter((fn) => fn !== handler);
|
|
4503
|
+
if (others.length === 0) {
|
|
4504
|
+
process.exit(SIGNAL_EXIT_CODE[sig] ?? 128 + 1);
|
|
4505
|
+
return;
|
|
4506
|
+
}
|
|
4507
|
+
};
|
|
4508
|
+
process.prependListener(sig, handler);
|
|
4509
|
+
}
|
|
4510
|
+
process.on("uncaughtException", (err) => {
|
|
4511
|
+
restoreAltScreen();
|
|
4512
|
+
try {
|
|
4513
|
+
process.stderr.write(
|
|
4514
|
+
`uncaughtException: ${err?.stack ?? String(err)}
|
|
4515
|
+
`
|
|
4516
|
+
);
|
|
4517
|
+
} catch {
|
|
4518
|
+
}
|
|
4519
|
+
process.exit(1);
|
|
4520
|
+
});
|
|
4521
|
+
process.on("unhandledRejection", (reason) => {
|
|
4522
|
+
restoreAltScreen();
|
|
4523
|
+
try {
|
|
4524
|
+
const text = reason instanceof Error ? reason.stack ?? String(reason) : String(reason);
|
|
4525
|
+
process.stderr.write(`unhandledRejection: ${text}
|
|
4526
|
+
`);
|
|
4527
|
+
} catch {
|
|
4528
|
+
}
|
|
4529
|
+
process.exit(1);
|
|
4530
|
+
});
|
|
4531
|
+
}
|
|
4264
4532
|
function readAgentsMdBlock(cwd) {
|
|
4265
4533
|
for (const name of ["AGENTS.md", "CLAUDE.md"]) {
|
|
4266
|
-
const filePath =
|
|
4267
|
-
if (
|
|
4534
|
+
const filePath = join2(cwd, name);
|
|
4535
|
+
if (existsSync3(filePath)) {
|
|
4268
4536
|
try {
|
|
4269
|
-
let content =
|
|
4537
|
+
let content = readFileSync2(filePath, "utf8").trim();
|
|
4270
4538
|
if (!content) continue;
|
|
4271
4539
|
if (Buffer.byteLength(content, "utf8") > AGENTS_MD_MAX_BYTES) {
|
|
4272
4540
|
content = Buffer.from(content, "utf8").subarray(0, AGENTS_MD_MAX_BYTES).toString("utf8") + "\n\n<!-- AGENTS.md truncated -->";
|
|
@@ -4290,10 +4558,14 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
4290
4558
|
effectiveAgentName = cachedRoute.agentName;
|
|
4291
4559
|
} else if (!continueId && env.NOLO_AUTO_ROUTE !== "0" && state.agentKey === DEFAULT_TUI_AGENT_KEY) {
|
|
4292
4560
|
const authToken = env.AUTH_TOKEN ?? env.AUTH ?? env.BENCHMARK_AUTH_TOKEN ?? "";
|
|
4293
|
-
const route = await classifyCliAutoRoute(message, {
|
|
4561
|
+
const route = authToken ? await classifyCliAutoRoute(message, {
|
|
4294
4562
|
serverUrl: state.serverUrl,
|
|
4295
4563
|
authToken
|
|
4296
|
-
})
|
|
4564
|
+
}) : {
|
|
4565
|
+
agentKey: CLI_AUTO_TIER_AGENT_KEYS[resolveCliAutoFallbackTier(message)],
|
|
4566
|
+
tier: resolveCliAutoFallbackTier(message),
|
|
4567
|
+
classified: false
|
|
4568
|
+
};
|
|
4297
4569
|
effectiveAgentKey = route.agentKey;
|
|
4298
4570
|
effectiveAgentName = `auto\u2192${route.tier}`;
|
|
4299
4571
|
if (effectiveAgentKey !== state.agentKey) {
|
|
@@ -4381,6 +4653,18 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
4381
4653
|
if (skillDiscoveryBlock) {
|
|
4382
4654
|
extraContextBlocks.push(skillDiscoveryBlock);
|
|
4383
4655
|
}
|
|
4656
|
+
const agentsMdMarker = "--- \u9879\u76EE\u6307\u4EE4\uFF08";
|
|
4657
|
+
const contextBlockScopes = [];
|
|
4658
|
+
for (const block of extraContextBlocks) {
|
|
4659
|
+
if (block.startsWith(agentsMdMarker)) {
|
|
4660
|
+
contextBlockScopes.push({ content: block, cacheScope: "session" });
|
|
4661
|
+
}
|
|
4662
|
+
}
|
|
4663
|
+
for (const block of extraContextBlocks) {
|
|
4664
|
+
if (!block.startsWith(agentsMdMarker)) {
|
|
4665
|
+
contextBlockScopes.push({ content: block, cacheScope: "turn" });
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4384
4668
|
const result = await agentRunner({
|
|
4385
4669
|
agentName: effectiveAgentName,
|
|
4386
4670
|
agentKey: effectiveAgentKey,
|
|
@@ -4401,9 +4685,17 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
4401
4685
|
...options.confirmDestructiveAction ? { confirmDestructiveAction: options.confirmDestructiveAction } : {},
|
|
4402
4686
|
...options.requestUserChoice ? { requestUserChoice: options.requestUserChoice } : {},
|
|
4403
4687
|
...options.abortSignal ? { abortSignal: options.abortSignal } : {},
|
|
4688
|
+
...options.pastedTextStore?.items.size ? {
|
|
4689
|
+
pastedTextStore: options.pastedTextStore,
|
|
4690
|
+
localRuntimeAdapterFactory: (factoryEnv, factoryOptions) => createCliLocalRuntimeAdapter({
|
|
4691
|
+
env: factoryEnv,
|
|
4692
|
+
cwd: factoryOptions?.cwd ?? state.cwd,
|
|
4693
|
+
pastedTextStore: options.pastedTextStore
|
|
4694
|
+
})
|
|
4695
|
+
} : {},
|
|
4404
4696
|
...options.activityReporter ? { activityReporter: options.activityReporter } : {},
|
|
4405
4697
|
...skillAllowedTools !== void 0 ? { allowedToolNames: skillAllowedTools } : {},
|
|
4406
|
-
...
|
|
4698
|
+
...contextBlockScopes.length > 0 ? { contextBlockScopes } : {}
|
|
4407
4699
|
});
|
|
4408
4700
|
if (!continueId && result.dialogId && effectiveAgentKey !== state.agentKey) {
|
|
4409
4701
|
autoRouteByDialog.set(result.dialogId, {
|
|
@@ -4411,19 +4703,32 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
4411
4703
|
agentName: effectiveAgentName
|
|
4412
4704
|
});
|
|
4413
4705
|
}
|
|
4414
|
-
return
|
|
4706
|
+
return {
|
|
4707
|
+
...result,
|
|
4708
|
+
contextWindow: resolveAgentContextWindow({
|
|
4709
|
+
agentKey: effectiveAgentKey,
|
|
4710
|
+
agentName: effectiveAgentName,
|
|
4711
|
+
autoRouteDefault: env.NOLO_AUTO_ROUTE !== "0"
|
|
4712
|
+
})
|
|
4713
|
+
};
|
|
4415
4714
|
}
|
|
4416
4715
|
function waitForActionGate(rl, input, output, gate, spawnRunner) {
|
|
4417
4716
|
const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
|
|
4418
4717
|
const displayCommand = commandPayload?.displayCommand ?? commandPayload?.command.join(" ") ?? gate.title;
|
|
4419
|
-
|
|
4420
|
-
|
|
4718
|
+
const isInteractiveHandoff = gate.kind === "handoff" && gate.title === "This command requires an interactive terminal.";
|
|
4719
|
+
const title = isInteractiveHandoff ? t("actionGateInteractiveTitle") : gate.title;
|
|
4720
|
+
const body = isInteractiveHandoff ? t("actionGateInteractiveBody") : gate.body;
|
|
4721
|
+
output.write(`
|
|
4722
|
+
[nolo] ${t("actionGateNeeded")}
|
|
4723
|
+
`);
|
|
4724
|
+
output.write(`[nolo] ${title}
|
|
4421
4725
|
`);
|
|
4422
|
-
if (
|
|
4726
|
+
if (body) output.write(`[nolo] ${body}
|
|
4423
4727
|
`);
|
|
4424
4728
|
output.write(` ${displayCommand}
|
|
4425
4729
|
`);
|
|
4426
|
-
output.write(
|
|
4730
|
+
output.write(`[nolo] ${t("actionGateEnterHint")}
|
|
4731
|
+
`);
|
|
4427
4732
|
return new Promise((resolve2) => {
|
|
4428
4733
|
let settled = false;
|
|
4429
4734
|
const finish = (result) => {
|
|
@@ -4513,17 +4818,28 @@ function isInteractiveInput(input) {
|
|
|
4513
4818
|
function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
4514
4819
|
const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
|
|
4515
4820
|
const displayCommand = commandPayload?.displayCommand ?? commandPayload?.command.join(" ") ?? gate.title;
|
|
4516
|
-
|
|
4517
|
-
|
|
4821
|
+
const isInteractiveHandoff = gate.kind === "handoff" && gate.title === "This command requires an interactive terminal.";
|
|
4822
|
+
const title = isInteractiveHandoff ? t("actionGateInteractiveTitle") : gate.title;
|
|
4823
|
+
const body = isInteractiveHandoff ? t("actionGateInteractiveBody") : gate.body;
|
|
4824
|
+
output.write(`
|
|
4825
|
+
[nolo] ${t("actionGateNeeded")}
|
|
4518
4826
|
`);
|
|
4519
|
-
|
|
4827
|
+
output.write(`[nolo] ${title}
|
|
4828
|
+
`);
|
|
4829
|
+
if (body) output.write(`[nolo] ${body}
|
|
4520
4830
|
`);
|
|
4521
4831
|
output.write(` ${displayCommand}
|
|
4522
4832
|
`);
|
|
4523
|
-
output.write(
|
|
4833
|
+
output.write(`[nolo] ${t("actionGateEnterHint")}
|
|
4834
|
+
`);
|
|
4524
4835
|
return new Promise((resolve2) => {
|
|
4525
4836
|
const rawInput = input;
|
|
4837
|
+
let settled = false;
|
|
4838
|
+
let commandRunning = false;
|
|
4526
4839
|
const finish = (result) => {
|
|
4840
|
+
if (settled) return;
|
|
4841
|
+
settled = true;
|
|
4842
|
+
hooks?.registerToken?.(null);
|
|
4527
4843
|
input.off("data", onData);
|
|
4528
4844
|
resolve2(result);
|
|
4529
4845
|
};
|
|
@@ -4541,13 +4857,9 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
4541
4857
|
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
4542
4858
|
}
|
|
4543
4859
|
});
|
|
4544
|
-
const
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
cancel("interrupted");
|
|
4548
|
-
return;
|
|
4549
|
-
}
|
|
4550
|
-
if (!text.includes("\r") && !text.includes("\n")) return;
|
|
4860
|
+
const runCommand = async () => {
|
|
4861
|
+
if (settled || commandRunning) return;
|
|
4862
|
+
commandRunning = true;
|
|
4551
4863
|
if (!commandPayload) {
|
|
4552
4864
|
fail("unsupported gate payload");
|
|
4553
4865
|
return;
|
|
@@ -4585,7 +4897,25 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
4585
4897
|
}
|
|
4586
4898
|
});
|
|
4587
4899
|
};
|
|
4588
|
-
|
|
4900
|
+
const handleToken = (text) => {
|
|
4901
|
+
if (settled || commandRunning) return;
|
|
4902
|
+
if (text.includes("")) {
|
|
4903
|
+
cancel("interrupted");
|
|
4904
|
+
return;
|
|
4905
|
+
}
|
|
4906
|
+
if (text.includes("\r") || text.includes("\n")) {
|
|
4907
|
+
void runCommand();
|
|
4908
|
+
}
|
|
4909
|
+
};
|
|
4910
|
+
const onData = (chunk) => {
|
|
4911
|
+
const text = String(chunk);
|
|
4912
|
+
handleToken(text);
|
|
4913
|
+
};
|
|
4914
|
+
if (hooks?.registerToken) {
|
|
4915
|
+
hooks.registerToken(handleToken);
|
|
4916
|
+
} else {
|
|
4917
|
+
input.on("data", onData);
|
|
4918
|
+
}
|
|
4589
4919
|
});
|
|
4590
4920
|
}
|
|
4591
4921
|
async function startTuiWorkspace(options) {
|
|
@@ -4597,22 +4927,33 @@ async function startTuiWorkspace(options) {
|
|
|
4597
4927
|
const spawnRunner = options.spawnRunner ?? spawnProcess;
|
|
4598
4928
|
const selfUpdater = options.selfUpdater ?? ((target) => runSelfUpdate({ output: target }));
|
|
4599
4929
|
if (output.isTTY) {
|
|
4600
|
-
output
|
|
4930
|
+
enterAltScreen(output);
|
|
4931
|
+
installAltScreenRestoreHandlers(output);
|
|
4932
|
+
output.write("\x1B[2J\x1B[H");
|
|
4601
4933
|
}
|
|
4602
|
-
const detected = await
|
|
4934
|
+
const detected = await detectTerminalBackground({
|
|
4603
4935
|
stdin: input,
|
|
4604
4936
|
stdout: output
|
|
4605
4937
|
});
|
|
4606
|
-
if (detected)
|
|
4938
|
+
if (detected) {
|
|
4939
|
+
setActiveBrightness(detected.brightness);
|
|
4940
|
+
setActiveTerminalBaseHex(detected.hex);
|
|
4941
|
+
}
|
|
4607
4942
|
const bannerColumns = output.columns;
|
|
4608
4943
|
output.write(renderWelcome(state, 0, 0, bannerColumns));
|
|
4609
4944
|
let fixedInput = createNoopFixedInput();
|
|
4610
4945
|
let buffer = "";
|
|
4611
4946
|
let cursorPos = 0;
|
|
4947
|
+
const pasteStore = createCollapsedPasteStore();
|
|
4612
4948
|
let activeTurnAbort = null;
|
|
4949
|
+
let forcedStop = false;
|
|
4950
|
+
let forcedStopEpoch = 0;
|
|
4951
|
+
let turnEpoch = 0;
|
|
4952
|
+
let activeTurnEpoch = 0;
|
|
4613
4953
|
const activityIndicator = createActivityIndicator({
|
|
4614
4954
|
isTurnActive: () => activeTurnAbort !== null,
|
|
4615
4955
|
fallbackLabel: () => `${state.agentName} -> working`,
|
|
4956
|
+
stoppingLabel: () => t("turnStopping"),
|
|
4616
4957
|
onRepaint: () => {
|
|
4617
4958
|
if (fixedInput.active && !fixedInput.isPaused()) {
|
|
4618
4959
|
output.write("\x1B[?2026h\x1B[?25l");
|
|
@@ -4642,8 +4983,10 @@ async function startTuiWorkspace(options) {
|
|
|
4642
4983
|
},
|
|
4643
4984
|
output
|
|
4644
4985
|
});
|
|
4986
|
+
const RENDER_THROTTLE_MS = 33;
|
|
4645
4987
|
let renderScheduled = false;
|
|
4646
4988
|
let renderTimer = null;
|
|
4989
|
+
let sessionEnded = false;
|
|
4647
4990
|
const flushPendingRender = () => {
|
|
4648
4991
|
if (renderTimer !== null) {
|
|
4649
4992
|
clearTimeout(renderTimer);
|
|
@@ -4670,11 +5013,26 @@ async function startTuiWorkspace(options) {
|
|
|
4670
5013
|
renderScheduled = false;
|
|
4671
5014
|
renderTimer = null;
|
|
4672
5015
|
paintSyncedFrame();
|
|
4673
|
-
},
|
|
5016
|
+
}, RENDER_THROTTLE_MS);
|
|
4674
5017
|
};
|
|
5018
|
+
const refreshGitStatus = () => {
|
|
5019
|
+
if ((options.env?.NOLO_CLI_GIT_STATUS ?? process.env.NOLO_CLI_GIT_STATUS) === "0") return;
|
|
5020
|
+
void detectGitStatusAsync(state.cwd).then((gitStatus) => {
|
|
5021
|
+
if (sessionEnded) return;
|
|
5022
|
+
state = { ...state, gitStatus };
|
|
5023
|
+
scheduleRender();
|
|
5024
|
+
});
|
|
5025
|
+
};
|
|
5026
|
+
let syncingLayout = false;
|
|
4675
5027
|
const renderHistoryToOutput = () => {
|
|
4676
5028
|
if (fixedInput.isPaused()) return;
|
|
4677
|
-
|
|
5029
|
+
if (syncingLayout) return;
|
|
5030
|
+
syncingLayout = true;
|
|
5031
|
+
try {
|
|
5032
|
+
renderHistory(output, history, fixedInput.getInputLines());
|
|
5033
|
+
} finally {
|
|
5034
|
+
syncingLayout = false;
|
|
5035
|
+
}
|
|
4678
5036
|
};
|
|
4679
5037
|
const readLatestAssistantReply = () => {
|
|
4680
5038
|
const lastReply = [...history.turns].reverse().find((turn) => turn.role === "assistant")?.content;
|
|
@@ -4712,7 +5070,11 @@ ${t("copyViewHint")}
|
|
|
4712
5070
|
return true;
|
|
4713
5071
|
};
|
|
4714
5072
|
let modalOwnsKeyboard = false;
|
|
5073
|
+
let rawActionGateTokenHandler = null;
|
|
4715
5074
|
const runOneAgentTurn = async (message, imageUrls, actionGateHandler, confirmDestructiveAction) => {
|
|
5075
|
+
forcedStop = false;
|
|
5076
|
+
turnEpoch += 1;
|
|
5077
|
+
const myEpoch = turnEpoch;
|
|
4716
5078
|
history.followBottom = true;
|
|
4717
5079
|
startTurn(history, "user");
|
|
4718
5080
|
appendToCurrentTurn(history, message);
|
|
@@ -4742,6 +5104,7 @@ ${t("copyViewHint")}
|
|
|
4742
5104
|
} : void 0;
|
|
4743
5105
|
try {
|
|
4744
5106
|
activeTurnAbort = new AbortController();
|
|
5107
|
+
activeTurnEpoch = myEpoch;
|
|
4745
5108
|
const runResult = await runAgentChat(
|
|
4746
5109
|
options.scriptDir,
|
|
4747
5110
|
state,
|
|
@@ -4755,10 +5118,27 @@ ${t("copyViewHint")}
|
|
|
4755
5118
|
...confirmDestructiveAction ? { confirmDestructiveAction } : {},
|
|
4756
5119
|
...requestUserChoice ? { requestUserChoice } : {},
|
|
4757
5120
|
abortSignal: activeTurnAbort.signal,
|
|
5121
|
+
pastedTextStore: pasteStore,
|
|
4758
5122
|
explicitAgentSwitch,
|
|
4759
5123
|
activityReporter
|
|
4760
5124
|
}
|
|
4761
5125
|
);
|
|
5126
|
+
const wasForceStopped = forcedStopEpoch === myEpoch;
|
|
5127
|
+
if (wasForceStopped) {
|
|
5128
|
+
if (runResult.dialogId || runResult.turnTokens) {
|
|
5129
|
+
const nextDialogKey = runResult.dialogId ? runResult.dialogId === state.dialogId && state.dialogKey ? state.dialogKey : state.dialogOwnerId ? `dialog-${state.dialogOwnerId}-${runResult.dialogId}` : void 0 : state.dialogKey;
|
|
5130
|
+
state = {
|
|
5131
|
+
...state,
|
|
5132
|
+
...runResult.dialogId ? {
|
|
5133
|
+
dialogId: runResult.dialogId,
|
|
5134
|
+
dialogKey: nextDialogKey,
|
|
5135
|
+
dialogLabel: runResult.dialogId
|
|
5136
|
+
} : {},
|
|
5137
|
+
...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {}
|
|
5138
|
+
};
|
|
5139
|
+
}
|
|
5140
|
+
return { ok: false, aborted: true };
|
|
5141
|
+
}
|
|
4762
5142
|
const wasAborted = activeTurnAbort.signal.aborted;
|
|
4763
5143
|
activeTurnAbort = null;
|
|
4764
5144
|
explicitAgentSwitch = false;
|
|
@@ -4769,9 +5149,13 @@ ${t("copyViewHint")}
|
|
|
4769
5149
|
if (fixedInput.active) fixedInput.repaint(buffer);
|
|
4770
5150
|
}
|
|
4771
5151
|
if (wasAborted) {
|
|
4772
|
-
|
|
5152
|
+
if (runResult.pendingToolName) {
|
|
5153
|
+
emitCommandOutput(t("turnStoppedToolPending", runResult.pendingToolName));
|
|
5154
|
+
} else {
|
|
5155
|
+
emitCommandOutput(t("turnStopped"));
|
|
5156
|
+
}
|
|
4773
5157
|
}
|
|
4774
|
-
if (runResult.dialogId || runResult.turnTokens) {
|
|
5158
|
+
if (runResult.dialogId || runResult.turnTokens || runResult.contextWindow) {
|
|
4775
5159
|
const nextDialogKey = runResult.dialogId ? runResult.dialogId === state.dialogId && state.dialogKey ? state.dialogKey : state.dialogOwnerId ? `dialog-${state.dialogOwnerId}-${runResult.dialogId}` : void 0 : state.dialogKey;
|
|
4776
5160
|
state = {
|
|
4777
5161
|
...state,
|
|
@@ -4780,7 +5164,8 @@ ${t("copyViewHint")}
|
|
|
4780
5164
|
dialogKey: nextDialogKey,
|
|
4781
5165
|
dialogLabel: runResult.dialogId
|
|
4782
5166
|
} : {},
|
|
4783
|
-
...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {}
|
|
5167
|
+
...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {},
|
|
5168
|
+
...runResult.contextWindow ? { contextWindow: runResult.contextWindow } : {}
|
|
4784
5169
|
};
|
|
4785
5170
|
}
|
|
4786
5171
|
if (!wasAborted && runResult.exitCode !== 0) {
|
|
@@ -4847,6 +5232,7 @@ ${t("copyViewHint")}
|
|
|
4847
5232
|
}
|
|
4848
5233
|
if (result.action?.type === "exit") return true;
|
|
4849
5234
|
if (result.action?.type === "clear") {
|
|
5235
|
+
clearCollapsedPasteStore(pasteStore);
|
|
4850
5236
|
history.turns.length = 0;
|
|
4851
5237
|
history.currentRole = null;
|
|
4852
5238
|
history.currentContent = "";
|
|
@@ -4917,7 +5303,19 @@ ${t("copyViewHint")}
|
|
|
4917
5303
|
...state,
|
|
4918
5304
|
agentName: pickResult.name,
|
|
4919
5305
|
agentKey: pickResult.key,
|
|
4920
|
-
contextWindow:
|
|
5306
|
+
contextWindow: resolveAgentContextWindow({
|
|
5307
|
+
agentKey: pickResult.key,
|
|
5308
|
+
agentName: pickResult.name,
|
|
5309
|
+
model: pickResult.model,
|
|
5310
|
+
autoRouteDefault: (options.env ?? process.env).NOLO_AUTO_ROUTE !== "0"
|
|
5311
|
+
}),
|
|
5312
|
+
estimatedContextTokens: estimateDefaultCliContextTokens({
|
|
5313
|
+
cwd: state.cwd,
|
|
5314
|
+
agentKey: pickResult.key,
|
|
5315
|
+
agentName: pickResult.name,
|
|
5316
|
+
model: pickResult.model
|
|
5317
|
+
}),
|
|
5318
|
+
...pickResult.apiSource ? { apiSource: pickResult.apiSource } : {}
|
|
4921
5319
|
};
|
|
4922
5320
|
if (state.dialogId) autoRouteByDialog.delete(state.dialogId);
|
|
4923
5321
|
explicitAgentSwitch = true;
|
|
@@ -4949,6 +5347,16 @@ ${t("copyViewHint")}
|
|
|
4949
5347
|
if (result.action?.type === "set-mouse") {
|
|
4950
5348
|
fixedInput.setMouseEnabled(result.action.enabled);
|
|
4951
5349
|
}
|
|
5350
|
+
if (result.action?.type === "set-altscreen") {
|
|
5351
|
+
if (result.action.enabled) {
|
|
5352
|
+
enterAltScreen(output);
|
|
5353
|
+
installAltScreenRestoreHandlers(output);
|
|
5354
|
+
} else {
|
|
5355
|
+
leaveAltScreen(output);
|
|
5356
|
+
}
|
|
5357
|
+
renderHistoryToOutput();
|
|
5358
|
+
fixedInput.repaint(buffer);
|
|
5359
|
+
}
|
|
4952
5360
|
if (result.action?.type === "copy-view") {
|
|
4953
5361
|
const opened = await openCopyView();
|
|
4954
5362
|
if (!opened) emitCommandOutput(t("copyNothing"));
|
|
@@ -4992,14 +5400,7 @@ ${t("copyViewHint")}
|
|
|
4992
5400
|
dialog: pickResult.dialog,
|
|
4993
5401
|
env: options.env ?? process.env
|
|
4994
5402
|
});
|
|
4995
|
-
const restored = loadedTurns.slice(-MAX_TUI_HISTORY_TURNS)
|
|
4996
|
-
(turn) => turn.role === "assistant" ? {
|
|
4997
|
-
...turn,
|
|
4998
|
-
content: formatAssistantDisplay(
|
|
4999
|
-
turn.content
|
|
5000
|
-
)
|
|
5001
|
-
} : turn
|
|
5002
|
-
);
|
|
5403
|
+
const restored = loadedTurns.slice(-MAX_TUI_HISTORY_TURNS);
|
|
5003
5404
|
history.turns.length = 0;
|
|
5004
5405
|
history.turns.push(...restored);
|
|
5005
5406
|
history.currentRole = null;
|
|
@@ -5013,6 +5414,7 @@ ${t("copyViewHint")}
|
|
|
5013
5414
|
dialogLabel: pickResult.dialog.id,
|
|
5014
5415
|
turnTokens: void 0
|
|
5015
5416
|
};
|
|
5417
|
+
clearCollapsedPasteStore(pasteStore);
|
|
5016
5418
|
emitCommandOutput(
|
|
5017
5419
|
`${t("resumedDialogPrefix")}: ${pickResult.dialog.title} (${pickResult.dialog.id})`
|
|
5018
5420
|
);
|
|
@@ -5136,6 +5538,7 @@ ${err.message}` : ""}`
|
|
|
5136
5538
|
output.write("\x1B[?2004h");
|
|
5137
5539
|
let busy = false;
|
|
5138
5540
|
let done = false;
|
|
5541
|
+
let resolveDone = null;
|
|
5139
5542
|
let cursorPos2 = 0;
|
|
5140
5543
|
fixedInput = createFixedInput(output, {
|
|
5141
5544
|
getStatusLine: () => {
|
|
@@ -5172,6 +5575,9 @@ ${err.message}` : ""}`
|
|
|
5172
5575
|
const oneLine = text.replace(/\r?\n/g, " \u23CE ");
|
|
5173
5576
|
return dimCliText(` \u2937 ${i + 1}. ${oneLine}`, colorEnabled);
|
|
5174
5577
|
});
|
|
5578
|
+
},
|
|
5579
|
+
onInputLinesChange: () => {
|
|
5580
|
+
renderHistoryToOutput();
|
|
5175
5581
|
}
|
|
5176
5582
|
});
|
|
5177
5583
|
fixedInput.init();
|
|
@@ -5194,6 +5600,9 @@ ${err.message}` : ""}`
|
|
|
5194
5600
|
const finish = () => {
|
|
5195
5601
|
if (done) return;
|
|
5196
5602
|
done = true;
|
|
5603
|
+
sessionEnded = true;
|
|
5604
|
+
resolveDone?.();
|
|
5605
|
+
clearCollapsedPasteStore(pasteStore);
|
|
5197
5606
|
resizeTarget.off?.("resize", onResize);
|
|
5198
5607
|
input.off("data", onData);
|
|
5199
5608
|
onData.destroy();
|
|
@@ -5211,7 +5620,10 @@ ${err.message}` : ""}`
|
|
|
5211
5620
|
}
|
|
5212
5621
|
return;
|
|
5213
5622
|
}
|
|
5214
|
-
if (modalOwnsKeyboard)
|
|
5623
|
+
if (modalOwnsKeyboard) {
|
|
5624
|
+
rawActionGateTokenHandler?.(sequence);
|
|
5625
|
+
return;
|
|
5626
|
+
}
|
|
5215
5627
|
const busyLock = busy;
|
|
5216
5628
|
const scrollAction = parseScrollAction(sequence);
|
|
5217
5629
|
if (scrollAction) {
|
|
@@ -5221,19 +5633,33 @@ ${err.message}` : ""}`
|
|
|
5221
5633
|
return;
|
|
5222
5634
|
}
|
|
5223
5635
|
if (busyLock && sequence === "\x1B" && activeTurnAbort) {
|
|
5636
|
+
if (activityIndicator.isStopping()) {
|
|
5637
|
+
forcedStop = true;
|
|
5638
|
+
forcedStopEpoch = activeTurnEpoch;
|
|
5639
|
+
activityIndicator.stop();
|
|
5640
|
+
activeTurnAbort.abort();
|
|
5641
|
+
activeTurnAbort = null;
|
|
5642
|
+
activeTurnEpoch = 0;
|
|
5643
|
+
busy = false;
|
|
5644
|
+
emitCommandOutput(t("forceStopped"));
|
|
5645
|
+
flushPendingRender();
|
|
5646
|
+
renderHistoryToOutput();
|
|
5647
|
+
if (fixedInput.active) fixedInput.repaint(buffer);
|
|
5648
|
+
return;
|
|
5649
|
+
}
|
|
5224
5650
|
const stopBinding = chatQueueBinding;
|
|
5225
5651
|
if (stopBinding && stopBinding.queueLength() > 0) {
|
|
5226
5652
|
stopBinding.preemptForStop();
|
|
5227
5653
|
}
|
|
5654
|
+
activityIndicator.markStopping();
|
|
5228
5655
|
activeTurnAbort.abort();
|
|
5229
5656
|
return;
|
|
5230
5657
|
}
|
|
5231
|
-
const result = applyTuiInputKey(buffer, sequence, {}, cursorPos2
|
|
5658
|
+
const result = applyTuiInputKey(buffer, sequence, {}, cursorPos2, {
|
|
5659
|
+
pasteStore
|
|
5660
|
+
});
|
|
5232
5661
|
if (result.copyView) {
|
|
5233
|
-
if (busyLock) return;
|
|
5234
|
-
busy = true;
|
|
5235
5662
|
const opened = await openCopyView();
|
|
5236
|
-
busy = false;
|
|
5237
5663
|
if (!opened) {
|
|
5238
5664
|
history.followBottom = true;
|
|
5239
5665
|
startTurn(history, "assistant");
|
|
@@ -5249,14 +5675,19 @@ ${err.message}` : ""}`
|
|
|
5249
5675
|
return;
|
|
5250
5676
|
}
|
|
5251
5677
|
if (result.submit !== void 0) {
|
|
5678
|
+
const submittedText = replaceCollapsedPastesWithReferences(
|
|
5679
|
+
result.submit,
|
|
5680
|
+
pasteStore
|
|
5681
|
+
);
|
|
5682
|
+
const submittedTrimmed = submittedText.trim();
|
|
5683
|
+
const startsChatTurn = submittedTrimmed.length > 0 && !submittedTrimmed.startsWith("/") && !submittedTrimmed.startsWith("!");
|
|
5252
5684
|
if (busyLock) {
|
|
5253
|
-
const
|
|
5254
|
-
const trimmedText = submittedText2.trim();
|
|
5685
|
+
const trimmedText = submittedText.trim();
|
|
5255
5686
|
const busySlashCommand = trimmedText.split(/\s+/)[0]?.toLowerCase();
|
|
5256
5687
|
const isBusyLocalSlash = busySlashCommand === "/context" || busySlashCommand === "/ctx" || busySlashCommand === "/switch";
|
|
5257
5688
|
if (isBusyLocalSlash) {
|
|
5258
5689
|
const beforeAgentKey = state.agentKey;
|
|
5259
|
-
const res = handleTuiInput(
|
|
5690
|
+
const res = handleTuiInput(submittedText, state);
|
|
5260
5691
|
if (res.action) {
|
|
5261
5692
|
output.write(
|
|
5262
5693
|
"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"
|
|
@@ -5274,6 +5705,7 @@ ${hint}` : hint;
|
|
|
5274
5705
|
`);
|
|
5275
5706
|
}
|
|
5276
5707
|
}
|
|
5708
|
+
releaseCollapsedPasteReferences(submittedText, pasteStore);
|
|
5277
5709
|
buffer = "";
|
|
5278
5710
|
cursorPos2 = 0;
|
|
5279
5711
|
if (fixedInput.active) fixedInput.repaint(buffer, cursorPos2);
|
|
@@ -5285,7 +5717,10 @@ ${hint}` : hint;
|
|
|
5285
5717
|
try {
|
|
5286
5718
|
return await waitForRawActionGate(input, output, gate, spawnRunner, {
|
|
5287
5719
|
beforeSubprocess: () => fixedInput.pause(),
|
|
5288
|
-
afterSubprocess: () => fixedInput.resumeFromSubprocess()
|
|
5720
|
+
afterSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
5721
|
+
registerToken: (handler) => {
|
|
5722
|
+
rawActionGateTokenHandler = handler;
|
|
5723
|
+
}
|
|
5289
5724
|
});
|
|
5290
5725
|
} finally {
|
|
5291
5726
|
modalOwnsKeyboard = false;
|
|
@@ -5308,7 +5743,7 @@ ${hint}` : hint;
|
|
|
5308
5743
|
}
|
|
5309
5744
|
);
|
|
5310
5745
|
const decision = binding.resolveSubmit({
|
|
5311
|
-
text:
|
|
5746
|
+
text: submittedText,
|
|
5312
5747
|
isRunning: true
|
|
5313
5748
|
});
|
|
5314
5749
|
if (decision.kind === "queue-text") {
|
|
@@ -5317,7 +5752,7 @@ ${hint}` : hint;
|
|
|
5317
5752
|
cursorPos2 = 0;
|
|
5318
5753
|
fixedInput.repaint(buffer, cursorPos2);
|
|
5319
5754
|
} else if (decision.kind === "queue-blocked") {
|
|
5320
|
-
} else if (decision.kind === "noop" && !
|
|
5755
|
+
} else if (decision.kind === "noop" && !submittedText.trim() && binding.queueLength() > 0) {
|
|
5321
5756
|
if (binding.preemptForDrain()) {
|
|
5322
5757
|
if (activeTurnAbort) {
|
|
5323
5758
|
activeTurnAbort.abort();
|
|
@@ -5326,13 +5761,16 @@ ${hint}` : hint;
|
|
|
5326
5761
|
}
|
|
5327
5762
|
return;
|
|
5328
5763
|
}
|
|
5329
|
-
if (!
|
|
5764
|
+
if (!submittedText.trim() && chatQueueBinding && chatQueueBinding.queueLength() > 0) {
|
|
5330
5765
|
const actionGateHandler = async (gate) => {
|
|
5331
5766
|
modalOwnsKeyboard = true;
|
|
5332
5767
|
try {
|
|
5333
5768
|
return await waitForRawActionGate(input, output, gate, spawnRunner, {
|
|
5334
5769
|
beforeSubprocess: () => fixedInput.pause(),
|
|
5335
|
-
afterSubprocess: () => fixedInput.resumeFromSubprocess()
|
|
5770
|
+
afterSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
5771
|
+
registerToken: (handler) => {
|
|
5772
|
+
rawActionGateTokenHandler = handler;
|
|
5773
|
+
}
|
|
5336
5774
|
});
|
|
5337
5775
|
} finally {
|
|
5338
5776
|
modalOwnsKeyboard = false;
|
|
@@ -5377,17 +5815,13 @@ ${err.message}` : ""}`
|
|
|
5377
5815
|
} finally {
|
|
5378
5816
|
busy = false;
|
|
5379
5817
|
}
|
|
5380
|
-
|
|
5381
|
-
if (drainEnv.NOLO_CLI_GIT_STATUS !== "0") {
|
|
5382
|
-
state = { ...state, gitStatus: detectGitStatus(state.cwd) };
|
|
5383
|
-
}
|
|
5818
|
+
refreshGitStatus();
|
|
5384
5819
|
flushPendingRender();
|
|
5385
5820
|
fixedInput.exitOutputMode(buffer, cursorPos2);
|
|
5386
5821
|
return;
|
|
5387
5822
|
}
|
|
5388
5823
|
}
|
|
5389
|
-
busy =
|
|
5390
|
-
const submittedText = result.submit;
|
|
5824
|
+
busy = startsChatTurn;
|
|
5391
5825
|
buffer = "";
|
|
5392
5826
|
cursorPos2 = 0;
|
|
5393
5827
|
fixedInput.enterOutputMode(submittedText);
|
|
@@ -5400,7 +5834,10 @@ ${err.message}` : ""}`
|
|
|
5400
5834
|
try {
|
|
5401
5835
|
return await waitForRawActionGate(input, output, gate, spawnRunner, {
|
|
5402
5836
|
beforeSubprocess: () => fixedInput.pause(),
|
|
5403
|
-
afterSubprocess: () => fixedInput.resumeFromSubprocess()
|
|
5837
|
+
afterSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
5838
|
+
registerToken: (handler) => {
|
|
5839
|
+
rawActionGateTokenHandler = handler;
|
|
5840
|
+
}
|
|
5404
5841
|
});
|
|
5405
5842
|
} finally {
|
|
5406
5843
|
modalOwnsKeyboard = false;
|
|
@@ -5430,10 +5867,7 @@ ${err.message}` : ""}`
|
|
|
5430
5867
|
finish();
|
|
5431
5868
|
return;
|
|
5432
5869
|
}
|
|
5433
|
-
|
|
5434
|
-
if (refreshEnv.NOLO_CLI_GIT_STATUS !== "0") {
|
|
5435
|
-
state = { ...state, gitStatus: detectGitStatus(state.cwd) };
|
|
5436
|
-
}
|
|
5870
|
+
refreshGitStatus();
|
|
5437
5871
|
flushPendingRender();
|
|
5438
5872
|
fixedInput.exitOutputMode(buffer, cursorPos2);
|
|
5439
5873
|
return;
|
|
@@ -5448,13 +5882,10 @@ ${err.message}` : ""}`
|
|
|
5448
5882
|
try {
|
|
5449
5883
|
input.on("data", onData);
|
|
5450
5884
|
fixedInput.repaint(buffer, cursorPos2);
|
|
5885
|
+
refreshGitStatus();
|
|
5451
5886
|
await new Promise((resolve2) => {
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
clearInterval(check);
|
|
5455
|
-
resolve2();
|
|
5456
|
-
}
|
|
5457
|
-
}, 10);
|
|
5887
|
+
resolveDone = resolve2;
|
|
5888
|
+
if (done) resolve2();
|
|
5458
5889
|
});
|
|
5459
5890
|
} finally {
|
|
5460
5891
|
finish();
|
|
@@ -5509,9 +5940,13 @@ export {
|
|
|
5509
5940
|
createNoopFixedInput,
|
|
5510
5941
|
createRawInputDecoder,
|
|
5511
5942
|
createTurnHistory,
|
|
5512
|
-
|
|
5943
|
+
displayWidth,
|
|
5944
|
+
enterAltScreen,
|
|
5513
5945
|
finalizeCurrentTurn,
|
|
5514
5946
|
fitAnsiLine,
|
|
5947
|
+
installAltScreenRestoreHandlers,
|
|
5948
|
+
isAltScreenOn,
|
|
5949
|
+
leaveAltScreen,
|
|
5515
5950
|
padOrTruncateToWidth,
|
|
5516
5951
|
parseScrollAction,
|
|
5517
5952
|
renderHistory,
|